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