xref: /aosp_15_r20/external/cronet/base/debug/asan_service_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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