|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/debug/asan_invalid_access.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/debug/alias.h" | 
|  | #include "base/logging.h" | 
|  | #include "build_config.h" | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | #include <windows.h> | 
|  | #endif | 
|  |  | 
|  | namespace base { | 
|  | namespace debug { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | #if defined(OS_WIN) && defined(ADDRESS_SANITIZER) | 
|  | // Corrupt a memory block and make sure that the corruption gets detected either | 
|  | // when we free it or when another crash happens (if |induce_crash| is set to | 
|  | // true). | 
|  | NOINLINE void CorruptMemoryBlock(bool induce_crash) { | 
|  | // NOTE(sebmarchand): We intentionally corrupt a memory block here in order to | 
|  | //     trigger an Address Sanitizer (ASAN) error report. | 
|  | static const int kArraySize = 5; | 
|  | LONG* array = new LONG[kArraySize]; | 
|  |  | 
|  | // Explicitly call out to a kernel32 function to perform the memory access. | 
|  | // This way the underflow won't be detected but the corruption will (as the | 
|  | // allocator will still be hooked). | 
|  | auto InterlockedIncrementFn = | 
|  | reinterpret_cast<LONG (*)(LONG volatile * addend)>( | 
|  | GetProcAddress(GetModuleHandle(L"kernel32"), "InterlockedIncrement")); | 
|  | CHECK(InterlockedIncrementFn); | 
|  |  | 
|  | LONG volatile dummy = InterlockedIncrementFn(array - 1); | 
|  | base::debug::Alias(const_cast<LONG*>(&dummy)); | 
|  |  | 
|  | if (induce_crash) | 
|  | CHECK(false); | 
|  | delete[] array; | 
|  | } | 
|  | #endif  // OS_WIN && ADDRESS_SANITIZER | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | #if defined(ADDRESS_SANITIZER) | 
|  | // NOTE(sebmarchand): We intentionally perform some invalid heap access here in | 
|  | //     order to trigger an AddressSanitizer (ASan) error report. | 
|  |  | 
|  | static const size_t kArraySize = 5; | 
|  |  | 
|  | void AsanHeapOverflow() { | 
|  | // Declares the array as volatile to make sure it doesn't get optimized away. | 
|  | std::unique_ptr<volatile int[]> array( | 
|  | const_cast<volatile int*>(new int[kArraySize])); | 
|  | int dummy = array[kArraySize]; | 
|  | base::debug::Alias(&dummy); | 
|  | } | 
|  |  | 
|  | void AsanHeapUnderflow() { | 
|  | // Declares the array as volatile to make sure it doesn't get optimized away. | 
|  | std::unique_ptr<volatile int[]> array( | 
|  | const_cast<volatile int*>(new int[kArraySize])); | 
|  | // We need to store the underflow address in a temporary variable as trying to | 
|  | // access array[-1] will trigger a warning C4245: "conversion from 'int' to | 
|  | // 'size_t', signed/unsigned mismatch". | 
|  | volatile int* underflow_address = &array[0] - 1; | 
|  | int dummy = *underflow_address; | 
|  | base::debug::Alias(&dummy); | 
|  | } | 
|  |  | 
|  | void AsanHeapUseAfterFree() { | 
|  | // Declares the array as volatile to make sure it doesn't get optimized away. | 
|  | std::unique_ptr<volatile int[]> array( | 
|  | const_cast<volatile int*>(new int[kArraySize])); | 
|  | volatile int* dangling = array.get(); | 
|  | array.reset(); | 
|  | int dummy = dangling[kArraySize / 2]; | 
|  | base::debug::Alias(&dummy); | 
|  | } | 
|  |  | 
|  | #if defined(OS_WIN) | 
|  | void AsanCorruptHeapBlock() { | 
|  | CorruptMemoryBlock(false); | 
|  | } | 
|  |  | 
|  | void AsanCorruptHeap() { | 
|  | CorruptMemoryBlock(true); | 
|  | } | 
|  | #endif  // OS_WIN | 
|  | #endif  // ADDRESS_SANITIZER | 
|  |  | 
|  | }  // namespace debug | 
|  | }  // namespace base |