1 //===-- wrappers_cpp_test.cpp -----------------------------------*- 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 #include "tests/scudo_unit_test.h" 10 11 #include <atomic> 12 #include <condition_variable> 13 #include <mutex> 14 #include <thread> 15 #include <vector> 16 17 void operator delete(void *, size_t) noexcept; 18 void operator delete[](void *, size_t) noexcept; 19 20 // Note that every Cxx allocation function in the test binary will be fulfilled 21 // by Scudo. See the comment in the C counterpart of this file. 22 23 template <typename T> static void testCxxNew() { 24 T *P = new T; 25 EXPECT_NE(P, nullptr); 26 memset(P, 0x42, sizeof(T)); 27 EXPECT_DEATH(delete[] P, ""); 28 delete P; 29 EXPECT_DEATH(delete P, ""); 30 31 P = new T; 32 EXPECT_NE(P, nullptr); 33 memset(P, 0x42, sizeof(T)); 34 operator delete(P, sizeof(T)); 35 36 P = new (std::nothrow) T; 37 EXPECT_NE(P, nullptr); 38 memset(P, 0x42, sizeof(T)); 39 delete P; 40 41 const size_t N = 16U; 42 T *A = new T[N]; 43 EXPECT_NE(A, nullptr); 44 memset(A, 0x42, sizeof(T) * N); 45 EXPECT_DEATH(delete A, ""); 46 delete[] A; 47 EXPECT_DEATH(delete[] A, ""); 48 49 A = new T[N]; 50 EXPECT_NE(A, nullptr); 51 memset(A, 0x42, sizeof(T) * N); 52 operator delete[](A, sizeof(T) * N); 53 54 A = new (std::nothrow) T[N]; 55 EXPECT_NE(A, nullptr); 56 memset(A, 0x42, sizeof(T) * N); 57 delete[] A; 58 } 59 60 class Pixel { 61 public: 62 enum class Color { Red, Green, Blue }; 63 int X = 0; 64 int Y = 0; 65 Color C = Color::Red; 66 }; 67 68 TEST(ScudoWrappersCppTest, New) { 69 testCxxNew<bool>(); 70 testCxxNew<uint8_t>(); 71 testCxxNew<uint16_t>(); 72 testCxxNew<uint32_t>(); 73 testCxxNew<uint64_t>(); 74 testCxxNew<float>(); 75 testCxxNew<double>(); 76 testCxxNew<long double>(); 77 testCxxNew<Pixel>(); 78 } 79 80 static std::mutex Mutex; 81 static std::condition_variable Cv; 82 static bool Ready = false; 83 84 static void stressNew() { 85 std::vector<uintptr_t *> V; 86 { 87 std::unique_lock<std::mutex> Lock(Mutex); 88 while (!Ready) 89 Cv.wait(Lock); 90 } 91 for (size_t I = 0; I < 256U; I++) { 92 const size_t N = std::rand() % 128U; 93 uintptr_t *P = new uintptr_t[N]; 94 if (P) { 95 memset(P, 0x42, sizeof(uintptr_t) * N); 96 V.push_back(P); 97 } 98 } 99 while (!V.empty()) { 100 delete[] V.back(); 101 V.pop_back(); 102 } 103 } 104 105 TEST(ScudoWrappersCppTest, ThreadedNew) { 106 std::thread Threads[32]; 107 for (size_t I = 0U; I < sizeof(Threads) / sizeof(Threads[0]); I++) 108 Threads[I] = std::thread(stressNew); 109 { 110 std::unique_lock<std::mutex> Lock(Mutex); 111 Ready = true; 112 Cv.notify_all(); 113 } 114 for (auto &T : Threads) 115 T.join(); 116 } 117 118 #if !SCUDO_FUCHSIA 119 // TODO(kostyak): for me, this test fails in a specific configuration when ran 120 // by itself with some Scudo or GWP-ASan violation. Other people 121 // can't seem to reproduce the failure. Consider skipping this in 122 // the event it fails on the upstream bots. 123 TEST(ScudoWrappersCppTest, AllocAfterFork) { 124 std::atomic_bool Stop; 125 126 // Create threads that simply allocate and free different sizes. 127 std::vector<std::thread *> Threads; 128 for (size_t N = 0; N < 5; N++) { 129 std::thread *T = new std::thread([&Stop] { 130 while (!Stop) { 131 for (size_t SizeLog = 3; SizeLog <= 21; SizeLog++) { 132 char *P = new char[1UL << SizeLog]; 133 EXPECT_NE(P, nullptr); 134 // Make sure this value is not optimized away. 135 asm volatile("" : : "r,m"(P) : "memory"); 136 delete[] P; 137 } 138 } 139 }); 140 Threads.push_back(T); 141 } 142 143 // Create a thread to fork and allocate. 144 for (size_t N = 0; N < 100; N++) { 145 pid_t Pid; 146 if ((Pid = fork()) == 0) { 147 for (size_t SizeLog = 3; SizeLog <= 21; SizeLog++) { 148 char *P = new char[1UL << SizeLog]; 149 EXPECT_NE(P, nullptr); 150 // Make sure this value is not optimized away. 151 asm volatile("" : : "r,m"(P) : "memory"); 152 // Make sure we can touch all of the allocation. 153 memset(P, 0x32, 1U << SizeLog); 154 // EXPECT_LE(1U << SizeLog, malloc_usable_size(ptr)); 155 delete[] P; 156 } 157 _exit(10); 158 } 159 EXPECT_NE(-1, Pid); 160 int Status; 161 EXPECT_EQ(Pid, waitpid(Pid, &Status, 0)); 162 EXPECT_FALSE(WIFSIGNALED(Status)); 163 EXPECT_EQ(10, WEXITSTATUS(Status)); 164 } 165 166 printf("Waiting for threads to complete\n"); 167 Stop = true; 168 for (auto Thread : Threads) 169 Thread->join(); 170 Threads.clear(); 171 } 172 #endif 173