blob: 747638b248605ee3a32a440b88ba7bdffa5157ad [file] [log] [blame]
Dynamic Tools Team517193e2019-09-11 14:48:41 +00001//===-- 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
Vitaly Bukab5ac5932021-05-29 17:11:36 -07009#include "memtag.h"
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080010#include "tests/scudo_unit_test.h"
Dynamic Tools Team517193e2019-09-11 14:48:41 +000011
Dynamic Tools Team83eaa512020-01-09 11:43:16 -080012#include <atomic>
Dynamic Tools Team517193e2019-09-11 14:48:41 +000013#include <condition_variable>
Vitaly Bukac4311c72021-06-23 23:52:47 -070014#include <memory>
Dynamic Tools Team517193e2019-09-11 14:48:41 +000015#include <mutex>
16#include <thread>
Dynamic Tools Team09e6d482019-11-26 18:18:14 -080017#include <vector>
Dynamic Tools Team517193e2019-09-11 14:48:41 +000018
19void operator delete(void *, size_t) noexcept;
20void operator delete[](void *, size_t) noexcept;
21
22// Note that every Cxx allocation function in the test binary will be fulfilled
23// by Scudo. See the comment in the C counterpart of this file.
24
Dynamic Tools Team517193e2019-09-11 14:48:41 +000025template <typename T> static void testCxxNew() {
26 T *P = new T;
27 EXPECT_NE(P, nullptr);
28 memset(P, 0x42, sizeof(T));
29 EXPECT_DEATH(delete[] P, "");
30 delete P;
31 EXPECT_DEATH(delete P, "");
32
33 P = new T;
34 EXPECT_NE(P, nullptr);
35 memset(P, 0x42, sizeof(T));
36 operator delete(P, sizeof(T));
37
38 P = new (std::nothrow) T;
39 EXPECT_NE(P, nullptr);
40 memset(P, 0x42, sizeof(T));
41 delete P;
42
43 const size_t N = 16U;
44 T *A = new T[N];
45 EXPECT_NE(A, nullptr);
46 memset(A, 0x42, sizeof(T) * N);
47 EXPECT_DEATH(delete A, "");
48 delete[] A;
49 EXPECT_DEATH(delete[] A, "");
50
51 A = new T[N];
52 EXPECT_NE(A, nullptr);
53 memset(A, 0x42, sizeof(T) * N);
54 operator delete[](A, sizeof(T) * N);
55
56 A = new (std::nothrow) T[N];
57 EXPECT_NE(A, nullptr);
58 memset(A, 0x42, sizeof(T) * N);
59 delete[] A;
60}
61
62class Pixel {
63public:
64 enum class Color { Red, Green, Blue };
65 int X = 0;
66 int Y = 0;
67 Color C = Color::Red;
68};
69
70TEST(ScudoWrappersCppTest, New) {
Mitch Phillips3ae243e2021-05-10 12:19:19 -070071 if (getenv("SKIP_TYPE_MISMATCH")) {
72 printf("Skipped type mismatch tests.\n");
73 return;
74 }
Dynamic Tools Team517193e2019-09-11 14:48:41 +000075 testCxxNew<bool>();
76 testCxxNew<uint8_t>();
77 testCxxNew<uint16_t>();
78 testCxxNew<uint32_t>();
79 testCxxNew<uint64_t>();
80 testCxxNew<float>();
81 testCxxNew<double>();
82 testCxxNew<long double>();
83 testCxxNew<Pixel>();
84}
85
86static std::mutex Mutex;
87static std::condition_variable Cv;
Kostya Kortchinskyc72ca562020-07-27 09:13:42 -070088static bool Ready;
Dynamic Tools Team517193e2019-09-11 14:48:41 +000089
90static void stressNew() {
91 std::vector<uintptr_t *> V;
92 {
93 std::unique_lock<std::mutex> Lock(Mutex);
94 while (!Ready)
95 Cv.wait(Lock);
96 }
97 for (size_t I = 0; I < 256U; I++) {
98 const size_t N = std::rand() % 128U;
99 uintptr_t *P = new uintptr_t[N];
100 if (P) {
101 memset(P, 0x42, sizeof(uintptr_t) * N);
102 V.push_back(P);
103 }
104 }
105 while (!V.empty()) {
106 delete[] V.back();
107 V.pop_back();
108 }
109}
110
111TEST(ScudoWrappersCppTest, ThreadedNew) {
Vitaly Bukab5ac5932021-05-29 17:11:36 -0700112 // TODO: Investigate why libc sometimes crashes with tag missmatch in
113 // __pthread_clockjoin_ex.
Vitaly Bukac4311c72021-06-23 23:52:47 -0700114 std::unique_ptr<scudo::ScopedDisableMemoryTagChecks> NoTags;
Vitaly Bukab5811082021-06-24 00:07:24 -0700115 if (!SCUDO_ANDROID && scudo::archSupportsMemoryTagging() && scudo::systemSupportsMemoryTagging())
Vitaly Bukac4311c72021-06-23 23:52:47 -0700116 NoTags = std::make_unique<scudo::ScopedDisableMemoryTagChecks>();
Vitaly Bukac971fbf2021-06-23 23:58:09 -0700117
Kostya Kortchinskyc72ca562020-07-27 09:13:42 -0700118 Ready = false;
Dynamic Tools Team517193e2019-09-11 14:48:41 +0000119 std::thread Threads[32];
120 for (size_t I = 0U; I < sizeof(Threads) / sizeof(Threads[0]); I++)
121 Threads[I] = std::thread(stressNew);
122 {
123 std::unique_lock<std::mutex> Lock(Mutex);
124 Ready = true;
125 Cv.notify_all();
126 }
127 for (auto &T : Threads)
128 T.join();
129}
Dynamic Tools Team83eaa512020-01-09 11:43:16 -0800130
131#if !SCUDO_FUCHSIA
132// TODO(kostyak): for me, this test fails in a specific configuration when ran
133// by itself with some Scudo or GWP-ASan violation. Other people
134// can't seem to reproduce the failure. Consider skipping this in
135// the event it fails on the upstream bots.
136TEST(ScudoWrappersCppTest, AllocAfterFork) {
137 std::atomic_bool Stop;
138
139 // Create threads that simply allocate and free different sizes.
140 std::vector<std::thread *> Threads;
141 for (size_t N = 0; N < 5; N++) {
142 std::thread *T = new std::thread([&Stop] {
143 while (!Stop) {
144 for (size_t SizeLog = 3; SizeLog <= 21; SizeLog++) {
145 char *P = new char[1UL << SizeLog];
146 EXPECT_NE(P, nullptr);
147 // Make sure this value is not optimized away.
148 asm volatile("" : : "r,m"(P) : "memory");
149 delete[] P;
150 }
151 }
152 });
153 Threads.push_back(T);
154 }
155
156 // Create a thread to fork and allocate.
157 for (size_t N = 0; N < 100; N++) {
158 pid_t Pid;
159 if ((Pid = fork()) == 0) {
160 for (size_t SizeLog = 3; SizeLog <= 21; SizeLog++) {
161 char *P = new char[1UL << SizeLog];
162 EXPECT_NE(P, nullptr);
163 // Make sure this value is not optimized away.
164 asm volatile("" : : "r,m"(P) : "memory");
165 // Make sure we can touch all of the allocation.
166 memset(P, 0x32, 1U << SizeLog);
167 // EXPECT_LE(1U << SizeLog, malloc_usable_size(ptr));
168 delete[] P;
169 }
170 _exit(10);
171 }
172 EXPECT_NE(-1, Pid);
173 int Status;
174 EXPECT_EQ(Pid, waitpid(Pid, &Status, 0));
175 EXPECT_FALSE(WIFSIGNALED(Status));
176 EXPECT_EQ(10, WEXITSTATUS(Status));
177 }
178
179 printf("Waiting for threads to complete\n");
180 Stop = true;
181 for (auto Thread : Threads)
182 Thread->join();
183 Threads.clear();
184}
185#endif