summaryrefslogtreecommitdiffstats
path: root/compiler-rt/lib/gwp_asan/tests
diff options
context:
space:
mode:
Diffstat (limited to 'compiler-rt/lib/gwp_asan/tests')
-rw-r--r--compiler-rt/lib/gwp_asan/tests/CMakeLists.txt8
-rw-r--r--compiler-rt/lib/gwp_asan/tests/alignment.cpp27
-rw-r--r--compiler-rt/lib/gwp_asan/tests/basic.cpp60
-rw-r--r--compiler-rt/lib/gwp_asan/tests/harness.h60
-rw-r--r--compiler-rt/lib/gwp_asan/tests/slot_reuse.cpp72
-rw-r--r--compiler-rt/lib/gwp_asan/tests/thread_contention.cpp69
6 files changed, 294 insertions, 2 deletions
diff --git a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt
index 6a59be5bca6..f2f72c85861 100644
--- a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt
+++ b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt
@@ -9,7 +9,8 @@ set(GWP_ASAN_UNITTEST_CFLAGS
file(GLOB GWP_ASAN_HEADERS ../*.h)
file(GLOB GWP_ASAN_UNITTESTS *.cpp)
set(GWP_ASAN_UNIT_TEST_HEADERS
- ${GWP_ASAN_HEADERS})
+ ${GWP_ASAN_HEADERS}
+ harness.h)
add_custom_target(GwpAsanUnitTests)
set_target_properties(GwpAsanUnitTests PROPERTIES FOLDER "Compiler-RT Tests")
@@ -26,8 +27,11 @@ if(COMPILER_RT_DEFAULT_TARGET_ARCH IN_LIST GWP_ASAN_SUPPORTED_ARCH)
set(GWP_ASAN_TEST_RUNTIME RTGwpAsanTest.${arch})
+ # RTSanitizerCommonNoTermination(NoLibc) required for __sanitizer::Printf.
set(GWP_ASAN_TEST_RUNTIME_OBJECTS
- $<TARGET_OBJECTS:RTGwpAsan.${arch}>)
+ $<TARGET_OBJECTS:RTGwpAsan.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommon.${arch}>
+ $<TARGET_OBJECTS:RTSanitizerCommonNoLibc.${arch}>)
add_library(${GWP_ASAN_TEST_RUNTIME} STATIC
${GWP_ASAN_TEST_RUNTIME_OBJECTS})
diff --git a/compiler-rt/lib/gwp_asan/tests/alignment.cpp b/compiler-rt/lib/gwp_asan/tests/alignment.cpp
new file mode 100644
index 00000000000..ffb91d5b57a
--- /dev/null
+++ b/compiler-rt/lib/gwp_asan/tests/alignment.cpp
@@ -0,0 +1,27 @@
+//===-- alignment.cc --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gwp_asan/tests/harness.h"
+
+TEST_F(DefaultGuardedPoolAllocator, BasicAllocation) {
+ std::vector<std::pair<int, int>> AllocSizeToAlignment = {
+ {1, 1}, {2, 2}, {3, 4}, {4, 4}, {5, 8}, {7, 8},
+ {8, 8}, {9, 16}, {15, 16}, {16, 16}, {17, 16}, {31, 16},
+ {32, 16}, {33, 16}, {4095, 4096}, {4096, 4096},
+ };
+
+ for (const auto &KV : AllocSizeToAlignment) {
+ void *Ptr = GPA.allocate(KV.first);
+ EXPECT_NE(nullptr, Ptr);
+
+ // Check the alignment of the pointer is as expected.
+ EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(Ptr) % KV.second);
+
+ GPA.deallocate(Ptr);
+ }
+}
diff --git a/compiler-rt/lib/gwp_asan/tests/basic.cpp b/compiler-rt/lib/gwp_asan/tests/basic.cpp
new file mode 100644
index 00000000000..9c80e276510
--- /dev/null
+++ b/compiler-rt/lib/gwp_asan/tests/basic.cpp
@@ -0,0 +1,60 @@
+//===-- basic.cc ------------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gwp_asan/tests/harness.h"
+
+TEST_F(CustomGuardedPoolAllocator, BasicAllocation) {
+ InitNumSlots(1);
+ void *Ptr = GPA.allocate(1);
+ EXPECT_NE(nullptr, Ptr);
+ EXPECT_TRUE(GPA.pointerIsMine(Ptr));
+ EXPECT_EQ(1u, GPA.getSize(Ptr));
+ GPA.deallocate(Ptr);
+}
+
+TEST_F(DefaultGuardedPoolAllocator, NullptrIsNotMine) {
+ EXPECT_FALSE(GPA.pointerIsMine(nullptr));
+}
+
+TEST_F(CustomGuardedPoolAllocator, SizedAllocations) {
+ InitNumSlots(1);
+
+ std::size_t MaxAllocSize = GPA.maximumAllocationSize();
+ EXPECT_TRUE(MaxAllocSize > 0);
+
+ for (unsigned AllocSize = 1; AllocSize <= MaxAllocSize; AllocSize <<= 1) {
+ void *Ptr = GPA.allocate(AllocSize);
+ EXPECT_NE(nullptr, Ptr);
+ EXPECT_TRUE(GPA.pointerIsMine(Ptr));
+ EXPECT_EQ(AllocSize, GPA.getSize(Ptr));
+ GPA.deallocate(Ptr);
+ }
+}
+
+TEST_F(DefaultGuardedPoolAllocator, TooLargeAllocation) {
+ EXPECT_EQ(nullptr, GPA.allocate(GPA.maximumAllocationSize() + 1));
+}
+
+TEST_F(CustomGuardedPoolAllocator, AllocAllSlots) {
+ constexpr unsigned kNumSlots = 128;
+ InitNumSlots(kNumSlots);
+ void *Ptrs[kNumSlots];
+ for (unsigned i = 0; i < kNumSlots; ++i) {
+ Ptrs[i] = GPA.allocate(1);
+ EXPECT_NE(nullptr, Ptrs[i]);
+ EXPECT_TRUE(GPA.pointerIsMine(Ptrs[i]));
+ }
+
+ // This allocation should fail as all the slots are used.
+ void *Ptr = GPA.allocate(1);
+ EXPECT_EQ(nullptr, Ptr);
+ EXPECT_FALSE(GPA.pointerIsMine(nullptr));
+
+ for (unsigned i = 0; i < kNumSlots; ++i)
+ GPA.deallocate(Ptrs[i]);
+}
diff --git a/compiler-rt/lib/gwp_asan/tests/harness.h b/compiler-rt/lib/gwp_asan/tests/harness.h
new file mode 100644
index 00000000000..987564dd9af
--- /dev/null
+++ b/compiler-rt/lib/gwp_asan/tests/harness.h
@@ -0,0 +1,60 @@
+//===-- harness.h -----------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef GWP_ASAN_TESTS_HARNESS_H_
+#define GWP_ASAN_TESTS_HARNESS_H_
+
+#include "gtest/gtest.h"
+
+// Include sanitizer_common first as gwp_asan/guarded_pool_allocator.h
+// transiently includes definitions.h, which overwrites some of the definitions
+// in sanitizer_common.
+#include "sanitizer_common/sanitizer_common.h"
+
+#include "gwp_asan/guarded_pool_allocator.h"
+#include "gwp_asan/options.h"
+
+class DefaultGuardedPoolAllocator : public ::testing::Test {
+public:
+ DefaultGuardedPoolAllocator() {
+ gwp_asan::options::Options Opts;
+ Opts.setDefaults();
+ MaxSimultaneousAllocations = Opts.MaxSimultaneousAllocations;
+
+ Opts.Printf = __sanitizer::Printf;
+ GPA.init(Opts);
+ }
+
+protected:
+ gwp_asan::GuardedPoolAllocator GPA;
+ decltype(gwp_asan::options::Options::MaxSimultaneousAllocations)
+ MaxSimultaneousAllocations;
+};
+
+class CustomGuardedPoolAllocator : public ::testing::Test {
+public:
+ void
+ InitNumSlots(decltype(gwp_asan::options::Options::MaxSimultaneousAllocations)
+ MaxSimultaneousAllocationsArg) {
+ gwp_asan::options::Options Opts;
+ Opts.setDefaults();
+
+ Opts.MaxSimultaneousAllocations = MaxSimultaneousAllocationsArg;
+ MaxSimultaneousAllocations = MaxSimultaneousAllocationsArg;
+
+ Opts.Printf = __sanitizer::Printf;
+ GPA.init(Opts);
+ }
+
+protected:
+ gwp_asan::GuardedPoolAllocator GPA;
+ decltype(gwp_asan::options::Options::MaxSimultaneousAllocations)
+ MaxSimultaneousAllocations;
+};
+
+#endif // GWP_ASAN_TESTS_HARNESS_H_
diff --git a/compiler-rt/lib/gwp_asan/tests/slot_reuse.cpp b/compiler-rt/lib/gwp_asan/tests/slot_reuse.cpp
new file mode 100644
index 00000000000..e2437390231
--- /dev/null
+++ b/compiler-rt/lib/gwp_asan/tests/slot_reuse.cpp
@@ -0,0 +1,72 @@
+//===-- slot_reuse.cc -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gwp_asan/tests/harness.h"
+
+void singleByteGoodAllocDealloc(gwp_asan::GuardedPoolAllocator *GPA) {
+ void *Ptr = GPA->allocate(1);
+ EXPECT_NE(nullptr, Ptr);
+ EXPECT_TRUE(GPA->pointerIsMine(Ptr));
+ EXPECT_EQ(1u, GPA->getSize(Ptr));
+ GPA->deallocate(Ptr);
+}
+
+TEST_F(CustomGuardedPoolAllocator, EnsureReuseOfQuarantine1) {
+ InitNumSlots(1);
+ for (unsigned i = 0; i < 128; ++i)
+ singleByteGoodAllocDealloc(&GPA);
+}
+
+TEST_F(CustomGuardedPoolAllocator, EnsureReuseOfQuarantine2) {
+ InitNumSlots(2);
+ for (unsigned i = 0; i < 128; ++i)
+ singleByteGoodAllocDealloc(&GPA);
+}
+
+TEST_F(CustomGuardedPoolAllocator, EnsureReuseOfQuarantine127) {
+ InitNumSlots(127);
+ for (unsigned i = 0; i < 128; ++i)
+ singleByteGoodAllocDealloc(&GPA);
+}
+
+// This test ensures that our slots are not reused ahead of time. We increase
+// the use-after-free detection by not reusing slots until all of them have been
+// allocated. This is done by always using the slots from left-to-right in the
+// pool before we used each slot once, at which point random selection takes
+// over.
+void runNoReuseBeforeNecessary(gwp_asan::GuardedPoolAllocator *GPA,
+ unsigned PoolSize) {
+ std::set<void *> Ptrs;
+ for (unsigned i = 0; i < PoolSize; ++i) {
+ void *Ptr = GPA->allocate(1);
+
+ EXPECT_TRUE(GPA->pointerIsMine(Ptr));
+ EXPECT_EQ(0u, Ptrs.count(Ptr));
+
+ Ptrs.insert(Ptr);
+ GPA->deallocate(Ptr);
+ }
+}
+
+TEST_F(CustomGuardedPoolAllocator, NoReuseBeforeNecessary2) {
+ constexpr unsigned kPoolSize = 2;
+ InitNumSlots(kPoolSize);
+ runNoReuseBeforeNecessary(&GPA, kPoolSize);
+}
+
+TEST_F(CustomGuardedPoolAllocator, NoReuseBeforeNecessary128) {
+ constexpr unsigned kPoolSize = 128;
+ InitNumSlots(kPoolSize);
+ runNoReuseBeforeNecessary(&GPA, kPoolSize);
+}
+
+TEST_F(CustomGuardedPoolAllocator, NoReuseBeforeNecessary129) {
+ constexpr unsigned kPoolSize = 129;
+ InitNumSlots(kPoolSize);
+ runNoReuseBeforeNecessary(&GPA, kPoolSize);
+}
diff --git a/compiler-rt/lib/gwp_asan/tests/thread_contention.cpp b/compiler-rt/lib/gwp_asan/tests/thread_contention.cpp
new file mode 100644
index 00000000000..1c00f4413dd
--- /dev/null
+++ b/compiler-rt/lib/gwp_asan/tests/thread_contention.cpp
@@ -0,0 +1,69 @@
+//===-- thread_contention.cc ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "gwp_asan/tests/harness.h"
+
+// Note: Compilation of <atomic> and <thread> are extremely expensive for
+// non-opt builds of clang.
+#include <atomic>
+#include <cstdlib>
+#include <thread>
+#include <vector>
+
+void asyncTask(gwp_asan::GuardedPoolAllocator *GPA,
+ std::atomic<bool> *StartingGun, unsigned NumIterations) {
+ while (!*StartingGun) {
+ // Wait for starting gun.
+ }
+
+ // Get ourselves a new allocation.
+ for (unsigned i = 0; i < NumIterations; ++i) {
+ volatile char *Ptr = reinterpret_cast<volatile char *>(
+ GPA->allocate(GPA->maximumAllocationSize()));
+ // Do any other threads have access to this page?
+ EXPECT_EQ(*Ptr, 0);
+
+ // Mark the page as from malloc. Wait to see if another thread also takes
+ // this page.
+ *Ptr = 'A';
+ std::this_thread::sleep_for(std::chrono::nanoseconds(10000));
+
+ // Check we still own the page.
+ EXPECT_EQ(*Ptr, 'A');
+
+ // And now release it.
+ *Ptr = 0;
+ GPA->deallocate(const_cast<char *>(Ptr));
+ }
+}
+
+void runThreadContentionTest(unsigned NumThreads, unsigned NumIterations,
+ gwp_asan::GuardedPoolAllocator *GPA) {
+
+ std::atomic<bool> StartingGun{false};
+ std::vector<std::thread> Threads;
+ if (std::thread::hardware_concurrency() < NumThreads) {
+ NumThreads = std::thread::hardware_concurrency();
+ }
+
+ for (unsigned i = 0; i < NumThreads; ++i) {
+ Threads.emplace_back(asyncTask, GPA, &StartingGun, NumIterations);
+ }
+
+ StartingGun = true;
+
+ for (auto &T : Threads)
+ T.join();
+}
+
+TEST_F(CustomGuardedPoolAllocator, ThreadContention) {
+ unsigned NumThreads = 4;
+ unsigned NumIterations = 10000;
+ InitNumSlots(NumThreads);
+ runThreadContentionTest(NumThreads, NumIterations, &GPA);
+}
OpenPOWER on IntegriCloud