diff options
-rw-r--r-- | absl/hash/internal/hash.h | 3 | ||||
-rw-r--r-- | absl/strings/cord_buffer.h | 2 | ||||
-rw-r--r-- | absl/synchronization/mutex.cc | 5 | ||||
-rw-r--r-- | absl/synchronization/mutex_test.cc | 19 | ||||
-rw-r--r-- | absl/types/optional_test.cc | 15 |
5 files changed, 32 insertions, 12 deletions
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index 89740dab..61970e0d 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h @@ -1074,6 +1074,7 @@ class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> { // Reads 1 to 3 bytes from p. Zero pads to fill uint32_t. static uint32_t Read1To3(const unsigned char* p, size_t len) { + // The trick used by this implementation is to avoid branches if possible. unsigned char mem0 = p[0]; unsigned char mem1 = p[len / 2]; unsigned char mem2 = p[len - 1]; @@ -1083,7 +1084,7 @@ class ABSL_DLL MixingHashState : public HashStateBase<MixingHashState> { unsigned char significant0 = mem0; #else unsigned char significant2 = mem0; - unsigned char significant1 = mem1; + unsigned char significant1 = len == 2 ? mem0 : mem1; unsigned char significant0 = mem2; #endif return static_cast<uint32_t>(significant0 | // diff --git a/absl/strings/cord_buffer.h b/absl/strings/cord_buffer.h index e39c84cd..a3600ac4 100644 --- a/absl/strings/cord_buffer.h +++ b/absl/strings/cord_buffer.h @@ -460,7 +460,7 @@ inline constexpr size_t CordBuffer::MaximumPayload() { } inline constexpr size_t CordBuffer::MaximumPayload(size_t block_size) { - return std::min(kCustomLimit, block_size) - cord_internal::kFlatOverhead; + return (std::min)(kCustomLimit, block_size) - cord_internal::kFlatOverhead; } inline CordBuffer CordBuffer::CreateWithDefaultLimit(size_t capacity) { diff --git a/absl/synchronization/mutex.cc b/absl/synchronization/mutex.cc index f6a8506c..a8911614 100644 --- a/absl/synchronization/mutex.cc +++ b/absl/synchronization/mutex.cc @@ -1403,7 +1403,7 @@ static GraphId DeadlockCheck(Mutex *mu) { ABSL_RAW_LOG(ERROR, "Cycle: "); int path_len = deadlock_graph->FindPath( mu_id, other_node_id, ABSL_ARRAYSIZE(b->path), b->path); - for (int j = 0; j != path_len; j++) { + for (int j = 0; j != path_len && j != ABSL_ARRAYSIZE(b->path); j++) { GraphId id = b->path[j]; Mutex *path_mu = static_cast<Mutex *>(deadlock_graph->Ptr(id)); if (path_mu == nullptr) continue; @@ -1416,6 +1416,9 @@ static GraphId DeadlockCheck(Mutex *mu) { symbolize); ABSL_RAW_LOG(ERROR, "%s", b->buf); } + if (path_len > static_cast<int>(ABSL_ARRAYSIZE(b->path))) { + ABSL_RAW_LOG(ERROR, "(long cycle; list truncated)"); + } if (synch_deadlock_detection.load(std::memory_order_acquire) == OnDeadlockCycle::kAbort) { deadlock_graph_mu.Unlock(); // avoid deadlock in fatal sighandler diff --git a/absl/synchronization/mutex_test.cc b/absl/synchronization/mutex_test.cc index 34751cb1..f76b1e8b 100644 --- a/absl/synchronization/mutex_test.cc +++ b/absl/synchronization/mutex_test.cc @@ -1131,6 +1131,25 @@ TEST(Mutex, DeadlockDetectorBazelWarning) { absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); } +TEST(Mutex, DeadlockDetectorLongCycle) { + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kReport); + + // This test generates a warning if it passes, and crashes otherwise. + // Cause bazel to ignore the warning. + ScopedDisableBazelTestWarnings disable_bazel_test_warnings; + + // Check that we survive a deadlock with a lock cycle. + std::vector<absl::Mutex> mutex(100); + for (size_t i = 0; i != mutex.size(); i++) { + mutex[i].Lock(); + mutex[(i + 1) % mutex.size()].Lock(); + mutex[i].Unlock(); + mutex[(i + 1) % mutex.size()].Unlock(); + } + + absl::SetMutexDeadlockDetectionMode(absl::OnDeadlockCycle::kAbort); +} + // This test is tagged with NO_THREAD_SAFETY_ANALYSIS because the // annotation-based static thread-safety analysis is not currently // predicate-aware and cannot tell if the two for-loops that acquire and diff --git a/absl/types/optional_test.cc b/absl/types/optional_test.cc index fbd4e8c2..83a9bb4a 100644 --- a/absl/types/optional_test.cc +++ b/absl/types/optional_test.cc @@ -97,9 +97,9 @@ struct StructorListener { // 4522: multiple assignment operators specified // We wrote multiple of them to test that the correct overloads are selected. #ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4521) -#pragma warning( disable : 4522) +#pragma warning(push) +#pragma warning(disable : 4521) +#pragma warning(disable : 4522) #endif struct Listenable { static StructorListener* listener; @@ -133,7 +133,7 @@ struct Listenable { ~Listenable() { ++listener->destruct; } }; #ifdef _MSC_VER -#pragma warning( pop ) +#pragma warning(pop) #endif StructorListener* Listenable::listener = nullptr; @@ -987,9 +987,8 @@ TEST(optionalTest, PointerStuff) { // Skip that test to make the build green again when using the old compiler. // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59296 is fixed in 4.9.1. #if defined(__GNUC__) && !defined(__clang__) -#define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) #if GCC_VERSION < 40901 #define ABSL_SKIP_OVERLOAD_TEST_DUE_TO_GCC_BUG #endif @@ -1201,7 +1200,6 @@ void optionalTest_Comparisons_EXPECT_GREATER(T x, U y) { EXPECT_TRUE(x >= y); } - template <typename T, typename U, typename V> void TestComparisons() { absl::optional<T> ae, a2{2}, a4{4}; @@ -1294,7 +1292,6 @@ TEST(optionalTest, Comparisons) { EXPECT_TRUE(e1 == e2); } - TEST(optionalTest, SwapRegression) { StructorListener listener; Listenable::listener = &listener; |