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#if defined(OS_WIN)
6#include <windows.h>
7#endif
8
9#include "base/debug/alias.h"
10#include "base/debug/asan_invalid_access.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13
14namespace base {
15namespace debug {
16
17namespace {
18
19#if defined(SYZYASAN) && defined(COMPILER_MSVC)
20// Disable warning C4530: "C++ exception handler used, but unwind semantics are
21// not enabled". We don't want to change the compilation flags just for this
22// test, and no exception should be triggered here, so this warning has no value
23// here.
24#pragma warning(push)
25#pragma warning(disable: 4530)
26// Corrupt a memory block and make sure that the corruption gets detected either
27// when we free it or when another crash happens (if |induce_crash| is set to
28// true).
29NOINLINE void CorruptMemoryBlock(bool induce_crash) {
30  // NOTE(sebmarchand): We intentionally corrupt a memory block here in order to
31  //     trigger an Address Sanitizer (ASAN) error report.
32  static const int kArraySize = 5;
33  int* array = new int[kArraySize];
34  // Encapsulate the invalid memory access into a try-catch statement to prevent
35  // this function from being instrumented. This way the underflow won't be
36  // detected but the corruption will (as the allocator will still be hooked).
37  try {
38    // Declares the dummy value as volatile to make sure it doesn't get
39    // optimized away.
40    int volatile dummy = array[-1]--;
41    base::debug::Alias(const_cast<int*>(&dummy));
42  } catch (...) {
43  }
44  if (induce_crash)
45    CHECK(false);
46  delete[] array;
47}
48#pragma warning(pop)
49#endif  // SYZYASAN && COMPILER_MSVC
50
51}  // namespace
52
53#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
54// NOTE(sebmarchand): We intentionally perform some invalid heap access here in
55//     order to trigger an AddressSanitizer (ASan) error report.
56
57static const size_t kArraySize = 5;
58
59void AsanHeapOverflow() {
60  scoped_ptr<int[]> array(new int[kArraySize]);
61  // Declares the dummy value as volatile to make sure it doesn't get optimized
62  // away.
63  int volatile dummy = 0;
64  dummy = array[kArraySize];
65  base::debug::Alias(const_cast<int*>(&dummy));
66}
67
68void AsanHeapUnderflow() {
69  scoped_ptr<int[]> array(new int[kArraySize]);
70  // Declares the dummy value as volatile to make sure it doesn't get optimized
71  // away.
72  int volatile dummy = 0;
73  // We need to store the underflow address in a temporary variable as trying to
74  // access array[-1] will trigger a warning C4245: "conversion from 'int' to
75  // 'size_t', signed/unsigned mismatch".
76  int* underflow_address = &array[0] - 1;
77  dummy = *underflow_address;
78  base::debug::Alias(const_cast<int*>(&dummy));
79}
80
81void AsanHeapUseAfterFree() {
82  scoped_ptr<int[]> array(new int[kArraySize]);
83  // Declares the dummy value as volatile to make sure it doesn't get optimized
84  // away.
85  int volatile dummy = 0;
86  int* dangling = array.get();
87  array.reset();
88  dummy = dangling[kArraySize / 2];
89  base::debug::Alias(const_cast<int*>(&dummy));
90}
91
92#endif  // ADDRESS_SANITIZER || SYZYASAN
93
94#if defined(SYZYASAN) && defined(COMPILER_MSVC)
95void AsanCorruptHeapBlock() {
96  CorruptMemoryBlock(false);
97}
98
99void AsanCorruptHeap() {
100  CorruptMemoryBlock(true);
101}
102#endif  // SYZYASAN && COMPILER_MSVC
103
104}  // namespace debug
105}  // namespace base
106