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