1 // Copyright 2022 The Chromium Authors
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_service.h"
6
7 #if defined(ADDRESS_SANITIZER)
8
9 #include <map>
10 #include <memory>
11 #include <sstream>
12
13 #include "base/debug/asan_invalid_access.h"
14 #include "base/memory/raw_ref.h"
15 #include "base/run_loop.h"
16 #include "base/test/bind.h"
17 #include "base/test/task_environment.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20
21 // All of the tests require death tests, so there's nothing to build if we're
22 // building for a platform that doesn't support them.
23 #if defined(GTEST_HAS_DEATH_TEST)
24
25 namespace base {
26 namespace debug {
27
28 class AsanServiceTest : public ::testing::Test {
29 protected:
SetUp()30 void SetUp() override { AsanService::GetInstance()->Initialize(); }
31 };
32
ExitedCleanly(int exit_status)33 bool ExitedCleanly(int exit_status) {
34 return exit_status == 0;
35 }
36
37 // TODO(crbug.com/40884672): ASAN death test is not picking up the failure
38 // in the emulator logs. Disabling to keep ASAN queue clear.
39 #if BUILDFLAG(IS_FUCHSIA)
40 #define MAYBE_ErrorCallback DISABLED_ErrorCallback
41 #define MAYBE_CrashInErrorCallback DISABLED_CrashInErrorCallback
42 #define MAYBE_ShouldExitCleanly DISABLED_ShouldExitCleanly
43 #define MAYBE_TaskTraceCallback DISABLED_TaskTraceCallback
44 #else
45 #define MAYBE_ErrorCallback ErrorCallback
46 #define MAYBE_CrashInErrorCallback CrashInErrorCallback
47 #define MAYBE_ShouldExitCleanly ShouldExitCleanly
48 #define MAYBE_TaskTraceCallback TaskTraceCallback
49 #endif
50
TEST_F(AsanServiceTest,MAYBE_ErrorCallback)51 TEST_F(AsanServiceTest, MAYBE_ErrorCallback) {
52 // Register an error callback, and check that the output is added.
53 AsanService::GetInstance()->AddErrorCallback([](const char*, bool*) {
54 AsanService::GetInstance()->Log("\nErrorCallback1");
55 });
56 EXPECT_DEATH(AsanHeapUseAfterFree(), "ErrorCallback1");
57
58 // Register a second error callback, and check that the output from both
59 // callbacks is added.
60 AsanService::GetInstance()->AddErrorCallback([](const char*, bool*) {
61 AsanService::GetInstance()->Log("\nErrorCallback2");
62 });
63 EXPECT_DEATH(AsanHeapUseAfterFree(), "ErrorCallback1");
64 EXPECT_DEATH(AsanHeapUseAfterFree(), "ErrorCallback2");
65 }
66
TEST_F(AsanServiceTest,MAYBE_CrashInErrorCallback)67 TEST_F(AsanServiceTest, MAYBE_CrashInErrorCallback) {
68 // If a nested fault happens, we don't expect to get our custom log messages
69 // displayed, but we should still get some part of the ASan report. This
70 // matches current ASan recursive fault handling - make sure we don't end up
71 // deadlocking.
72 AsanService::GetInstance()->AddErrorCallback([](const char*, bool*) {
73 AsanService::GetInstance()->Log("\nErrorCallback1");
74 AsanHeapUseAfterFree();
75 });
76 EXPECT_DEATH(AsanHeapUseAfterFree(),
77 "AddressSanitizer: nested bug in the same thread");
78 }
79
TEST_F(AsanServiceTest,MAYBE_ShouldExitCleanly)80 TEST_F(AsanServiceTest, MAYBE_ShouldExitCleanly) {
81 // Register an error callback, and check that the output is added.
82 AsanService::GetInstance()->AddErrorCallback([](const char*, bool*) {
83 AsanService::GetInstance()->Log("\nErrorCallback1");
84 });
85 EXPECT_DEATH(AsanHeapUseAfterFree(), "ErrorCallback1");
86 EXPECT_DEATH(AsanHeapUseAfterFree(), "ABORTING");
87
88 // Register a second error callback which will set should_exit_cleanly.
89 AsanService::GetInstance()->AddErrorCallback(
90 [](const char* reason, bool* should_exit_cleanly) {
91 AsanService::GetInstance()->Log("\nShouldExitCleanly");
92 *should_exit_cleanly = true;
93 });
94
95 // Check that we now exit instead of crashing.
96 EXPECT_EXIT(AsanHeapUseAfterFree(), ExitedCleanly, "ErrorCallback1");
97 EXPECT_EXIT(AsanHeapUseAfterFree(), ExitedCleanly, "ShouldExitCleanly");
98 EXPECT_EXIT(AsanHeapUseAfterFree(), ExitedCleanly, "EXITING");
99 }
100
101 class AsanTaskTraceTest {
102 public:
103 AsanTaskTraceTest() = default;
104
Run()105 void Run() {
106 task_runner_->PostTask(
107 FROM_HERE, BindOnce(&AsanTaskTraceTest::PostingTask, Unretained(this)));
108 task_environment_.RunUntilIdle();
109 }
110
111 private:
PostingTask()112 void PostingTask() {
113 task_runner_->PostTask(FROM_HERE, BindOnce(&AsanHeapUseAfterFree));
114 }
115
116 test::TaskEnvironment task_environment_;
117 const raw_ref<SingleThreadTaskRunner> task_runner_{
118 *task_environment_.GetMainThreadTaskRunner()};
119 };
120
TEST_F(AsanServiceTest,MAYBE_TaskTraceCallback)121 TEST_F(AsanServiceTest, MAYBE_TaskTraceCallback) {
122 AsanTaskTraceTest test;
123 // We can't check the symbolization of the task trace, as this will fail on
124 // build configurations that don't include symbols. We instead just check
125 // that the task trace has the correct number of entries.
126 EXPECT_DEATH(test.Run(), "#0 0x.* .*\\n\\s+#1 0x.*");
127 }
128
129 } // namespace debug
130 } // namespace base
131
132 #endif // defined(GTEST_HAS_DEATH_TEST)
133 #endif // ADDRESS_SANITIZER
134