• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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)34 NOINLINE 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()69 void 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()77 void 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()89 void 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()100 void AsanCorruptHeapBlock() {
101   CorruptMemoryBlock(false);
102 }
103 
AsanCorruptHeap()104 void AsanCorruptHeap() {
105   CorruptMemoryBlock(true);
106 }
107 #endif  // BUILDFLAG(IS_WIN)
108 #endif  // ADDRESS_SANITIZER
109 
110 }  // namespace debug
111 }  // namespace base
112