//===-- sanitizer_atomic_test.cc ------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
//
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_atomic.h"
#include "gtest/gtest.h"
namespace __sanitizer {
template<typename T>
struct ValAndMagic {
typename T::Type magic0;
T a;
typename T::Type magic1;
static ValAndMagic<T> *sink;
};
template<typename T>
ValAndMagic<T> *ValAndMagic<T>::sink;
template<typename T, memory_order load_mo, memory_order store_mo>
void CheckStoreLoad() {
typedef typename T::Type Type;
ValAndMagic<T> val;
// Prevent the compiler from scalarizing the struct.
ValAndMagic<T>::sink = &val;
// Ensure that surrounding memory is not overwritten.
val.magic0 = val.magic1 = (Type)-3;
for (u64 i = 0; i < 100; i++) {
// Generate a value that occupies all bytes of the variable.
u64 v = i;
v |= v << 8;
v |= v << 16;
v |= v << 32;
val.a.val_dont_use = (Type)v;
EXPECT_EQ(atomic_load(&val.a, load_mo), (Type)v);
val.a.val_dont_use = (Type)-1;
atomic_store(&val.a, (Type)v, store_mo);
EXPECT_EQ(val.a.val_dont_use, (Type)v);
}
EXPECT_EQ(val.magic0, (Type)-3);
EXPECT_EQ(val.magic1, (Type)-3);
}
TEST(SanitizerCommon, AtomicStoreLoad) {
CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_relaxed>();
CheckStoreLoad<atomic_uint8_t, memory_order_consume, memory_order_relaxed>();
CheckStoreLoad<atomic_uint8_t, memory_order_acquire, memory_order_relaxed>();
CheckStoreLoad<atomic_uint8_t, memory_order_relaxed, memory_order_release>();
CheckStoreLoad<atomic_uint8_t, memory_order_seq_cst, memory_order_seq_cst>();
CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_relaxed>();
CheckStoreLoad<atomic_uint16_t, memory_order_consume, memory_order_relaxed>();
CheckStoreLoad<atomic_uint16_t, memory_order_acquire, memory_order_relaxed>();
CheckStoreLoad<atomic_uint16_t, memory_order_relaxed, memory_order_release>();
CheckStoreLoad<atomic_uint16_t, memory_order_seq_cst, memory_order_seq_cst>();
CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_relaxed>();
CheckStoreLoad<atomic_uint32_t, memory_order_consume, memory_order_relaxed>();
CheckStoreLoad<atomic_uint32_t, memory_order_acquire, memory_order_relaxed>();
CheckStoreLoad<atomic_uint32_t, memory_order_relaxed, memory_order_release>();
CheckStoreLoad<atomic_uint32_t, memory_order_seq_cst, memory_order_seq_cst>();
CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_relaxed>();
CheckStoreLoad<atomic_uint64_t, memory_order_consume, memory_order_relaxed>();
CheckStoreLoad<atomic_uint64_t, memory_order_acquire, memory_order_relaxed>();
CheckStoreLoad<atomic_uint64_t, memory_order_relaxed, memory_order_release>();
CheckStoreLoad<atomic_uint64_t, memory_order_seq_cst, memory_order_seq_cst>();
CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_relaxed>
();
CheckStoreLoad<atomic_uintptr_t, memory_order_consume, memory_order_relaxed>
();
CheckStoreLoad<atomic_uintptr_t, memory_order_acquire, memory_order_relaxed>
();
CheckStoreLoad<atomic_uintptr_t, memory_order_relaxed, memory_order_release>
();
CheckStoreLoad<atomic_uintptr_t, memory_order_seq_cst, memory_order_seq_cst>
();
}
// Clang crashes while compiling this test for Android:
// http://llvm.org/bugs/show_bug.cgi?id=15587
#if !SANITIZER_ANDROID
template<typename T>
void CheckAtomicCompareExchange() {
typedef typename T::Type Type;
{
Type old_val = 42;
Type new_val = 24;
Type var = old_val;
EXPECT_TRUE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
memory_order_relaxed));
EXPECT_FALSE(atomic_compare_exchange_strong((T*)&var, &old_val, new_val,
memory_order_relaxed));
EXPECT_EQ(new_val, old_val);
}
{
Type old_val = 42;
Type new_val = 24;
Type var = old_val;
EXPECT_TRUE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
memory_order_relaxed));
EXPECT_FALSE(atomic_compare_exchange_weak((T*)&var, &old_val, new_val,
memory_order_relaxed));
EXPECT_EQ(new_val, old_val);
}
}
TEST(SanitizerCommon, AtomicCompareExchangeTest) {
CheckAtomicCompareExchange<atomic_uint8_t>();
CheckAtomicCompareExchange<atomic_uint16_t>();
CheckAtomicCompareExchange<atomic_uint32_t>();
CheckAtomicCompareExchange<atomic_uint64_t>();
CheckAtomicCompareExchange<atomic_uintptr_t>();
}
#endif //!SANITIZER_ANDROID
} // namespace __sanitizer