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