Skip to content

Commit

Permalink
suppress warning array-bounds in F14Table
Browse files Browse the repository at this point in the history
Summary:
There are two cases:
* In `F14Chunk::item()`, it is a contractual requirement on the caller that the this instance is not any global empty-instance, i.e., is a real `F14Chunk` and is not actually any `F14EmptyTagVector`. GCC does not know this requirement and diagnoses a possible violation of `array-bounds`, so we teach GCC to understand this requirement.
* In `prefetchAddr`, it is intentional that a wild address may be prefetched. This allows the find operation to avoid extra loads and branches that would slow it down, just to issue prefetches intended to speed it up. In C++, accesses via wild addresses are forbidden. But on every architecture, prefetches of wild addresses are permitted. GCC diagnoses a poossible violation of `array-bounds`, so we suppress.

Addresses violations of warning `array-bounds` following these patterns:
```
In file included from folly/folly/container/detail/F14Policy.h:29,
                 from folly/container/F14Map.h:41,
                 from folly/container/test/F14MapTest.cpp:17:
In function ‘void folly::f14::detail::prefetchAddr(const T*) [with T = std::pair<const folly::test::Tracked<1>, int>]’,
    inlined from ‘folly::f14::detail::F14Table<Policy>::ItemIter folly::f14::detail::F14Table<Policy>::findImpl(HashPair, const K&, Prefetch) const [with K = int; Policy = folly::f14::detail::ValueContainerPolicy<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1>, void>]’ at folly/container/detail/F14Table.h:1575:21,
    inlined from ‘folly::f14::detail::F14Table<Policy>::ItemIter folly::f14::detail::F14Table<Policy>::find(const K&) const [with K = int; Policy = folly::f14::detail::ValueContainerPolicy<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1>, void>]’ at folly/container/detail/F14Table.h:1627:20,
    inlined from ‘folly::f14::detail::F14BasicMap<Policy>::EnableHeterogeneousFind<K, bool> folly::f14::detail::F14BasicMap<Policy>::contains(const K&) const [with K = int; Policy = folly::f14::detail::ValueContainerPolicy<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1>, void>]’ at folly/container/F14Map.h:931:24,
    inlined from ‘folly::f14::detail::F14BasicMap<Policy>::EnableHeterogeneousFind<K, long unsigned int> folly::f14::detail::F14BasicMap<Policy>::count(const K&) const [with K = int; Policy = folly::f14::detail::ValueContainerPolicy<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1>, void>]’ at folly/container/F14Map.h:789:20,
    inlined from ‘void runHeterogeneousInsertTest() [with M = folly::F14FastMap<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1> >]’ at folly/container/test/F14MapTest.cpp:1800:3:
folly/container/detail/F14Table.h:461:21: warning: array subscript 9 is outside array bounds of ‘const folly::f14::detail::F14EmptyTagVector [1]’ [-Warray-bounds=]
  461 |   __builtin_prefetch(static_cast<void const*>(ptr));
      |   ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
folly/container/detail/F14Table.h: In function ‘void runHeterogeneousInsertTest() [with M = folly::F14FastMap<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1> >]’:
folly/container/detail/F14Table.h:490:38: note: at offset 144 into object ‘instance’ of size 16
  490 |   static constexpr F14EmptyTagVector instance;
      |                                      ^~~~~~~~
```
```
In file included from /opt/rh/gcc-toolset-13/root/usr/include/c++/13/functional:65,
                 from folly/lang/Exception.h:21,
                 from folly/Range.h:43,
                 from folly/container/F14Map.h:33:
In member function ‘constexpr const std::array<_Tp, _Nm>::value_type& std::array<_Tp, _Nm>::operator[](size_type) const [with _Tp = std::aligned_storage<16, 8>::type; long unsigned int _Nm = 15]’,
    inlined from ‘folly::f14::detail::F14Chunk<ItemType>::Item* folly::f14::detail::F14Chunk<ItemType>::itemAddr(std::size_t) const [with ItemType = std::pair<const folly::test::Tracked<1>, int>]’ at folly/container/detail/F14Table.h:750:62,
    inlined from ‘folly::f14::detail::F14Chunk<ItemType>::Item& folly::f14::detail::F14Chunk<ItemType>::item(std::size_t) [with ItemType = std::pair<const folly::test::Tracked<1>, int>]’ at folly/container/detail/F14Table.h:755:25,
    inlined from ‘folly::f14::detail::F14Table<Policy>::ItemIter folly::f14::detail::F14Table<Policy>::findImpl(HashPair, const K&, Prefetch) const [with K = int; Policy = folly::f14::detail::ValueContainerPolicy<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1>, void>]’ at folly/container/detail/F14Table.h:1580:13,
    inlined from ‘folly::f14::detail::F14Table<Policy>::ItemIter folly::f14::detail::F14Table<Policy>::find(const K&) const [with K = int; Policy = folly::f14::detail::ValueContainerPolicy<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1>, void>]’ at folly/container/detail/F14Table.h:1627:20,
    inlined from ‘folly::f14::detail::F14BasicMap<Policy>::EnableHeterogeneousFind<K, bool> folly::f14::detail::F14BasicMap<Policy>::contains(const K&) const [with K = int; Policy = folly::f14::detail::ValueContainerPolicy<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1>, void>]’ at folly/container/F14Map.h:931:24,
    inlined from ‘folly::f14::detail::F14BasicMap<Policy>::EnableHeterogeneousFind<K, long unsigned int> folly::f14::detail::F14BasicMap<Policy>::count(const K&) const [with K = int; Policy = folly::f14::detail::ValueContainerPolicy<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1>, void>]’ at folly/container/F14Map.h:789:20,
    inlined from ‘void runHeterogeneousInsertTest() [with M = folly::F14FastMap<folly::test::Tracked<1>, int, folly::test::TransparentTrackedHash<1>, folly::test::TransparentTrackedEqual<1> >]’ at folly/container/test/F14MapTest.cpp:1800:3:
/opt/rh/gcc-toolset-13/root/usr/include/c++/13/array:213:24: warning: array subscript 0 is outside array bounds of ‘const folly::f14::detail::F14EmptyTagVector [1]’ [-Warray-bounds=]
  213 |         return _M_elems[__n];
      |                ~~~~~~~~^
```

