Add some function to induce ASan crashes.
This will allows to induce ASan crashes in the browser and in the renderer processes, this is really useful when trying to debug an ASan crash (to make sure that the build is really instrumented).
This code add the following crash urls to chrome:
chrome://crash/browser-heap-overflow
chrome://crash/browser-heap-underflow
chrome://crash/browser-use-after-free
chrome://crash/browser-corrupt-heap-block
chrome://crash/browser-corrupt-heap
Those URLs induce a crash in the browser process, while those:
chrome://crash/heap-overflow
chrome://crash/heap-underflow
chrome://crash/use-after-free
chrome://crash/corrupt-heap-block
chrome://crash/corrupt-heap
induce a crash in the renderer process.
We need this because as these process use a different DLL (chrome.dll vs
chrome_child.dll) one of them could be ASan-instrumented while the other one
isn't... So the current code in renderer/ is useless for the browser-only
instrumented builds...
BUG=
Review URL: https://codereview.chromium.org/306753003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277201 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/base.gypi b/base/base.gypi
index 274dc3d..8c603a73 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -130,6 +130,8 @@
'critical_closure_internal_ios.mm',
'debug/alias.cc',
'debug/alias.h',
+ 'debug/asan_invalid_access.cc',
+ 'debug/asan_invalid_access.h',
'debug/crash_logging.cc',
'debug/crash_logging.h',
'debug/debugger.cc',
diff --git a/base/debug/asan_invalid_access.cc b/base/debug/asan_invalid_access.cc
new file mode 100644
index 0000000..ff7788a3
--- /dev/null
+++ b/base/debug/asan_invalid_access.cc
@@ -0,0 +1,94 @@
+// 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.
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/debug/alias.h"
+#include "base/debug/asan_invalid_access.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+#if defined(SYZYASAN)
+// 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;
+ int* array = new int[kArraySize];
+ // Encapsulate the invalid memory access into a try-catch statement to prevent
+ // this function from being instrumented. This way the underflow won't be
+ // detected but the corruption will (as the allocator will still be hooked).
+ try {
+ // Declares the dummy value as volatile to make sure it doesn't get
+ // optimized away.
+ int volatile dummy = array[-1]--;
+ base::debug::Alias(const_cast<int*>(&dummy));
+ } catch (...) {
+ }
+ if (induce_crash)
+ CHECK(false);
+ delete[] array;
+}
+#endif
+
+} // namespace
+
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+// NOTE(sebmarchand): We intentionally perform some invalid heap access here in
+// order to trigger an AddressSanitizer (ASan) error report.
+
+static const int kArraySize = 5;
+
+void AsanHeapOverflow() {
+ scoped_ptr<int[]> array(new int[kArraySize]);
+ // Declares the dummy value as volatile to make sure it doesn't get optimized
+ // away.
+ int volatile dummy = 0;
+ dummy = array[kArraySize];
+ base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+void AsanHeapUnderflow() {
+ scoped_ptr<int[]> array(new int[kArraySize]);
+ // Declares the dummy value as volatile to make sure it doesn't get optimized
+ // away.
+ int volatile dummy = 0;
+ dummy = array[-1];
+ base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+void AsanHeapUseAfterFree() {
+ scoped_ptr<int[]> array(new int[kArraySize]);
+ // Declares the dummy value as volatile to make sure it doesn't get optimized
+ // away.
+ int volatile dummy = 0;
+ int* dangling = array.get();
+ array.reset();
+ dummy = dangling[kArraySize / 2];
+ base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+#endif // ADDRESS_SANITIZER || SYZYASAN
+
+#if defined(SYZYASAN)
+void AsanCorruptHeapBlock() {
+ CorruptMemoryBlock(false);
+}
+
+void AsanCorruptHeap() {
+ CorruptMemoryBlock(true);
+}
+#endif // SYZYASAN
+
+} // namespace debug
+} // namespace base
diff --git a/base/debug/asan_invalid_access.h b/base/debug/asan_invalid_access.h
new file mode 100644
index 0000000..eee7dcbe
--- /dev/null
+++ b/base/debug/asan_invalid_access.h
@@ -0,0 +1,46 @@
+// 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.
+//
+// Defines some functions that intentionally do an invalid memory access in
+// order to trigger an AddressSanitizer (ASan) error report.
+
+#ifndef BASE_DEBUG_ASAN_INVALID_ACCESS_H_
+#define BASE_DEBUG_ASAN_INVALID_ACCESS_H_
+
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace debug {
+
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+
+// Generates an heap buffer overflow.
+NOINLINE void AsanHeapOverflow();
+
+// Generates an heap buffer underflow.
+NOINLINE void AsanHeapUnderflow();
+
+// Generates an use after free.
+NOINLINE void AsanHeapUseAfterFree();
+
+#endif // ADDRESS_SANITIZER || SYZYASAN
+
+// The "corrupt-block" and "corrupt-heap" classes of bugs is specific to
+// SyzyASan.
+#if defined(SYZYASAN)
+
+// Corrupts a memory block and makes sure that the corruption gets detected when
+// we try to free this block.
+NOINLINE void AsanCorruptHeapBlock();
+
+// Corrupts the heap and makes sure that the corruption gets detected when a
+// crash occur.
+NOINLINE void AsanCorruptHeap();
+
+#endif // SYZYASAN
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_ASAN_INVALID_ACCESS_H_
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc
index b1da3e1a..7d4c96e 100644
--- a/base/tools_sanity_unittest.cc
+++ b/base/tools_sanity_unittest.cc
@@ -7,6 +7,8 @@
// errors to verify the sanity of the tools.
#include "base/atomicops.h"
+#include "base/debug/asan_invalid_access.h"
+#include "base/debug/profiler.h"
#include "base/message_loop/message_loop.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread.h"
@@ -24,9 +26,16 @@
#if defined(OS_IOS)
// EXPECT_DEATH is not supported on IOS.
#define HARMFUL_ACCESS(action,error_regexp) do { action; } while (0)
+#elif defined(SYZYASAN)
+// We won't get a meaningful error message because we're not running under the
+// SyzyASan logger, but we can at least make sure that the error has been
+// generated in the SyzyASan runtime.
+#define HARMFUL_ACCESS(action,unused) \
+if (debug::IsBinaryInstrumented()) { EXPECT_DEATH(action, \
+ "AsanRuntime::OnError"); }
#else
#define HARMFUL_ACCESS(action,error_regexp) EXPECT_DEATH(action,error_regexp)
-#endif // !OS_IOS
+#endif // !OS_IOS && !SYZYASAN
#else
#define HARMFUL_ACCESS(action,error_regexp) \
do { if (RunningOnValgrind()) { action; } } while (0)
@@ -162,6 +171,7 @@
}
#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+
TEST(ToolsSanityTest, DISABLED_AddressSanitizerNullDerefCrashTest) {
// Intentionally crash to make sure AddressSanitizer is running.
// This test should not be ran on bots.
@@ -193,7 +203,31 @@
*access = 43;
}
-#endif
+TEST(ToolsSanityTest, AsanHeapOverflow) {
+ HARMFUL_ACCESS(debug::AsanHeapOverflow() ,"to the right");
+}
+
+TEST(ToolsSanityTest, AsanHeapUnderflow) {
+ HARMFUL_ACCESS(debug::AsanHeapUnderflow(), "to the left");
+}
+
+TEST(ToolsSanityTest, AsanHeapUseAfterFree) {
+ HARMFUL_ACCESS(debug::AsanHeapUseAfterFree(), "heap-use-after-free");
+}
+
+#if defined(SYZYASAN)
+TEST(ToolsSanityTest, AsanCorruptHeapBlock) {
+ HARMFUL_ACCESS(debug::AsanCorruptHeapBlock(), "");
+}
+
+TEST(ToolsSanityTest, AsanCorruptHeap) {
+ // This test will kill the process by raising an exception, there's no
+ // particular string to look for in the stack trace.
+ EXPECT_DEATH(debug::AsanCorruptHeap(), "");
+}
+#endif // SYZYASAN
+
+#endif // ADDRESS_SANITIZER || SYZYASAN
namespace {