• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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