Reviewed By: ilvokhin

Differential Revision: D67791477

fbshipit-source-id: 78a82789dec0c04eda176111a2e4db241decaabf
  • Loading branch information
yfeldblum authored and facebook-github-bot committed Jan 6, 2025
1 parent d1a9afa commit 11ae18e
Showing 1 changed file with 14 additions and 0 deletions.
14 changes: 14 additions & 0 deletions folly/container/detail/F14Table.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,15 @@ using Defaulted =
template <typename T>
FOLLY_ALWAYS_INLINE static void prefetchAddr(T const* ptr) {
#ifndef _WIN32
FOLLY_PUSH_WARNING
FOLLY_GNU_DISABLE_WARNING("-Warray-bounds")
/// The argument ptr is permitted to be wild, since wild pointers are allowed
/// for prefetching on every architecture. While this behavior is technically
/// undefined (forbidden) in C and C++, we need this behavior in order to
/// avoid extra cost in the callers. Recent versions of GCC warn when they
/// detect uses of pointers which may be wild. So we suppress the warning.
__builtin_prefetch(static_cast<void const*>(ptr));
FOLLY_POP_WARNING
#elif FOLLY_NEON
__prefetch(static_cast<void const*>(ptr));
#elif FOLLY_SSE >= 2
Expand Down Expand Up @@ -745,13 +753,19 @@ struct alignas(kRequiredVectorAlignment) F14Chunk {
return tags_[index] != 0;
}

/// Permitted to return a wild pointer, which is allowed for prefetching on
/// every architecture. This behavior is technically undefined (forbidden) in
/// C and C++, but we violate the rule in order to avoid extra cost in the
/// prefetch paths. The wild pointer that may be returned is whatever follows
/// any empty-instance global in the memory of any DSO.
Item* itemAddr(std::size_t i) const {
return static_cast<Item*>(
const_cast<void*>(static_cast<void const*>(&rawItems_[i])));
}

Item& item(std::size_t i) {
FOLLY_SAFE_DCHECK(this->occupied(i), "");
compiler_may_unsafely_assume(this != getSomeEmptyInstance());
return *std::launder(itemAddr(i));
}

Expand Down

0 comments on commit 11ae18e

Please sign in to comment.