| 1 | //===-- harness.h -----------------------------------------------*- C++ -*-===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #ifndef GWP_ASAN_TESTS_HARNESS_H_ |
| 10 | #define GWP_ASAN_TESTS_HARNESS_H_ |
| 11 | |
| 12 | #include <stdarg.h> |
| 13 | |
| 14 | #if defined(__Fuchsia__) |
| 15 | #ifndef ZXTEST_USE_STREAMABLE_MACROS |
| 16 | #define ZXTEST_USE_STREAMABLE_MACROS |
| 17 | #endif |
| 18 | #include <zxtest/zxtest.h> |
| 19 | namespace testing = zxtest; |
| 20 | // zxtest defines a different ASSERT_DEATH, taking a lambda and an error message |
| 21 | // if death didn't occur, versus gtest taking a statement and a string to search |
| 22 | // for in the dying process. zxtest doesn't define an EXPECT_DEATH, so we use |
| 23 | // that in the tests below (which works as intended for gtest), and we define |
| 24 | // EXPECT_DEATH as a wrapper for zxtest's ASSERT_DEATH. Note that zxtest drops |
| 25 | // the functionality for checking for a particular message in death. |
| 26 | #define EXPECT_DEATH(X, Y) ASSERT_DEATH(([&] { X; }), "") |
| 27 | #else |
| 28 | #include "gtest/gtest.h" |
| 29 | #endif |
| 30 | |
| 31 | #include "gwp_asan/guarded_pool_allocator.h" |
| 32 | #include "gwp_asan/optional/backtrace.h" |
| 33 | #include "gwp_asan/optional/printf.h" |
| 34 | #include "gwp_asan/optional/segv_handler.h" |
| 35 | #include "gwp_asan/options.h" |
| 36 | |
| 37 | namespace gwp_asan { |
| 38 | namespace test { |
| 39 | // This printf-function getter allows other platforms (e.g. Android) to define |
| 40 | // their own signal-safe Printf function. In LLVM, we use |
| 41 | // `optional/printf_sanitizer_common.cpp` which supplies the __sanitizer::Printf |
| 42 | // for this purpose. |
| 43 | Printf_t getPrintfFunction(); |
| 44 | }; // namespace test |
| 45 | }; // namespace gwp_asan |
| 46 | |
| 47 | char *AllocateMemory(gwp_asan::GuardedPoolAllocator &GPA); |
| 48 | void DeallocateMemory(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr); |
| 49 | void DeallocateMemory2(gwp_asan::GuardedPoolAllocator &GPA, void *Ptr); |
| 50 | void TouchMemory(void *Ptr); |
| 51 | |
| 52 | void CheckOnlyOneGwpAsanCrash(const std::string &OutputBuffer); |
| 53 | |
| 54 | class DefaultGuardedPoolAllocator : public ::testing::Test { |
| 55 | public: |
| 56 | void SetUp() override { |
| 57 | gwp_asan::options::Options Opts; |
| 58 | MaxSimultaneousAllocations = Opts.MaxSimultaneousAllocations; |
| 59 | GPA.init(Opts); |
| 60 | } |
| 61 | |
| 62 | void TearDown() override { GPA.uninitTestOnly(); } |
| 63 | |
| 64 | protected: |
| 65 | gwp_asan::GuardedPoolAllocator GPA; |
| 66 | decltype(gwp_asan::options::Options::MaxSimultaneousAllocations) |
| 67 | MaxSimultaneousAllocations; |
| 68 | }; |
| 69 | |
| 70 | class CustomGuardedPoolAllocator : public ::testing::Test { |
| 71 | public: |
| 72 | void |
| 73 | InitNumSlots(decltype(gwp_asan::options::Options::MaxSimultaneousAllocations) |
| 74 | MaxSimultaneousAllocationsArg) { |
| 75 | gwp_asan::options::Options Opts; |
| 76 | Opts.MaxSimultaneousAllocations = MaxSimultaneousAllocationsArg; |
| 77 | MaxSimultaneousAllocations = MaxSimultaneousAllocationsArg; |
| 78 | GPA.init(Opts); |
| 79 | } |
| 80 | |
| 81 | void TearDown() override { GPA.uninitTestOnly(); } |
| 82 | |
| 83 | protected: |
| 84 | gwp_asan::GuardedPoolAllocator GPA; |
| 85 | decltype(gwp_asan::options::Options::MaxSimultaneousAllocations) |
| 86 | MaxSimultaneousAllocations; |
| 87 | }; |
| 88 | |
| 89 | class BacktraceGuardedPoolAllocator |
| 90 | : public ::testing::TestWithParam</* Recoverable */ bool> { |
| 91 | public: |
| 92 | void SetUp() override { |
| 93 | gwp_asan::options::Options Opts; |
| 94 | Opts.Backtrace = gwp_asan::backtrace::getBacktraceFunction(); |
| 95 | GPA.init(Opts); |
| 96 | |
| 97 | // In recoverable mode, capture GWP-ASan logs to an internal buffer so that |
| 98 | // we can search it in unit tests. For non-recoverable tests, the default |
| 99 | // buffer is fine, as any tests should be EXPECT_DEATH()'d. |
| 100 | Recoverable = GetParam(); |
| 101 | gwp_asan::Printf_t PrintfFunction = PrintfToBuffer; |
| 102 | GetOutputBuffer().clear(); |
| 103 | if (!Recoverable) |
| 104 | PrintfFunction = gwp_asan::test::getPrintfFunction(); |
| 105 | |
| 106 | gwp_asan::segv_handler::installSignalHandlers( |
| 107 | GPA: &GPA, Printf: PrintfFunction, PrintBacktrace: gwp_asan::backtrace::getPrintBacktraceFunction(), |
| 108 | SegvBacktrace: gwp_asan::backtrace::getSegvBacktraceFunction(), |
| 109 | /* Recoverable */ Recoverable); |
| 110 | } |
| 111 | |
| 112 | void TearDown() override { |
| 113 | GPA.uninitTestOnly(); |
| 114 | gwp_asan::segv_handler::uninstallSignalHandlers(); |
| 115 | } |
| 116 | |
| 117 | protected: |
| 118 | static std::string &GetOutputBuffer() { |
| 119 | static std::string Buffer; |
| 120 | return Buffer; |
| 121 | } |
| 122 | |
| 123 | __attribute__((format(printf, 1, 2))) static void |
| 124 | PrintfToBuffer(const char *Format, ...) { |
| 125 | va_list AP; |
| 126 | va_start(AP, Format); |
| 127 | char Buffer[8192]; |
| 128 | vsnprintf(Buffer, sizeof(Buffer), Format, AP); |
| 129 | GetOutputBuffer() += Buffer; |
| 130 | va_end(AP); |
| 131 | } |
| 132 | |
| 133 | gwp_asan::GuardedPoolAllocator GPA; |
| 134 | bool Recoverable; |
| 135 | }; |
| 136 | |
| 137 | // https://github.com/google/googletest/blob/master/docs/advanced.md#death-tests-and-threads |
| 138 | using DefaultGuardedPoolAllocatorDeathTest = DefaultGuardedPoolAllocator; |
| 139 | using CustomGuardedPoolAllocatorDeathTest = CustomGuardedPoolAllocator; |
| 140 | using BacktraceGuardedPoolAllocatorDeathTest = BacktraceGuardedPoolAllocator; |
| 141 | |
| 142 | #endif // GWP_ASAN_TESTS_HARNESS_H_ |
| 143 | |