1 // Copyright 2014 The Chromium Authors. All rights reserved.
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/debug/alias.h"
12 #include "base/logging.h"
13 #include "build/build_config.h"
14 
15 #if defined(OS_WIN)
16 #include <windows.h>
17 #endif
18 
19 namespace base {
20 namespace debug {
21 
22 namespace {
23 
24 #if defined(OS_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  // OS_WIN && ADDRESS_SANITIZER
50 
51 }  // namespace
52 
53 #if defined(ADDRESS_SANITIZER)
54 // NOTE(sebmarchand): We intentionally perform some invalid heap access here in
55 //     order to trigger an AddressSanitizer (ASan) error report.
56 
57 static const size_t kArraySize = 5;
58 
AsanHeapOverflow()59 void AsanHeapOverflow() {
60   // Declares the array as volatile to make sure it doesn't get optimized away.
61   std::unique_ptr<volatile int[]> array(
62       const_cast<volatile int*>(new int[kArraySize]));
63   int dummy = array[kArraySize];
64   base::debug::Alias(&dummy);
65 }
66 
AsanHeapUnderflow()67 void AsanHeapUnderflow() {
68   // Declares the array as volatile to make sure it doesn't get optimized away.
69   std::unique_ptr<volatile int[]> array(
70       const_cast<volatile int*>(new int[kArraySize]));
71   // We need to store the underflow address in a temporary variable as trying to
72   // access array[-1] will trigger a warning C4245: "conversion from 'int' to
73   // 'size_t', signed/unsigned mismatch".
74   volatile int* underflow_address = &array[0] - 1;
75   int dummy = *underflow_address;
76   base::debug::Alias(&dummy);
77 }
78 
AsanHeapUseAfterFree()79 void AsanHeapUseAfterFree() {
80   // Declares the array as volatile to make sure it doesn't get optimized away.
81   std::unique_ptr<volatile int[]> array(
82       const_cast<volatile int*>(new int[kArraySize]));
83   volatile int* dangling = array.get();
84   array.reset();
85   int dummy = dangling[kArraySize / 2];
86   base::debug::Alias(&dummy);
87 }
88 
89 #if defined(OS_WIN)
AsanCorruptHeapBlock()90 void AsanCorruptHeapBlock() {
91   CorruptMemoryBlock(false);
92 }
93 
AsanCorruptHeap()94 void AsanCorruptHeap() {
95   CorruptMemoryBlock(true);
96 }
97 #endif  // OS_WIN
98 #endif  // ADDRESS_SANITIZER
99 
100 }  // namespace debug
101 }  // namespace base
102