1 //===-- wrappers_cpp_test.cpp -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 #include "tests/scudo_unit_test.h"
13 #include <condition_variable>
20 // Android does not support checking for new/delete mismatches.
22 #define SKIP_MISMATCH_TESTS 1
24 #define SKIP_MISMATCH_TESTS 0
27 void operator delete(void *, size_t) noexcept
;
28 void operator delete[](void *, size_t) noexcept
;
31 #ifndef SCUDO_ENABLE_HOOKS_TESTS
32 #define SCUDO_ENABLE_HOOKS_TESTS 0
35 #if (SCUDO_ENABLE_HOOKS_TESTS == 1) && (SCUDO_ENABLE_HOOKS == 0)
36 #error "Hooks tests should have hooks enabled as well!"
43 struct DeallocContext
{
46 static AllocContext AC
;
47 static DeallocContext DC
;
49 #if (SCUDO_ENABLE_HOOKS_TESTS == 1)
50 __attribute__((visibility("default"))) void __scudo_allocate_hook(void *Ptr
,
55 __attribute__((visibility("default"))) void __scudo_deallocate_hook(void *Ptr
) {
58 #endif // (SCUDO_ENABLE_HOOKS_TESTS == 1)
61 class ScudoWrappersCppTest
: public Test
{
63 void SetUp() override
{
64 if (SCUDO_ENABLE_HOOKS
&& !SCUDO_ENABLE_HOOKS_TESTS
)
65 printf("Hooks are enabled but hooks tests are disabled.\n");
68 void verifyAllocHookPtr(UNUSED
void *Ptr
) {
69 if (SCUDO_ENABLE_HOOKS_TESTS
)
70 EXPECT_EQ(Ptr
, AC
.Ptr
);
72 void verifyAllocHookSize(UNUSED
size_t Size
) {
73 if (SCUDO_ENABLE_HOOKS_TESTS
)
74 EXPECT_EQ(Size
, AC
.Size
);
76 void verifyDeallocHookPtr(UNUSED
void *Ptr
) {
77 if (SCUDO_ENABLE_HOOKS_TESTS
)
78 EXPECT_EQ(Ptr
, DC
.Ptr
);
81 template <typename T
> void testCxxNew() {
83 EXPECT_NE(P
, nullptr);
84 verifyAllocHookPtr(P
);
85 verifyAllocHookSize(sizeof(T
));
86 memset(P
, 0x42, sizeof(T
));
87 EXPECT_DEATH(delete[] P
, "");
89 verifyDeallocHookPtr(P
);
90 EXPECT_DEATH(delete P
, "");
93 EXPECT_NE(P
, nullptr);
94 memset(P
, 0x42, sizeof(T
));
95 operator delete(P
, sizeof(T
));
96 verifyDeallocHookPtr(P
);
98 P
= new (std::nothrow
) T
;
99 verifyAllocHookPtr(P
);
100 verifyAllocHookSize(sizeof(T
));
101 EXPECT_NE(P
, nullptr);
102 memset(P
, 0x42, sizeof(T
));
104 verifyDeallocHookPtr(P
);
106 const size_t N
= 16U;
108 EXPECT_NE(A
, nullptr);
109 verifyAllocHookPtr(A
);
110 verifyAllocHookSize(sizeof(T
) * N
);
111 memset(A
, 0x42, sizeof(T
) * N
);
112 EXPECT_DEATH(delete A
, "");
114 verifyDeallocHookPtr(A
);
115 EXPECT_DEATH(delete[] A
, "");
118 EXPECT_NE(A
, nullptr);
119 memset(A
, 0x42, sizeof(T
) * N
);
120 operator delete[](A
, sizeof(T
) * N
);
121 verifyDeallocHookPtr(A
);
123 A
= new (std::nothrow
) T
[N
];
124 verifyAllocHookPtr(A
);
125 verifyAllocHookSize(sizeof(T
) * N
);
126 EXPECT_NE(A
, nullptr);
127 memset(A
, 0x42, sizeof(T
) * N
);
129 verifyDeallocHookPtr(A
);
132 using ScudoWrappersCppDeathTest
= ScudoWrappersCppTest
;
136 enum class Color
{ Red
, Green
, Blue
};
139 Color C
= Color::Red
;
142 // Note that every Cxx allocation function in the test binary will be fulfilled
143 // by Scudo. See the comment in the C counterpart of this file.
145 TEST_F(ScudoWrappersCppDeathTest
, New
) {
146 if (getenv("SKIP_TYPE_MISMATCH") || SKIP_MISMATCH_TESTS
) {
147 printf("Skipped type mismatch tests.\n");
151 testCxxNew
<uint8_t>();
152 testCxxNew
<uint16_t>();
153 testCxxNew
<uint32_t>();
154 testCxxNew
<uint64_t>();
156 testCxxNew
<double>();
157 testCxxNew
<long double>();
161 static std::mutex Mutex
;
162 static std::condition_variable Cv
;
165 static void stressNew() {
166 std::vector
<uintptr_t *> V
;
168 std::unique_lock
<std::mutex
> Lock(Mutex
);
172 for (size_t I
= 0; I
< 256U; I
++) {
173 const size_t N
= static_cast<size_t>(std::rand()) % 128U;
174 uintptr_t *P
= new uintptr_t[N
];
176 memset(P
, 0x42, sizeof(uintptr_t) * N
);
186 TEST_F(ScudoWrappersCppTest
, ThreadedNew
) {
187 // TODO: Investigate why libc sometimes crashes with tag missmatch in
188 // __pthread_clockjoin_ex.
189 std::unique_ptr
<scudo::ScopedDisableMemoryTagChecks
> NoTags
;
190 if (!SCUDO_ANDROID
&& scudo::archSupportsMemoryTagging() &&
191 scudo::systemSupportsMemoryTagging())
192 NoTags
= std::make_unique
<scudo::ScopedDisableMemoryTagChecks
>();
195 std::thread Threads
[32];
196 for (size_t I
= 0U; I
< sizeof(Threads
) / sizeof(Threads
[0]); I
++)
197 Threads
[I
] = std::thread(stressNew
);
199 std::unique_lock
<std::mutex
> Lock(Mutex
);
203 for (auto &T
: Threads
)
208 TEST_F(ScudoWrappersCppTest
, AllocAfterFork
) {
209 // This test can fail flakily when ran as a part of large number of
210 // other tests if the maxmimum number of mappings allowed is low.
211 // We tried to reduce the number of iterations of the loops with
212 // moderate success, so we will now skip this test under those
215 long MaxMapCount
= 0;
216 // If the file can't be accessed, we proceed with the test.
217 std::ifstream
Stream("/proc/sys/vm/max_map_count");
219 Stream
>> MaxMapCount
;
220 if (MaxMapCount
< 200000)
225 std::atomic_bool Stop
;
227 // Create threads that simply allocate and free different sizes.
228 std::vector
<std::thread
*> Threads
;
229 for (size_t N
= 0; N
< 5; N
++) {
230 std::thread
*T
= new std::thread([&Stop
] {
232 for (size_t SizeLog
= 3; SizeLog
<= 20; SizeLog
++) {
233 char *P
= new char[1UL << SizeLog
];
234 EXPECT_NE(P
, nullptr);
235 // Make sure this value is not optimized away.
236 asm volatile("" : : "r,m"(P
) : "memory");
241 Threads
.push_back(T
);
244 // Create a thread to fork and allocate.
245 for (size_t N
= 0; N
< 50; N
++) {
247 if ((Pid
= fork()) == 0) {
248 for (size_t SizeLog
= 3; SizeLog
<= 20; SizeLog
++) {
249 char *P
= new char[1UL << SizeLog
];
250 EXPECT_NE(P
, nullptr);
251 // Make sure this value is not optimized away.
252 asm volatile("" : : "r,m"(P
) : "memory");
253 // Make sure we can touch all of the allocation.
254 memset(P
, 0x32, 1U << SizeLog
);
255 // EXPECT_LE(1U << SizeLog, malloc_usable_size(ptr));
262 EXPECT_EQ(Pid
, waitpid(Pid
, &Status
, 0));
263 EXPECT_FALSE(WIFSIGNALED(Status
));
264 EXPECT_EQ(10, WEXITSTATUS(Status
));
267 printf("Waiting for threads to complete\n");
269 for (auto Thread
: Threads
)