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 134
|
// 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/strings/string_piece.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/1402267): 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() {}
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
|