1 // Copyright 2014 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. 4 5 #include "base/debug/asan_invalid_access.h" 6 7 #include <stddef.h> 8 9 #include <memory> 10 11 #include "base/check.h" 12 #include "base/debug/alias.h" 13 #include "build/build_config.h" 14 15 #if BUILDFLAG(IS_WIN) 16 #include <windows.h> 17 #endif 18 19 namespace base { 20 namespace debug { 21 22 namespace { 23 24 #if BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER) 25 // Corrupt a memory block and make sure that the corruption gets detected either 26 // when we free it or when another crash happens (if |induce_crash| is set to 27 // true). CorruptMemoryBlock(bool induce_crash)28NOINLINE void CorruptMemoryBlock(bool induce_crash) { 29 // NOTE(sebmarchand): We intentionally corrupt a memory block here in order to 30 // trigger an Address Sanitizer (ASAN) error report. 31 static const int kArraySize = 5; 32 LONG* array = new LONG[kArraySize]; 33 34 // Explicitly call out to a kernel32 function to perform the memory access. 35 // This way the underflow won't be detected but the corruption will (as the 36 // allocator will still be hooked). 37 auto InterlockedIncrementFn = 38 reinterpret_cast<LONG (*)(LONG volatile * addend)>( 39 GetProcAddress(GetModuleHandle(L"kernel32"), "InterlockedIncrement")); 40 CHECK(InterlockedIncrementFn); 41 42 LONG volatile dummy = InterlockedIncrementFn(array - 1); 43 base::debug::Alias(const_cast<LONG*>(&dummy)); 44 45 if (induce_crash) 46 CHECK(false); 47 delete[] array; 48 } 49 #endif // BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER) 50 51 } // namespace 52 53 #if defined(ADDRESS_SANITIZER) || BUILDFLAG(IS_HWASAN) 54 // NOTE(sebmarchand): We intentionally perform some invalid heap access here in 55 // order to trigger an AddressSanitizer (ASan) error report. 56 57 // This variable is used to size an array of ints. It needs to be a multiple of 58 // 4 so that off-by-one overflows are detected by HWASan, which has a shadow 59 // granularity of 16 bytes. 60 static const size_t kArraySize = 4; 61 AsanHeapOverflow()62void AsanHeapOverflow() { 63 // Declares the array as volatile to make sure it doesn't get optimized away. 64 std::unique_ptr<volatile int[]> array( 65 const_cast<volatile int*>(new int[kArraySize])); 66 int dummy = array[kArraySize]; 67 base::debug::Alias(&dummy); 68 } 69 AsanHeapUnderflow()70void AsanHeapUnderflow() { 71 // Declares the array as volatile to make sure it doesn't get optimized away. 72 std::unique_ptr<volatile int[]> array( 73 const_cast<volatile int*>(new int[kArraySize])); 74 // We need to store the underflow address in a temporary variable as trying to 75 // access array[-1] will trigger a warning C4245: "conversion from 'int' to 76 // 'size_t', signed/unsigned mismatch". 77 volatile int* underflow_address = &array[0] - 1; 78 int dummy = *underflow_address; 79 base::debug::Alias(&dummy); 80 } 81 AsanHeapUseAfterFree()82void AsanHeapUseAfterFree() { 83 // Declares the array as volatile to make sure it doesn't get optimized away. 84 std::unique_ptr<volatile int[]> array( 85 const_cast<volatile int*>(new int[kArraySize])); 86 volatile int* dangling = array.get(); 87 array.reset(); 88 int dummy = dangling[kArraySize / 2]; 89 base::debug::Alias(&dummy); 90 } 91 92 #if BUILDFLAG(IS_WIN) AsanCorruptHeapBlock()93void AsanCorruptHeapBlock() { 94 CorruptMemoryBlock(false); 95 } 96 AsanCorruptHeap()97void AsanCorruptHeap() { 98 CorruptMemoryBlock(true); 99 } 100 #endif // BUILDFLAG(IS_WIN) 101 #endif // ADDRESS_SANITIZER 102 103 } // namespace debug 104 } // namespace base 105