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 <condition_variable> 12 #include <mutex> 13 #include <thread> 14 #include <vector> 15 16 void operator delete(void *, size_t) noexcept; 17 void operator delete[](void *, size_t) noexcept; 18 19 // Note that every Cxx allocation function in the test binary will be fulfilled 20 // by Scudo. See the comment in the C counterpart of this file. 21 22 template <typename T> static void testCxxNew() { 23 T *P = new T; 24 EXPECT_NE(P, nullptr); 25 memset(P, 0x42, sizeof(T)); 26 EXPECT_DEATH(delete[] P, ""); 27 delete P; 28 EXPECT_DEATH(delete P, ""); 29 30 P = new T; 31 EXPECT_NE(P, nullptr); 32 memset(P, 0x42, sizeof(T)); 33 operator delete(P, sizeof(T)); 34 35 P = new (std::nothrow) T; 36 EXPECT_NE(P, nullptr); 37 memset(P, 0x42, sizeof(T)); 38 delete P; 39 40 const size_t N = 16U; 41 T *A = new T[N]; 42 EXPECT_NE(A, nullptr); 43 memset(A, 0x42, sizeof(T) * N); 44 EXPECT_DEATH(delete A, ""); 45 delete[] A; 46 EXPECT_DEATH(delete[] A, ""); 47 48 A = new T[N]; 49 EXPECT_NE(A, nullptr); 50 memset(A, 0x42, sizeof(T) * N); 51 operator delete[](A, sizeof(T) * N); 52 53 A = new (std::nothrow) T[N]; 54 EXPECT_NE(A, nullptr); 55 memset(A, 0x42, sizeof(T) * N); 56 delete[] A; 57 } 58 59 class Pixel { 60 public: 61 enum class Color { Red, Green, Blue }; 62 int X = 0; 63 int Y = 0; 64 Color C = Color::Red; 65 }; 66 67 TEST(ScudoWrappersCppTest, New) { 68 testCxxNew<bool>(); 69 testCxxNew<uint8_t>(); 70 testCxxNew<uint16_t>(); 71 testCxxNew<uint32_t>(); 72 testCxxNew<uint64_t>(); 73 testCxxNew<float>(); 74 testCxxNew<double>(); 75 testCxxNew<long double>(); 76 testCxxNew<Pixel>(); 77 } 78 79 static std::mutex Mutex; 80 static std::condition_variable Cv; 81 static bool Ready = false; 82 83 static void stressNew() { 84 std::vector<uintptr_t *> V; 85 { 86 std::unique_lock<std::mutex> Lock(Mutex); 87 while (!Ready) 88 Cv.wait(Lock); 89 } 90 for (size_t I = 0; I < 256U; I++) { 91 const size_t N = std::rand() % 128U; 92 uintptr_t *P = new uintptr_t[N]; 93 if (P) { 94 memset(P, 0x42, sizeof(uintptr_t) * N); 95 V.push_back(P); 96 } 97 } 98 while (!V.empty()) { 99 delete[] V.back(); 100 V.pop_back(); 101 } 102 } 103 104 TEST(ScudoWrappersCppTest, ThreadedNew) { 105 std::thread Threads[32]; 106 for (size_t I = 0U; I < sizeof(Threads) / sizeof(Threads[0]); I++) 107 Threads[I] = std::thread(stressNew); 108 { 109 std::unique_lock<std::mutex> Lock(Mutex); 110 Ready = true; 111 Cv.notify_all(); 112 } 113 for (auto &T : Threads) 114 T.join(); 115 } 116