| // 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 <memory> | |
| #include "starboard/types.h" | |
| #include "base/debug/alias.h" | |
| #include "base/logging.h" | |
| #include "build/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 |