我们有一个问题,当程序在lldb下运行时,初始化Google Breakpad异常处理程序出错,但从shell正常运行时却没有。
系统为MacOS 13 (Ventura), IDE为Visual Studio Code。
下面的代码在调用init()
时失败:
namespace crashhandler {
static std::unique_ptr<google_breakpad::ExceptionHandler> pExceptionHandler;
namespace {
bool DumpCallback(const char* dump_dir, const char* minidump_id, void*, bool success) {
if (success)
printf("Application crashed. Breakpad Crash Handler created a dump at location %s/%s.dmpn",
dump_dir, minidump_id);
else
printf("Application crashed. Breakpad Crash Handler failed to create a dump");
fflush(stdout);
return success;
}
} // namespace
void init(const std::string& reportPath) // <-- crash happens when calling this function
{
if (pExceptionHandler)
return;
pExceptionHandler.reset(
new google_breakpad::ExceptionHandler(reportPath, nullptr, DumpCallback, nullptr, true, nullptr));
}
} // namespace crashhandler
调试控制台显示:
=================================================================
==5060==ERROR: AddressSanitizer: stack-buffer-underflow on address 0x00016fdfee00 at pc 0x000100ac9030 bp 0x00016ff11540 sp 0x00016ff10d08
READ of size 4608 at 0x00016fdfee00 thread T2
#0 0x100ac902c in wrap_write+0x15c (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1902c)
#1 0x100109f08 in google_breakpad::UntypedMDRVA::Copy(unsigned int, void const*, unsigned long)+0x54 (my_server:arm64+0x100109f08)
#2 0x10010ce14 in google_breakpad::MinidumpGenerator::WriteStackFromStartAddress(unsigned long long, MDMemoryDescriptor*)+0xf8 (my_server:arm64+0x10010ce14)
#3 0x10010d244 in google_breakpad::MinidumpGenerator::WriteThreadStream(unsigned int, MDRawThread*)+0x100 (my_server:arm64+0x10010d244)
#4 0x10010c04c in google_breakpad::MinidumpGenerator::WriteThreadListStream(MDRawDirectory*)+0xfc (my_server:arm64+0x10010c04c)
#5 0x10010bd20 in google_breakpad::MinidumpGenerator::Write(char const*)+0xc8 (my_server:arm64+0x10010bd20)
#6 0x10010adc0 in google_breakpad::ExceptionHandler::WriteMinidumpWithException(int, int, int, __darwin_ucontext64*, unsigned int, bool, bool)+0x160 (my_server:arm64+0x10010adc0)
#7 0x10010af1c in google_breakpad::ExceptionHandler::WaitForMessage(void*)+0x104 (my_server:arm64+0x10010af1c)
#8 0x1a330a068 in _pthread_start+0x90 (libsystem_pthread.dylib:arm64e+0x7068)
#9 0x1a3304e28 in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1e28)
Address 0x00016fdfee00 is located in stack of thread T0 at offset 0 in frame
#0 0x1000034cc in main main.cpp:36
This frame has 10 object(s):
[32, 56) 'reportPath' (line 39) <== Memory access at offset 0 partially underflows this variable
[96, 120) 'ref.tmp' (line 40) <== Memory access at offset 0 partially underflows this variable
[160, 208) 'parser' (line 43) <== Memory access at offset 0 partially underflows this variable
[240, 264) 'configPath' (line 45) <== Memory access at offset 0 partially underflows this variable
[304, 320) 'ref.tmp12' (line 46) <== Memory access at offset 0 partially underflows this variable
[336, 360) 'agg.tmp' <== Memory access at offset 0 partially underflows this variable
[400, 416) 'ref.tmp30' (line 57) <== Memory access at offset 0 partially underflows this variable
[432, 456) 'agg.tmp42' <== Memory access at offset 0 partially underflows this variable
[496, 520) 'agg.tmp80' <== Memory access at offset 0 partially underflows this variable
[560, 568) 'ref.tmp86' (line 74) <== Memory access at offset 0 partially underflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
(longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-underflow (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x1902c) in wrap_write+0x15c
Shadow bytes around the buggy address:
0x00702dfdfd70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702dfdfd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702dfdfd90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702dfdfda0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x00702dfdfdb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x00702dfdfdc0:[f1]f1 f1 f1 00 00 00 f2 f2 f2 f2 f2 f8 f8 f8 f2
0x00702dfdfdd0: f2 f2 f2 f2 f8 f8 f8 f8 f8 f8 f2 f2 f2 f2 f8 f8
0x00702dfdfde0: f8 f2 f2 f2 f2 f2 f8 f8 f2 f2 00 00 00 f2 f2 f2
0x00702dfdfdf0: f2 f2 f8 f8 f2 f2 00 00 00 f2 f2 f2 f2 f2 00 00
0x00702dfdfe00: 00 f2 f2 f2 f2 f2 f8 f3 f3 f3 f3 f3 00 00 00 00
0x00702dfdfe10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Thread T2 created by T0 here:
#0 0x100ae8c5c in wrap_pthread_create+0x54 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x38c5c)
#1 0x10010a360 in google_breakpad::ExceptionHandler::Setup(bool)+0xd0 (my_server:arm64+0x10010a360)
#2 0x10010a1c4 in google_breakpad::ExceptionHandler::ExceptionHandler(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, bool (*)(void*), bool (*)(char const*, char const*, void*, bool), void*, bool, char const*)+0x110 (my_server:arm64+0x10010a1c4)
#3 0x1001132b4 in crashhandler::init(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)+0x58 (my_server:arm64+0x1001132b4)
#4 0x10000367c in main main.cpp:41
#5 0x1a2fdfe4c (<unknown module>)
==5060==ABORTING
重申一下,如果我在调试器之外运行程序,它会正常运行。
是什么原因导致的?
Breakpad正在向进程的"任务异常端口"中插入一个权限。-这是你从进程内部或外部监听崩溃之类的地方-即当你是调试器时。但是在Mach中,异常端口只有一个所有者。因此,当您在调试器下运行时,Breakpad和调试器会争夺对异常端口的控制。例如,如果您在附加调试器之前设置了端口权限,那么在附加调试器之后,您将得到一个错误的端口,因为lldb现在拥有该端口。
调试使用任务异常端口处理程序的程序不被很好地支持,因为(a)它将是棘手的得到正确的,(b)没有足够的程序需要这样做来激励努力(至少在调试器端)。大多数人在调试构建时关闭异常处理,因为他们的异常捕获器和调试器几乎在做相同的工作,并且在调试器中捕获比在内部异常处理程序中捕获更方便。异常处理程序的核心部分通常非常简单,如果您确实需要调试该部分,则可以进行printf调试。