xref: /aosp_15_r20/external/cronet/base/debug/asan_invalid_access.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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)28 NOINLINE 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()62 void 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()70 void 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()82 void 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()93 void AsanCorruptHeapBlock() {
94   CorruptMemoryBlock(false);
95 }
96 
AsanCorruptHeap()97 void AsanCorruptHeap() {
98   CorruptMemoryBlock(true);
99 }
100 #endif  // BUILDFLAG(IS_WIN)
101 #endif  // ADDRESS_SANITIZER
102 
103 }  // namespace debug
104 }  // namespace base
105