Commit 28da027e authored by Nathan Bronson's avatar Nathan Bronson Committed by Facebook GitHub Bot

suggest race condition to users that trip F14's internal checks

Summary:
Some of the CHECKs and DCHECKs in F14 are often tripped by users
that write to an F14 map or set from multiple threads without proper
concurrency control.  This diff adds a message to those locations that
suggests that they may have a race condition.

Reviewed By: yfeldblum

Differential Revision: D22826369

fbshipit-source-id: 8d5e96feea4dbb8dda404980d9a9d3412fb2eb64
parent 2fb430a3
...@@ -129,6 +129,11 @@ struct F14TableStats { ...@@ -129,6 +129,11 @@ struct F14TableStats {
namespace f14 { namespace f14 {
namespace detail { namespace detail {
inline constexpr char const* invariantFailurePossibleRaceCondition() {
return "F14 internal invariant violated, most likely due to a race condition, "
"use-after-free, or heap corruption";
}
template <F14IntrinsicsMode> template <F14IntrinsicsMode>
struct F14LinkCheck {}; struct F14LinkCheck {};
...@@ -444,12 +449,14 @@ struct alignas(kRequiredVectorAlignment) F14Chunk { ...@@ -444,12 +449,14 @@ struct alignas(kRequiredVectorAlignment) F14Chunk {
void setTag(std::size_t index, std::size_t tag) { void setTag(std::size_t index, std::size_t tag) {
FOLLY_SAFE_DCHECK( FOLLY_SAFE_DCHECK(
this != emptyInstance() && tag >= 0x80 && tag <= 0xff, ""); this != emptyInstance() && tag >= 0x80 && tag <= 0xff, "");
FOLLY_SAFE_CHECK(tags_[index] == 0, ""); FOLLY_SAFE_CHECK(
tags_[index] == 0, invariantFailurePossibleRaceCondition());
tags_[index] = static_cast<uint8_t>(tag); tags_[index] = static_cast<uint8_t>(tag);
} }
void clearTag(std::size_t index) { void clearTag(std::size_t index) {
FOLLY_SAFE_CHECK((tags_[index] & 0x80) != 0, ""); FOLLY_SAFE_CHECK(
(tags_[index] & 0x80) != 0, invariantFailurePossibleRaceCondition());
tags_[index] = 0; tags_[index] = 0;
} }
...@@ -534,7 +541,9 @@ struct alignas(kRequiredVectorAlignment) F14Chunk { ...@@ -534,7 +541,9 @@ struct alignas(kRequiredVectorAlignment) F14Chunk {
} }
bool occupied(std::size_t index) const { bool occupied(std::size_t index) const {
FOLLY_SAFE_DCHECK(tags_[index] == 0 || (tags_[index] & 0x80) != 0, ""); FOLLY_SAFE_DCHECK(
tags_[index] == 0 || (tags_[index] & 0x80) != 0,
invariantFailurePossibleRaceCondition());
return tags_[index] != 0; return tags_[index] != 0;
} }
...@@ -544,12 +553,14 @@ struct alignas(kRequiredVectorAlignment) F14Chunk { ...@@ -544,12 +553,14 @@ struct alignas(kRequiredVectorAlignment) F14Chunk {
} }
Item& item(std::size_t i) { Item& item(std::size_t i) {
FOLLY_SAFE_DCHECK(this->occupied(i), ""); FOLLY_SAFE_DCHECK(
this->occupied(i), invariantFailurePossibleRaceCondition());
return *launder(itemAddr(i)); return *launder(itemAddr(i));
} }
Item const& citem(std::size_t i) const { Item const& citem(std::size_t i) const {
FOLLY_SAFE_DCHECK(this->occupied(i), ""); FOLLY_SAFE_DCHECK(
this->occupied(i), invariantFailurePossibleRaceCondition());
return *launder(itemAddr(i)); return *launder(itemAddr(i));
} }
...@@ -1523,7 +1534,8 @@ class F14Table : public Policy { ...@@ -1523,7 +1534,8 @@ class F14Table : public Policy {
index += delta; index += delta;
} }
unsigned itemIndex = fullness[index]++; unsigned itemIndex = fullness[index]++;
FOLLY_SAFE_DCHECK(!chunk->occupied(itemIndex), ""); FOLLY_SAFE_DCHECK(
!chunk->occupied(itemIndex), invariantFailurePossibleRaceCondition());
chunk->setTag(itemIndex, hp.second); chunk->setTag(itemIndex, hp.second);
chunk->adjustHostedOverflowCount(hostedOp); chunk->adjustHostedOverflowCount(hostedOp);
return ItemIter{chunk, itemIndex}; return ItemIter{chunk, itemIndex};
...@@ -1710,7 +1722,9 @@ class F14Table : public Policy { ...@@ -1710,7 +1722,9 @@ class F14Table : public Policy {
auto&& srcArg = std::forward<T>(src).buildArgForItem(srcItem); auto&& srcArg = std::forward<T>(src).buildArgForItem(srcItem);
auto const& srcKey = src.keyForValue(srcArg); auto const& srcKey = src.keyForValue(srcArg);
auto hp = splitHash(this->computeKeyHash(srcKey)); auto hp = splitHash(this->computeKeyHash(srcKey));
FOLLY_SAFE_CHECK(hp.second == srcChunk->tag(i), ""); FOLLY_SAFE_CHECK(
hp.second == srcChunk->tag(i),
invariantFailurePossibleRaceCondition());
insertAtBlank( insertAtBlank(
allocateTag(fullness, hp), allocateTag(fullness, hp),
hp, hp,
...@@ -1942,7 +1956,9 @@ class F14Table : public Policy { ...@@ -1942,7 +1956,9 @@ class F14Table : public Policy {
Item& srcItem = srcChunk->item(srcI); Item& srcItem = srcChunk->item(srcI);
auto hp = splitHash( auto hp = splitHash(
this->computeItemHash(const_cast<Item const&>(srcItem))); this->computeItemHash(const_cast<Item const&>(srcItem)));
FOLLY_SAFE_CHECK(hp.second == srcChunk->tag(srcI), ""); FOLLY_SAFE_CHECK(
hp.second == srcChunk->tag(srcI),
invariantFailurePossibleRaceCondition());
auto dstIter = allocateTag(fullness, hp); auto dstIter = allocateTag(fullness, hp);
this->moveItemDuringRehash(dstIter.itemAddr(), srcItem); this->moveItemDuringRehash(dstIter.itemAddr(), srcItem);
...@@ -2007,7 +2023,8 @@ class F14Table : public Policy { ...@@ -2007,7 +2023,8 @@ class F14Table : public Policy {
FOLLY_ALWAYS_INLINE void debugModePerturbSlotInsertOrder( FOLLY_ALWAYS_INLINE void debugModePerturbSlotInsertOrder(
ChunkPtr chunk, ChunkPtr chunk,
std::size_t& itemIndex) { std::size_t& itemIndex) {
FOLLY_SAFE_DCHECK(!chunk->occupied(itemIndex), ""); FOLLY_SAFE_DCHECK(
!chunk->occupied(itemIndex), invariantFailurePossibleRaceCondition());
constexpr bool perturbSlot = FOLLY_F14_PERTURB_INSERTION_ORDER; constexpr bool perturbSlot = FOLLY_F14_PERTURB_INSERTION_ORDER;
if (perturbSlot && !tlsPendingSafeInserts()) { if (perturbSlot && !tlsPendingSafeInserts()) {
std::size_t e = chunkMask_ == 0 ? bucket_count() : Chunk::kCapacity; std::size_t e = chunkMask_ == 0 ? bucket_count() : Chunk::kCapacity;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment