1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This file contains intentional memory errors, some of which may lead to
6 // crashes if the test is ran without special memory testing tools. We use these
7 // errors to verify the sanity of the tools.
11 #include "base/atomicops.h"
12 #include "base/cfi_buildflags.h"
13 #include "base/debug/asan_invalid_access.h"
14 #include "base/debug/profiler.h"
15 #include "base/logging.h"
16 #include "base/memory/raw_ptr.h"
17 #include "base/sanitizer_buildflags.h"
18 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
19 #include "base/threading/thread.h"
20 #include "build/build_config.h"
21 #include "testing/gtest/include/gtest/gtest.h"
33 const base::subtle::Atomic32 kMagicValue = 42;
35 // Helper for memory accesses that can potentially corrupt memory or cause a
36 // crash during a native run.
37 #if defined(ADDRESS_SANITIZER)
38 #define HARMFUL_ACCESS(action, error_regexp) \
39 EXPECT_DEATH_IF_SUPPORTED(action, error_regexp)
40 #elif BUILDFLAG(IS_HWASAN)
41 #define HARMFUL_ACCESS(action, error_regexp) \
42 EXPECT_DEATH(action, "tag-mismatch")
44 #define HARMFUL_ACCESS(action, error_regexp)
45 #define HARMFUL_ACCESS_IS_NOOP
48 void DoReadUninitializedValue(volatile char *ptr) {
49 // Comparison with 64 is to prevent clang from optimizing away the
50 // jump -- valgrind only catches jumps and conditional moves, but clang uses
51 // the borrow flag if the condition is just `*ptr == '\0'`. We no longer
52 // support valgrind, but this constant should be fine to keep as-is.
54 VLOG(1) << "Uninit condition is true";
56 VLOG(1) << "Uninit condition is false";
60 void ReadUninitializedValue(volatile char *ptr) {
61 #if defined(MEMORY_SANITIZER)
62 EXPECT_DEATH(DoReadUninitializedValue(ptr),
63 "use-of-uninitialized-value");
65 DoReadUninitializedValue(ptr);
69 #ifndef HARMFUL_ACCESS_IS_NOOP
70 void ReadValueOutOfArrayBoundsLeft(char *ptr) {
72 VLOG(1) << "Reading a byte out of bounds: " << c;
75 void ReadValueOutOfArrayBoundsRight(char *ptr, size_t size) {
76 char c = ptr[size + 1];
77 VLOG(1) << "Reading a byte out of bounds: " << c;
80 void WriteValueOutOfArrayBoundsLeft(char *ptr) {
81 ptr[-1] = kMagicValue;
84 void WriteValueOutOfArrayBoundsRight(char *ptr, size_t size) {
85 ptr[size] = kMagicValue;
87 #endif // HARMFUL_ACCESS_IS_NOOP
89 void MakeSomeErrors(char *ptr, size_t size) {
90 ReadUninitializedValue(ptr);
92 HARMFUL_ACCESS(ReadValueOutOfArrayBoundsLeft(ptr), "2 bytes before");
93 HARMFUL_ACCESS(ReadValueOutOfArrayBoundsRight(ptr, size), "1 bytes after");
94 HARMFUL_ACCESS(WriteValueOutOfArrayBoundsLeft(ptr), "1 bytes before");
95 HARMFUL_ACCESS(WriteValueOutOfArrayBoundsRight(ptr, size), "0 bytes after");
100 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
101 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
102 defined(UNDEFINED_SANITIZER)
103 // build/sanitizers/sanitizer_options.cc defines symbols like
104 // __asan_default_options which the sanitizer runtime calls if they exist
105 // in the executable. If they don't, the sanitizer runtime silently uses an
106 // internal default value instead. The build puts the symbol
107 // _sanitizer_options_link_helper (which the sanitizer runtime doesn't know
108 // about, it's a chrome thing) in that file and then tells the linker that
109 // that symbol must exist. This causes sanitizer_options.cc to be part of
110 // our binaries, which in turn makes sure our __asan_default_options are used.
111 // We had problems with __asan_default_options not being used, so this test
112 // verifies that _sanitizer_options_link_helper actually makes it into our
114 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN)
115 // TODO(https://crbug.com/1322143): Sanitizer options are currently broken
117 // TODO(https://crbug.com/1321584): __asan_default_options should be used
118 // on Windows too, but currently isn't.
119 #define MAYBE_LinksSanitizerOptions DISABLED_LinksSanitizerOptions
121 #define MAYBE_LinksSanitizerOptions LinksSanitizerOptions
123 TEST(ToolsSanityTest, MAYBE_LinksSanitizerOptions) {
124 constexpr char kSym[] = "_sanitizer_options_link_helper";
125 #if BUILDFLAG(IS_WIN)
126 auto sym = GetProcAddress(GetModuleHandle(nullptr), kSym);
128 void* sym = dlsym(RTLD_DEFAULT, kSym);
130 EXPECT_TRUE(sym != nullptr);
134 // A memory leak detector should report an error in this test.
135 TEST(ToolsSanityTest, MemoryLeak) {
136 // Without the |volatile|, clang optimizes away the next two lines.
137 int* volatile leak = new int[256]; // Leak some memory intentionally.
138 leak[4] = 1; // Make sure the allocated memory is used.
141 TEST(ToolsSanityTest, AccessesToNewMemory) {
142 char* foo = new char[16];
143 MakeSomeErrors(foo, 16);
146 HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
149 TEST(ToolsSanityTest, AccessesToMallocMemory) {
150 char* foo = reinterpret_cast<char*>(malloc(16));
151 MakeSomeErrors(foo, 16);
154 HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
157 TEST(ToolsSanityTest, AccessesToStack) {
160 ReadUninitializedValue(foo);
161 HARMFUL_ACCESS(ReadValueOutOfArrayBoundsLeft(foo),
162 "underflows this variable");
163 HARMFUL_ACCESS(ReadValueOutOfArrayBoundsRight(foo, 16),
164 "overflows this variable");
165 HARMFUL_ACCESS(WriteValueOutOfArrayBoundsLeft(foo),
166 "underflows this variable");
167 HARMFUL_ACCESS(WriteValueOutOfArrayBoundsRight(foo, 16),
168 "overflows this variable");
171 #if defined(ADDRESS_SANITIZER)
173 // alloc_dealloc_mismatch defaults to
174 // !SANITIZER_MAC && !SANITIZER_WINDOWS && !SANITIZER_ANDROID,
175 // in the sanitizer runtime upstream.
176 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || \
177 BUILDFLAG(IS_FUCHSIA)
178 #define MAYBE_SingleElementDeletedWithBraces \
179 DISABLED_SingleElementDeletedWithBraces
180 #define MAYBE_ArrayDeletedWithoutBraces DISABLED_ArrayDeletedWithoutBraces
182 #define MAYBE_ArrayDeletedWithoutBraces ArrayDeletedWithoutBraces
183 #define MAYBE_SingleElementDeletedWithBraces SingleElementDeletedWithBraces
184 #endif // defined(ADDRESS_SANITIZER)
186 static int* allocateArray() {
187 // Clang warns about the mismatched new[]/delete if they occur in the same
192 // This test may corrupt memory if not compiled with AddressSanitizer.
193 TEST(ToolsSanityTest, MAYBE_ArrayDeletedWithoutBraces) {
194 // Without the |volatile|, clang optimizes away the next two lines.
195 int* volatile foo = allocateArray();
196 HARMFUL_ACCESS(delete foo, "alloc-dealloc-mismatch");
197 // Under ASan the crash happens in the process spawned by HARMFUL_ACCESS,
198 // need to free the memory in the parent.
202 static int* allocateScalar() {
203 // Clang warns about the mismatched new/delete[] if they occur in the same
208 // This test may corrupt memory if not compiled with AddressSanitizer.
209 TEST(ToolsSanityTest, MAYBE_SingleElementDeletedWithBraces) {
210 // Without the |volatile|, clang optimizes away the next two lines.
211 int* volatile foo = allocateScalar();
213 HARMFUL_ACCESS(delete [] foo, "alloc-dealloc-mismatch");
214 // Under ASan the crash happens in the process spawned by HARMFUL_ACCESS,
215 // need to free the memory in the parent.
220 TEST(ToolsSanityTest, DISABLED_AddressSanitizerNullDerefCrashTest) {
221 // Intentionally crash to make sure AddressSanitizer is running.
222 // This test should not be ran on bots.
223 int* volatile zero = NULL;
227 TEST(ToolsSanityTest, DISABLED_AddressSanitizerLocalOOBCrashTest) {
228 // Intentionally crash to make sure AddressSanitizer is instrumenting
229 // the local variables.
230 // This test should not be ran on bots.
232 // Work around the OOB warning reported by Clang.
233 int* volatile access = &array[5];
238 int g_asan_test_global_array[10];
241 TEST(ToolsSanityTest, DISABLED_AddressSanitizerGlobalOOBCrashTest) {
242 // Intentionally crash to make sure AddressSanitizer is instrumenting
243 // the global variables.
244 // This test should not be ran on bots.
246 // Work around the OOB warning reported by Clang.
247 int* volatile access = g_asan_test_global_array - 1;
251 #ifndef HARMFUL_ACCESS_IS_NOOP
252 TEST(ToolsSanityTest, AsanHeapOverflow) {
253 HARMFUL_ACCESS(debug::AsanHeapOverflow(), "after");
256 TEST(ToolsSanityTest, AsanHeapUnderflow) {
257 HARMFUL_ACCESS(debug::AsanHeapUnderflow(), "before");
260 TEST(ToolsSanityTest, AsanHeapUseAfterFree) {
261 HARMFUL_ACCESS(debug::AsanHeapUseAfterFree(), "heap-use-after-free");
264 #if BUILDFLAG(IS_WIN)
265 // The ASAN runtime doesn't detect heap corruption, this needs fixing before
266 // ASAN builds can ship to the wild. See https://crbug.com/818747.
267 TEST(ToolsSanityTest, DISABLED_AsanCorruptHeapBlock) {
268 HARMFUL_ACCESS(debug::AsanCorruptHeapBlock(), "");
271 TEST(ToolsSanityTest, DISABLED_AsanCorruptHeap) {
272 // This test will kill the process by raising an exception, there's no
273 // particular string to look for in the stack trace.
274 EXPECT_DEATH(debug::AsanCorruptHeap(), "");
276 #endif // BUILDFLAG(IS_WIN)
277 #endif // !HARMFUL_ACCESS_IS_NOOP
281 // We use caps here just to ensure that the method name doesn't interfere with
282 // the wildcarded suppressions.
283 class TOOLS_SANITY_TEST_CONCURRENT_THREAD : public PlatformThread::Delegate {
285 explicit TOOLS_SANITY_TEST_CONCURRENT_THREAD(bool *value) : value_(value) {}
286 ~TOOLS_SANITY_TEST_CONCURRENT_THREAD() override = default;
287 void ThreadMain() override {
290 // Sleep for a few milliseconds so the two threads are more likely to live
291 // simultaneously. Otherwise we may miss the report due to mutex
292 // lock/unlock's inside thread creation code in pure-happens-before mode...
293 PlatformThread::Sleep(Milliseconds(100));
296 raw_ptr<bool> value_;
299 class ReleaseStoreThread : public PlatformThread::Delegate {
301 explicit ReleaseStoreThread(base::subtle::Atomic32 *value) : value_(value) {}
302 ~ReleaseStoreThread() override = default;
303 void ThreadMain() override {
304 base::subtle::Release_Store(value_, kMagicValue);
306 // Sleep for a few milliseconds so the two threads are more likely to live
307 // simultaneously. Otherwise we may miss the report due to mutex
308 // lock/unlock's inside thread creation code in pure-happens-before mode...
309 PlatformThread::Sleep(Milliseconds(100));
312 raw_ptr<base::subtle::Atomic32> value_;
315 class AcquireLoadThread : public PlatformThread::Delegate {
317 explicit AcquireLoadThread(base::subtle::Atomic32 *value) : value_(value) {}
318 ~AcquireLoadThread() override = default;
319 void ThreadMain() override {
320 // Wait for the other thread to make Release_Store
321 PlatformThread::Sleep(Milliseconds(100));
322 base::subtle::Acquire_Load(value_);
325 raw_ptr<base::subtle::Atomic32> value_;
328 void RunInParallel(PlatformThread::Delegate *d1, PlatformThread::Delegate *d2) {
329 PlatformThreadHandle a;
330 PlatformThreadHandle b;
331 PlatformThread::Create(0, d1, &a);
332 PlatformThread::Create(0, d2, &b);
333 PlatformThread::Join(a);
334 PlatformThread::Join(b);
337 #if defined(THREAD_SANITIZER)
339 bool *shared = new bool(false);
340 TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(shared), thread2(shared);
341 RunInParallel(&thread1, &thread2);
342 EXPECT_TRUE(*shared);
344 // We're in a death test - crash.
351 #if defined(THREAD_SANITIZER)
352 // A data race detector should report an error in this test.
353 TEST(ToolsSanityTest, DataRace) {
354 // The suppression regexp must match that in base/debug/tsan_suppressions.cc.
355 EXPECT_DEATH(DataRace(), "1 race:base/tools_sanity_unittest.cc");
359 TEST(ToolsSanityTest, AnnotateBenignRace) {
361 ANNOTATE_BENIGN_RACE(&shared, "Intentional race - make sure doesn't show up");
362 TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(&shared), thread2(&shared);
363 RunInParallel(&thread1, &thread2);
367 TEST(ToolsSanityTest, AtomicsAreIgnored) {
368 base::subtle::Atomic32 shared = 0;
369 ReleaseStoreThread thread1(&shared);
370 AcquireLoadThread thread2(&shared);
371 RunInParallel(&thread1, &thread2);
372 EXPECT_EQ(kMagicValue, shared);
375 #if BUILDFLAG(CFI_ENFORCEMENT_TRAP)
376 #if BUILDFLAG(IS_WIN)
377 #define CFI_ERROR_MSG "EXCEPTION_ILLEGAL_INSTRUCTION"
378 #elif BUILDFLAG(IS_ANDROID)
379 // TODO(pcc): Produce proper stack dumps on Android and test for the correct
381 #define CFI_ERROR_MSG "^$"
383 #define CFI_ERROR_MSG "ILL_ILLOPN"
385 #elif BUILDFLAG(CFI_ENFORCEMENT_DIAGNOSTIC)
386 #define CFI_ERROR_MSG "runtime error: control flow integrity check"
387 #endif // BUILDFLAG(CFI_ENFORCEMENT_TRAP || CFI_ENFORCEMENT_DIAGNOSTIC)
389 #if defined(CFI_ERROR_MSG)
393 virtual void f() { n_++; }
400 void f() override { n_--; }
405 void f() override { n_ += 2; }
408 NOINLINE void KillVptrAndCall(A *obj) {
409 *reinterpret_cast<void **>(obj) = 0;
413 TEST(ToolsSanityTest, BadVirtualCallNull) {
416 EXPECT_DEATH({ KillVptrAndCall(&a); KillVptrAndCall(&b); }, CFI_ERROR_MSG);
419 NOINLINE void OverwriteVptrAndCall(B *obj, A *vptr) {
420 *reinterpret_cast<void **>(obj) = *reinterpret_cast<void **>(vptr);
424 TEST(ToolsSanityTest, BadVirtualCallWrongType) {
428 EXPECT_DEATH({ OverwriteVptrAndCall(&b, &a); OverwriteVptrAndCall(&b, &c); },
432 // TODO(pcc): remove CFI_CAST_CHECK, see https://crbug.com/626794.
433 #if BUILDFLAG(CFI_CAST_CHECK)
434 TEST(ToolsSanityTest, BadDerivedCast) {
436 EXPECT_DEATH((void)(B*)&a, CFI_ERROR_MSG);
439 TEST(ToolsSanityTest, BadUnrelatedCast) {
449 EXPECT_DEATH((void)(B*)&a, CFI_ERROR_MSG);
451 #endif // BUILDFLAG(CFI_CAST_CHECK)
453 #endif // CFI_ERROR_MSG
456 #undef HARMFUL_ACCESS
457 #undef HARMFUL_ACCESS_IS_NOOP