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