xref: /aosp_15_r20/external/cronet/base/debug/asan_service.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2022 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "base/debug/asan_service.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #if defined(ADDRESS_SANITIZER)
8*6777b538SAndroid Build Coastguard Worker #include <sanitizer/asan_interface.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/debug/task_trace.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/no_destructor.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/process/process.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/process/process_handle.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/strings/stringprintf.h"
15*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
16*6777b538SAndroid Build Coastguard Worker 
17*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
18*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/win/windows_types.h"
20*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_WIN)
21*6777b538SAndroid Build Coastguard Worker 
22*6777b538SAndroid Build Coastguard Worker #if defined(COMPONENT_BUILD) && BUILDFLAG(IS_WIN)
23*6777b538SAndroid Build Coastguard Worker // In component builds on Windows, weak function exported by ASan have the
24*6777b538SAndroid Build Coastguard Worker // `__dll` suffix. ASan itself uses the `alternatename` directive to account for
25*6777b538SAndroid Build Coastguard Worker // that.
26*6777b538SAndroid Build Coastguard Worker #pragma comment(linker,                                                \
27*6777b538SAndroid Build Coastguard Worker                     "/alternatename:__sanitizer_report_error_summary=" \
28*6777b538SAndroid Build Coastguard Worker                     "__sanitizer_report_error_summary__dll")
29*6777b538SAndroid Build Coastguard Worker #pragma comment(linker,                                     \
30*6777b538SAndroid Build Coastguard Worker                 "/alternatename:__sanitizer_set_report_fd=" \
31*6777b538SAndroid Build Coastguard Worker                 "__sanitizer_set_report_fd__dll")
32*6777b538SAndroid Build Coastguard Worker #endif  // defined(COMPONENT_BUILD) && BUILDFLAG(IS_WIN)
33*6777b538SAndroid Build Coastguard Worker 
34*6777b538SAndroid Build Coastguard Worker namespace base {
35*6777b538SAndroid Build Coastguard Worker namespace debug {
36*6777b538SAndroid Build Coastguard Worker 
37*6777b538SAndroid Build Coastguard Worker namespace {
38*6777b538SAndroid Build Coastguard Worker NO_SANITIZE("address")
TaskTraceErrorCallback(const char * error,bool *)39*6777b538SAndroid Build Coastguard Worker void TaskTraceErrorCallback(const char* error, bool*) {
40*6777b538SAndroid Build Coastguard Worker   // Use the sanitizer api to symbolize the task trace, which otherwise might
41*6777b538SAndroid Build Coastguard Worker   // not symbolize properly. This also lets us format the task trace in the
42*6777b538SAndroid Build Coastguard Worker   // same way as the address sanitizer backtraces, which also means that we can
43*6777b538SAndroid Build Coastguard Worker   // get the stack trace symbolized with asan_symbolize.py in the cases where
44*6777b538SAndroid Build Coastguard Worker   // symbolization at runtime fails.
45*6777b538SAndroid Build Coastguard Worker   std::array<const void*, 4> addresses;
46*6777b538SAndroid Build Coastguard Worker   size_t address_count = TaskTrace().GetAddresses(addresses);
47*6777b538SAndroid Build Coastguard Worker 
48*6777b538SAndroid Build Coastguard Worker   AsanService::GetInstance()->Log("Task trace:");
49*6777b538SAndroid Build Coastguard Worker   size_t frame_index = 0;
50*6777b538SAndroid Build Coastguard Worker   for (size_t i = 0; i < std::min(address_count, addresses.size()); ++i) {
51*6777b538SAndroid Build Coastguard Worker     char buffer[4096] = {};
52*6777b538SAndroid Build Coastguard Worker     void* address = const_cast<void*>(addresses[i]);
53*6777b538SAndroid Build Coastguard Worker     __sanitizer_symbolize_pc(address, "%p %F %L", buffer, sizeof(buffer));
54*6777b538SAndroid Build Coastguard Worker     for (char* ptr = buffer; *ptr != 0; ptr += strlen(ptr)) {
55*6777b538SAndroid Build Coastguard Worker       AsanService::GetInstance()->Log("    #%i %s", frame_index++, ptr);
56*6777b538SAndroid Build Coastguard Worker     }
57*6777b538SAndroid Build Coastguard Worker   }
58*6777b538SAndroid Build Coastguard Worker   AsanService::GetInstance()->Log("");
59*6777b538SAndroid Build Coastguard Worker }
60*6777b538SAndroid Build Coastguard Worker }  // namespace
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker // static
63*6777b538SAndroid Build Coastguard Worker NO_SANITIZE("address")
GetInstance()64*6777b538SAndroid Build Coastguard Worker AsanService* AsanService::GetInstance() {
65*6777b538SAndroid Build Coastguard Worker   static NoDestructor<AsanService> instance;
66*6777b538SAndroid Build Coastguard Worker   return instance.get();
67*6777b538SAndroid Build Coastguard Worker }
68*6777b538SAndroid Build Coastguard Worker 
Initialize()69*6777b538SAndroid Build Coastguard Worker void AsanService::Initialize() {
70*6777b538SAndroid Build Coastguard Worker   AutoLock lock(lock_);
71*6777b538SAndroid Build Coastguard Worker   if (!is_initialized_) {
72*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_WIN)
73*6777b538SAndroid Build Coastguard Worker     if (logging::IsLoggingToFileEnabled()) {
74*6777b538SAndroid Build Coastguard Worker       // Sandboxed processes cannot open files but are provided a HANDLE.
75*6777b538SAndroid Build Coastguard Worker       HANDLE log_handle = logging::DuplicateLogFileHandle();
76*6777b538SAndroid Build Coastguard Worker       if (log_handle) {
77*6777b538SAndroid Build Coastguard Worker         // Sanitizer APIs need a HANDLE cast to void*.
78*6777b538SAndroid Build Coastguard Worker         __sanitizer_set_report_fd(reinterpret_cast<void*>(log_handle));
79*6777b538SAndroid Build Coastguard Worker       }
80*6777b538SAndroid Build Coastguard Worker     }
81*6777b538SAndroid Build Coastguard Worker #endif  // BUILDFLAG(IS_WIN)
82*6777b538SAndroid Build Coastguard Worker     __asan_set_error_report_callback(ErrorReportCallback);
83*6777b538SAndroid Build Coastguard Worker     error_callbacks_.push_back(TaskTraceErrorCallback);
84*6777b538SAndroid Build Coastguard Worker     is_initialized_ = true;
85*6777b538SAndroid Build Coastguard Worker   }
86*6777b538SAndroid Build Coastguard Worker }
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker NO_SANITIZE("address")
Log(const char * format,...)89*6777b538SAndroid Build Coastguard Worker void AsanService::Log(const char* format, ...) {
90*6777b538SAndroid Build Coastguard Worker   va_list ap;
91*6777b538SAndroid Build Coastguard Worker   va_start(ap, format);
92*6777b538SAndroid Build Coastguard Worker   auto formatted_message = StringPrintV(format, ap);
93*6777b538SAndroid Build Coastguard Worker   va_end(ap);
94*6777b538SAndroid Build Coastguard Worker 
95*6777b538SAndroid Build Coastguard Worker   // Despite its name, the function just prints the input to the destination
96*6777b538SAndroid Build Coastguard Worker   // configured by ASan.
97*6777b538SAndroid Build Coastguard Worker   __sanitizer_report_error_summary(formatted_message.c_str());
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker 
AddErrorCallback(ErrorCallback error_callback)100*6777b538SAndroid Build Coastguard Worker void AsanService::AddErrorCallback(ErrorCallback error_callback) {
101*6777b538SAndroid Build Coastguard Worker   AutoLock lock(lock_);
102*6777b538SAndroid Build Coastguard Worker   CHECK(is_initialized_);
103*6777b538SAndroid Build Coastguard Worker   error_callbacks_.push_back(error_callback);
104*6777b538SAndroid Build Coastguard Worker }
105*6777b538SAndroid Build Coastguard Worker 
106*6777b538SAndroid Build Coastguard Worker NO_SANITIZE("address")
RunErrorCallbacks(const char * reason)107*6777b538SAndroid Build Coastguard Worker void AsanService::RunErrorCallbacks(const char* reason) {
108*6777b538SAndroid Build Coastguard Worker   ProcessId process_id = GetCurrentProcId();
109*6777b538SAndroid Build Coastguard Worker   bool should_exit_cleanly = false;
110*6777b538SAndroid Build Coastguard Worker 
111*6777b538SAndroid Build Coastguard Worker   {
112*6777b538SAndroid Build Coastguard Worker     // We can hold `lock_` throughout the error callbacks, since ASan doesn't
113*6777b538SAndroid Build Coastguard Worker     // re-enter when handling nested errors on the same thread.
114*6777b538SAndroid Build Coastguard Worker     AutoLock lock(lock_);
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker     Log("\n==%i==ADDITIONAL INFO", (int)process_id);
117*6777b538SAndroid Build Coastguard Worker     Log("\n==%i==Note: Please include this section with the ASan report.",
118*6777b538SAndroid Build Coastguard Worker         (int)process_id);
119*6777b538SAndroid Build Coastguard Worker     for (const auto& error_callback : error_callbacks_) {
120*6777b538SAndroid Build Coastguard Worker       error_callback(reason, &should_exit_cleanly);
121*6777b538SAndroid Build Coastguard Worker     }
122*6777b538SAndroid Build Coastguard Worker     Log("\n==%i==END OF ADDITIONAL INFO", (int)process_id);
123*6777b538SAndroid Build Coastguard Worker   }
124*6777b538SAndroid Build Coastguard Worker 
125*6777b538SAndroid Build Coastguard Worker   if (should_exit_cleanly) {
126*6777b538SAndroid Build Coastguard Worker     Log("\n==%i==EXITING", (int)process_id);
127*6777b538SAndroid Build Coastguard Worker     Process::TerminateCurrentProcessImmediately(0);
128*6777b538SAndroid Build Coastguard Worker   }
129*6777b538SAndroid Build Coastguard Worker }
130*6777b538SAndroid Build Coastguard Worker 
131*6777b538SAndroid Build Coastguard Worker // static
132*6777b538SAndroid Build Coastguard Worker NO_SANITIZE("address")
ErrorReportCallback(const char * reason)133*6777b538SAndroid Build Coastguard Worker void AsanService::ErrorReportCallback(const char* reason) {
134*6777b538SAndroid Build Coastguard Worker   AsanService::GetInstance()->RunErrorCallbacks(reason);
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker 
AsanService()137*6777b538SAndroid Build Coastguard Worker AsanService::AsanService() {}
138*6777b538SAndroid Build Coastguard Worker 
139*6777b538SAndroid Build Coastguard Worker }  // namespace debug
140*6777b538SAndroid Build Coastguard Worker }  // namespace base
141*6777b538SAndroid Build Coastguard Worker 
142*6777b538SAndroid Build Coastguard Worker #endif  // defined(ADDRESS_SANITIZER)
143