1*76559068SAndroid Build Coastguard Worker //===-- wrappers_cpp_test.cpp -----------------------------------*- C++ -*-===//
2*76559068SAndroid Build Coastguard Worker //
3*76559068SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*76559068SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information.
5*76559068SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*76559068SAndroid Build Coastguard Worker //
7*76559068SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
8*76559068SAndroid Build Coastguard Worker
9*76559068SAndroid Build Coastguard Worker #include "memtag.h"
10*76559068SAndroid Build Coastguard Worker #include "tests/scudo_unit_test.h"
11*76559068SAndroid Build Coastguard Worker
12*76559068SAndroid Build Coastguard Worker #include <atomic>
13*76559068SAndroid Build Coastguard Worker #include <condition_variable>
14*76559068SAndroid Build Coastguard Worker #include <fstream>
15*76559068SAndroid Build Coastguard Worker #include <memory>
16*76559068SAndroid Build Coastguard Worker #include <mutex>
17*76559068SAndroid Build Coastguard Worker #include <thread>
18*76559068SAndroid Build Coastguard Worker #include <vector>
19*76559068SAndroid Build Coastguard Worker
20*76559068SAndroid Build Coastguard Worker // Android does not support checking for new/delete mismatches.
21*76559068SAndroid Build Coastguard Worker #if SCUDO_ANDROID
22*76559068SAndroid Build Coastguard Worker #define SKIP_MISMATCH_TESTS 1
23*76559068SAndroid Build Coastguard Worker #else
24*76559068SAndroid Build Coastguard Worker #define SKIP_MISMATCH_TESTS 0
25*76559068SAndroid Build Coastguard Worker #endif
26*76559068SAndroid Build Coastguard Worker
27*76559068SAndroid Build Coastguard Worker void operator delete(void *, size_t) noexcept;
28*76559068SAndroid Build Coastguard Worker void operator delete[](void *, size_t) noexcept;
29*76559068SAndroid Build Coastguard Worker
30*76559068SAndroid Build Coastguard Worker extern "C" {
31*76559068SAndroid Build Coastguard Worker #ifndef SCUDO_ENABLE_HOOKS_TESTS
32*76559068SAndroid Build Coastguard Worker #define SCUDO_ENABLE_HOOKS_TESTS 0
33*76559068SAndroid Build Coastguard Worker #endif
34*76559068SAndroid Build Coastguard Worker
35*76559068SAndroid Build Coastguard Worker #if (SCUDO_ENABLE_HOOKS_TESTS == 1) && (SCUDO_ENABLE_HOOKS == 0)
36*76559068SAndroid Build Coastguard Worker #error "Hooks tests should have hooks enabled as well!"
37*76559068SAndroid Build Coastguard Worker #endif
38*76559068SAndroid Build Coastguard Worker
39*76559068SAndroid Build Coastguard Worker struct AllocContext {
40*76559068SAndroid Build Coastguard Worker void *Ptr;
41*76559068SAndroid Build Coastguard Worker size_t Size;
42*76559068SAndroid Build Coastguard Worker };
43*76559068SAndroid Build Coastguard Worker struct DeallocContext {
44*76559068SAndroid Build Coastguard Worker void *Ptr;
45*76559068SAndroid Build Coastguard Worker };
46*76559068SAndroid Build Coastguard Worker static AllocContext AC;
47*76559068SAndroid Build Coastguard Worker static DeallocContext DC;
48*76559068SAndroid Build Coastguard Worker
49*76559068SAndroid Build Coastguard Worker #if (SCUDO_ENABLE_HOOKS_TESTS == 1)
__scudo_allocate_hook(void * Ptr,size_t Size)50*76559068SAndroid Build Coastguard Worker __attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr,
51*76559068SAndroid Build Coastguard Worker size_t Size) {
52*76559068SAndroid Build Coastguard Worker AC.Ptr = Ptr;
53*76559068SAndroid Build Coastguard Worker AC.Size = Size;
54*76559068SAndroid Build Coastguard Worker }
__scudo_deallocate_hook(void * Ptr)55*76559068SAndroid Build Coastguard Worker __attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr) {
56*76559068SAndroid Build Coastguard Worker DC.Ptr = Ptr;
57*76559068SAndroid Build Coastguard Worker }
58*76559068SAndroid Build Coastguard Worker #endif // (SCUDO_ENABLE_HOOKS_TESTS == 1)
59*76559068SAndroid Build Coastguard Worker }
60*76559068SAndroid Build Coastguard Worker
61*76559068SAndroid Build Coastguard Worker class ScudoWrappersCppTest : public Test {
62*76559068SAndroid Build Coastguard Worker protected:
SetUp()63*76559068SAndroid Build Coastguard Worker void SetUp() override {
64*76559068SAndroid Build Coastguard Worker if (SCUDO_ENABLE_HOOKS && !SCUDO_ENABLE_HOOKS_TESTS)
65*76559068SAndroid Build Coastguard Worker printf("Hooks are enabled but hooks tests are disabled.\n");
66*76559068SAndroid Build Coastguard Worker }
67*76559068SAndroid Build Coastguard Worker
verifyAllocHookPtr(UNUSED void * Ptr)68*76559068SAndroid Build Coastguard Worker void verifyAllocHookPtr(UNUSED void *Ptr) {
69*76559068SAndroid Build Coastguard Worker if (SCUDO_ENABLE_HOOKS_TESTS)
70*76559068SAndroid Build Coastguard Worker EXPECT_EQ(Ptr, AC.Ptr);
71*76559068SAndroid Build Coastguard Worker }
verifyAllocHookSize(UNUSED size_t Size)72*76559068SAndroid Build Coastguard Worker void verifyAllocHookSize(UNUSED size_t Size) {
73*76559068SAndroid Build Coastguard Worker if (SCUDO_ENABLE_HOOKS_TESTS)
74*76559068SAndroid Build Coastguard Worker EXPECT_EQ(Size, AC.Size);
75*76559068SAndroid Build Coastguard Worker }
verifyDeallocHookPtr(UNUSED void * Ptr)76*76559068SAndroid Build Coastguard Worker void verifyDeallocHookPtr(UNUSED void *Ptr) {
77*76559068SAndroid Build Coastguard Worker if (SCUDO_ENABLE_HOOKS_TESTS)
78*76559068SAndroid Build Coastguard Worker EXPECT_EQ(Ptr, DC.Ptr);
79*76559068SAndroid Build Coastguard Worker }
80*76559068SAndroid Build Coastguard Worker
testCxxNew()81*76559068SAndroid Build Coastguard Worker template <typename T> void testCxxNew() {
82*76559068SAndroid Build Coastguard Worker T *P = new T;
83*76559068SAndroid Build Coastguard Worker EXPECT_NE(P, nullptr);
84*76559068SAndroid Build Coastguard Worker verifyAllocHookPtr(P);
85*76559068SAndroid Build Coastguard Worker verifyAllocHookSize(sizeof(T));
86*76559068SAndroid Build Coastguard Worker memset(P, 0x42, sizeof(T));
87*76559068SAndroid Build Coastguard Worker EXPECT_DEATH(delete[] P, "");
88*76559068SAndroid Build Coastguard Worker delete P;
89*76559068SAndroid Build Coastguard Worker verifyDeallocHookPtr(P);
90*76559068SAndroid Build Coastguard Worker EXPECT_DEATH(delete P, "");
91*76559068SAndroid Build Coastguard Worker
92*76559068SAndroid Build Coastguard Worker P = new T;
93*76559068SAndroid Build Coastguard Worker EXPECT_NE(P, nullptr);
94*76559068SAndroid Build Coastguard Worker memset(P, 0x42, sizeof(T));
95*76559068SAndroid Build Coastguard Worker operator delete(P, sizeof(T));
96*76559068SAndroid Build Coastguard Worker verifyDeallocHookPtr(P);
97*76559068SAndroid Build Coastguard Worker
98*76559068SAndroid Build Coastguard Worker P = new (std::nothrow) T;
99*76559068SAndroid Build Coastguard Worker verifyAllocHookPtr(P);
100*76559068SAndroid Build Coastguard Worker verifyAllocHookSize(sizeof(T));
101*76559068SAndroid Build Coastguard Worker EXPECT_NE(P, nullptr);
102*76559068SAndroid Build Coastguard Worker memset(P, 0x42, sizeof(T));
103*76559068SAndroid Build Coastguard Worker delete P;
104*76559068SAndroid Build Coastguard Worker verifyDeallocHookPtr(P);
105*76559068SAndroid Build Coastguard Worker
106*76559068SAndroid Build Coastguard Worker const size_t N = 16U;
107*76559068SAndroid Build Coastguard Worker T *A = new T[N];
108*76559068SAndroid Build Coastguard Worker EXPECT_NE(A, nullptr);
109*76559068SAndroid Build Coastguard Worker verifyAllocHookPtr(A);
110*76559068SAndroid Build Coastguard Worker verifyAllocHookSize(sizeof(T) * N);
111*76559068SAndroid Build Coastguard Worker memset(A, 0x42, sizeof(T) * N);
112*76559068SAndroid Build Coastguard Worker EXPECT_DEATH(delete A, "");
113*76559068SAndroid Build Coastguard Worker delete[] A;
114*76559068SAndroid Build Coastguard Worker verifyDeallocHookPtr(A);
115*76559068SAndroid Build Coastguard Worker EXPECT_DEATH(delete[] A, "");
116*76559068SAndroid Build Coastguard Worker
117*76559068SAndroid Build Coastguard Worker A = new T[N];
118*76559068SAndroid Build Coastguard Worker EXPECT_NE(A, nullptr);
119*76559068SAndroid Build Coastguard Worker memset(A, 0x42, sizeof(T) * N);
120*76559068SAndroid Build Coastguard Worker operator delete[](A, sizeof(T) * N);
121*76559068SAndroid Build Coastguard Worker verifyDeallocHookPtr(A);
122*76559068SAndroid Build Coastguard Worker
123*76559068SAndroid Build Coastguard Worker A = new (std::nothrow) T[N];
124*76559068SAndroid Build Coastguard Worker verifyAllocHookPtr(A);
125*76559068SAndroid Build Coastguard Worker verifyAllocHookSize(sizeof(T) * N);
126*76559068SAndroid Build Coastguard Worker EXPECT_NE(A, nullptr);
127*76559068SAndroid Build Coastguard Worker memset(A, 0x42, sizeof(T) * N);
128*76559068SAndroid Build Coastguard Worker delete[] A;
129*76559068SAndroid Build Coastguard Worker verifyDeallocHookPtr(A);
130*76559068SAndroid Build Coastguard Worker }
131*76559068SAndroid Build Coastguard Worker };
132*76559068SAndroid Build Coastguard Worker using ScudoWrappersCppDeathTest = ScudoWrappersCppTest;
133*76559068SAndroid Build Coastguard Worker
134*76559068SAndroid Build Coastguard Worker class Pixel {
135*76559068SAndroid Build Coastguard Worker public:
136*76559068SAndroid Build Coastguard Worker enum class Color { Red, Green, Blue };
137*76559068SAndroid Build Coastguard Worker int X = 0;
138*76559068SAndroid Build Coastguard Worker int Y = 0;
139*76559068SAndroid Build Coastguard Worker Color C = Color::Red;
140*76559068SAndroid Build Coastguard Worker };
141*76559068SAndroid Build Coastguard Worker
142*76559068SAndroid Build Coastguard Worker // Note that every Cxx allocation function in the test binary will be fulfilled
143*76559068SAndroid Build Coastguard Worker // by Scudo. See the comment in the C counterpart of this file.
144*76559068SAndroid Build Coastguard Worker
TEST_F(ScudoWrappersCppDeathTest,New)145*76559068SAndroid Build Coastguard Worker TEST_F(ScudoWrappersCppDeathTest, New) {
146*76559068SAndroid Build Coastguard Worker if (getenv("SKIP_TYPE_MISMATCH") || SKIP_MISMATCH_TESTS) {
147*76559068SAndroid Build Coastguard Worker printf("Skipped type mismatch tests.\n");
148*76559068SAndroid Build Coastguard Worker return;
149*76559068SAndroid Build Coastguard Worker }
150*76559068SAndroid Build Coastguard Worker testCxxNew<bool>();
151*76559068SAndroid Build Coastguard Worker testCxxNew<uint8_t>();
152*76559068SAndroid Build Coastguard Worker testCxxNew<uint16_t>();
153*76559068SAndroid Build Coastguard Worker testCxxNew<uint32_t>();
154*76559068SAndroid Build Coastguard Worker testCxxNew<uint64_t>();
155*76559068SAndroid Build Coastguard Worker testCxxNew<float>();
156*76559068SAndroid Build Coastguard Worker testCxxNew<double>();
157*76559068SAndroid Build Coastguard Worker testCxxNew<long double>();
158*76559068SAndroid Build Coastguard Worker testCxxNew<Pixel>();
159*76559068SAndroid Build Coastguard Worker }
160*76559068SAndroid Build Coastguard Worker
161*76559068SAndroid Build Coastguard Worker static std::mutex Mutex;
162*76559068SAndroid Build Coastguard Worker static std::condition_variable Cv;
163*76559068SAndroid Build Coastguard Worker static bool Ready;
164*76559068SAndroid Build Coastguard Worker
stressNew()165*76559068SAndroid Build Coastguard Worker static void stressNew() {
166*76559068SAndroid Build Coastguard Worker std::vector<uintptr_t *> V;
167*76559068SAndroid Build Coastguard Worker {
168*76559068SAndroid Build Coastguard Worker std::unique_lock<std::mutex> Lock(Mutex);
169*76559068SAndroid Build Coastguard Worker while (!Ready)
170*76559068SAndroid Build Coastguard Worker Cv.wait(Lock);
171*76559068SAndroid Build Coastguard Worker }
172*76559068SAndroid Build Coastguard Worker for (size_t I = 0; I < 256U; I++) {
173*76559068SAndroid Build Coastguard Worker const size_t N = static_cast<size_t>(std::rand()) % 128U;
174*76559068SAndroid Build Coastguard Worker uintptr_t *P = new uintptr_t[N];
175*76559068SAndroid Build Coastguard Worker if (P) {
176*76559068SAndroid Build Coastguard Worker memset(P, 0x42, sizeof(uintptr_t) * N);
177*76559068SAndroid Build Coastguard Worker V.push_back(P);
178*76559068SAndroid Build Coastguard Worker }
179*76559068SAndroid Build Coastguard Worker }
180*76559068SAndroid Build Coastguard Worker while (!V.empty()) {
181*76559068SAndroid Build Coastguard Worker delete[] V.back();
182*76559068SAndroid Build Coastguard Worker V.pop_back();
183*76559068SAndroid Build Coastguard Worker }
184*76559068SAndroid Build Coastguard Worker }
185*76559068SAndroid Build Coastguard Worker
TEST_F(ScudoWrappersCppTest,ThreadedNew)186*76559068SAndroid Build Coastguard Worker TEST_F(ScudoWrappersCppTest, ThreadedNew) {
187*76559068SAndroid Build Coastguard Worker // TODO: Investigate why libc sometimes crashes with tag missmatch in
188*76559068SAndroid Build Coastguard Worker // __pthread_clockjoin_ex.
189*76559068SAndroid Build Coastguard Worker std::unique_ptr<scudo::ScopedDisableMemoryTagChecks> NoTags;
190*76559068SAndroid Build Coastguard Worker if (!SCUDO_ANDROID && scudo::archSupportsMemoryTagging() &&
191*76559068SAndroid Build Coastguard Worker scudo::systemSupportsMemoryTagging())
192*76559068SAndroid Build Coastguard Worker NoTags = std::make_unique<scudo::ScopedDisableMemoryTagChecks>();
193*76559068SAndroid Build Coastguard Worker
194*76559068SAndroid Build Coastguard Worker Ready = false;
195*76559068SAndroid Build Coastguard Worker std::thread Threads[32];
196*76559068SAndroid Build Coastguard Worker for (size_t I = 0U; I < sizeof(Threads) / sizeof(Threads[0]); I++)
197*76559068SAndroid Build Coastguard Worker Threads[I] = std::thread(stressNew);
198*76559068SAndroid Build Coastguard Worker {
199*76559068SAndroid Build Coastguard Worker std::unique_lock<std::mutex> Lock(Mutex);
200*76559068SAndroid Build Coastguard Worker Ready = true;
201*76559068SAndroid Build Coastguard Worker Cv.notify_all();
202*76559068SAndroid Build Coastguard Worker }
203*76559068SAndroid Build Coastguard Worker for (auto &T : Threads)
204*76559068SAndroid Build Coastguard Worker T.join();
205*76559068SAndroid Build Coastguard Worker }
206*76559068SAndroid Build Coastguard Worker
207*76559068SAndroid Build Coastguard Worker #if !SCUDO_FUCHSIA
TEST_F(ScudoWrappersCppTest,AllocAfterFork)208*76559068SAndroid Build Coastguard Worker TEST_F(ScudoWrappersCppTest, AllocAfterFork) {
209*76559068SAndroid Build Coastguard Worker // This test can fail flakily when ran as a part of large number of
210*76559068SAndroid Build Coastguard Worker // other tests if the maxmimum number of mappings allowed is low.
211*76559068SAndroid Build Coastguard Worker // We tried to reduce the number of iterations of the loops with
212*76559068SAndroid Build Coastguard Worker // moderate success, so we will now skip this test under those
213*76559068SAndroid Build Coastguard Worker // circumstances.
214*76559068SAndroid Build Coastguard Worker if (SCUDO_LINUX) {
215*76559068SAndroid Build Coastguard Worker long MaxMapCount = 0;
216*76559068SAndroid Build Coastguard Worker // If the file can't be accessed, we proceed with the test.
217*76559068SAndroid Build Coastguard Worker std::ifstream Stream("/proc/sys/vm/max_map_count");
218*76559068SAndroid Build Coastguard Worker if (Stream.good()) {
219*76559068SAndroid Build Coastguard Worker Stream >> MaxMapCount;
220*76559068SAndroid Build Coastguard Worker if (MaxMapCount < 200000)
221*76559068SAndroid Build Coastguard Worker return;
222*76559068SAndroid Build Coastguard Worker }
223*76559068SAndroid Build Coastguard Worker }
224*76559068SAndroid Build Coastguard Worker
225*76559068SAndroid Build Coastguard Worker std::atomic_bool Stop;
226*76559068SAndroid Build Coastguard Worker
227*76559068SAndroid Build Coastguard Worker // Create threads that simply allocate and free different sizes.
228*76559068SAndroid Build Coastguard Worker std::vector<std::thread *> Threads;
229*76559068SAndroid Build Coastguard Worker for (size_t N = 0; N < 5; N++) {
230*76559068SAndroid Build Coastguard Worker std::thread *T = new std::thread([&Stop] {
231*76559068SAndroid Build Coastguard Worker while (!Stop) {
232*76559068SAndroid Build Coastguard Worker for (size_t SizeLog = 3; SizeLog <= 20; SizeLog++) {
233*76559068SAndroid Build Coastguard Worker char *P = new char[1UL << SizeLog];
234*76559068SAndroid Build Coastguard Worker EXPECT_NE(P, nullptr);
235*76559068SAndroid Build Coastguard Worker // Make sure this value is not optimized away.
236*76559068SAndroid Build Coastguard Worker asm volatile("" : : "r,m"(P) : "memory");
237*76559068SAndroid Build Coastguard Worker delete[] P;
238*76559068SAndroid Build Coastguard Worker }
239*76559068SAndroid Build Coastguard Worker }
240*76559068SAndroid Build Coastguard Worker });
241*76559068SAndroid Build Coastguard Worker Threads.push_back(T);
242*76559068SAndroid Build Coastguard Worker }
243*76559068SAndroid Build Coastguard Worker
244*76559068SAndroid Build Coastguard Worker // Create a thread to fork and allocate.
245*76559068SAndroid Build Coastguard Worker for (size_t N = 0; N < 50; N++) {
246*76559068SAndroid Build Coastguard Worker pid_t Pid;
247*76559068SAndroid Build Coastguard Worker if ((Pid = fork()) == 0) {
248*76559068SAndroid Build Coastguard Worker for (size_t SizeLog = 3; SizeLog <= 20; SizeLog++) {
249*76559068SAndroid Build Coastguard Worker char *P = new char[1UL << SizeLog];
250*76559068SAndroid Build Coastguard Worker EXPECT_NE(P, nullptr);
251*76559068SAndroid Build Coastguard Worker // Make sure this value is not optimized away.
252*76559068SAndroid Build Coastguard Worker asm volatile("" : : "r,m"(P) : "memory");
253*76559068SAndroid Build Coastguard Worker // Make sure we can touch all of the allocation.
254*76559068SAndroid Build Coastguard Worker memset(P, 0x32, 1U << SizeLog);
255*76559068SAndroid Build Coastguard Worker // EXPECT_LE(1U << SizeLog, malloc_usable_size(ptr));
256*76559068SAndroid Build Coastguard Worker delete[] P;
257*76559068SAndroid Build Coastguard Worker }
258*76559068SAndroid Build Coastguard Worker _exit(10);
259*76559068SAndroid Build Coastguard Worker }
260*76559068SAndroid Build Coastguard Worker EXPECT_NE(-1, Pid);
261*76559068SAndroid Build Coastguard Worker int Status;
262*76559068SAndroid Build Coastguard Worker EXPECT_EQ(Pid, waitpid(Pid, &Status, 0));
263*76559068SAndroid Build Coastguard Worker EXPECT_FALSE(WIFSIGNALED(Status));
264*76559068SAndroid Build Coastguard Worker EXPECT_EQ(10, WEXITSTATUS(Status));
265*76559068SAndroid Build Coastguard Worker }
266*76559068SAndroid Build Coastguard Worker
267*76559068SAndroid Build Coastguard Worker printf("Waiting for threads to complete\n");
268*76559068SAndroid Build Coastguard Worker Stop = true;
269*76559068SAndroid Build Coastguard Worker for (auto Thread : Threads)
270*76559068SAndroid Build Coastguard Worker Thread->join();
271*76559068SAndroid Build Coastguard Worker Threads.clear();
272*76559068SAndroid Build Coastguard Worker }
273*76559068SAndroid Build Coastguard Worker #endif
274