This is an archive of the discontinued LLVM Phabricator instance.

[llvm] [Support] Fix segv if argv0 is null in getMainExecutable()
ClosedPublic

Authored by mgorny on Nov 7 2020, 1:08 PM.

Details

Summary

When LLDB Python bindings are used and stack backtraces are enabled
for logging, getMainExecutable() is called with argv0 being null.
This caused the fallback function getprogpath() (used on FreeBSD, NetBSD
and Linux) to segfault. Make it handle null executable name gracefully.

Diff Detail

Event Timeline

mgorny created this revision.Nov 7 2020, 1:08 PM
Herald added a project: Restricted Project. · View Herald TranscriptNov 7 2020, 1:08 PM
mgorny requested review of this revision.Nov 7 2020, 1:08 PM
emaste accepted this revision.Nov 7 2020, 1:09 PM
This revision is now accepted and ready to land.Nov 7 2020, 1:09 PM

Are you sure that's the right level at which to fix this? Can you explain how that particular test manages to pass a nullptr to this function?

Are you sure that's the right level at which to fix this? Can you explain how that particular test manages to pass a nullptr to this function?

I'm not. However, it's a smaller change that checking it before every one of the three getprogpath() calls.

getMainExecutable() is passed argv0=nullptr. Other platforms probably don't hit this because their primary code succeeds, while the code for FreeBSD < 13 apparently doesn't here. Hence, getprogname() is called with nullptr argument.

(lldb) bt
* thread #1, name = 'python3.7', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
  * frame #0: 0x00000008086c48ff libLLVMSupport.so.12git`llvm::sys::fs::getMainExecutable(char const*, void*) + 80
    frame #1: 0x00000008086c96e8 libLLVMSupport.so.12git`printSymbolizedStackTrace(llvm::StringRef, void**, int, llvm::raw_ostream&) + 485
    frame #2: 0x00000008086ca91e libLLVMSupport.so.12git`llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) + 96
    frame #3: 0x0000000802b24b34 _lldb.so`lldb_private::Log::WriteHeader(llvm::raw_ostream&, llvm::StringRef, llvm::StringRef) + 718
    frame #4: 0x0000000802b2472b _lldb.so`lldb_private::Log::VAPrintf(char const*, __va_list_tag*) + 165
    frame #5: 0x0000000802b245a9 _lldb.so`lldb_private::Log::Printf(char const*, ...) + 107
    frame #6: 0x0000000802a41f55 _lldb.so`lldb_private::CommandInterpreter::HandleCommand(char const*, lldb_private::LazyBool, lldb_private::CommandReturnObject&, lldb_private::ExecutionContext*, bool, bool) + 127
    frame #7: 0x000000080270575d _lldb.so`lldb::SBCommandInterpreter::HandleCommand(char const*, lldb::SBExecutionContext&, lldb::SBCommandReturnObject&, bool) + 389
    frame #8: 0x00000008027053e6 _lldb.so`lldb::SBCommandInterpreter::HandleCommand(char const*, lldb::SBCommandReturnObject&, bool) + 216
    frame #9: 0x00000008029172ca _lldb.so`_wrap_SBCommandInterpreter_HandleCommand(_object*, _object*) + 2069
    frame #10: 0x000000080036a3d7 libpython3.7m.so.1.0`PyCFunction_Call + 327
    [...]

(the rest of the backtrace is Python)

llvm::sys::PrintStackTrace() calls printSymbolizedStackTrace(Argv0, ...), and the global static variable Argv0 is only set by llvm::sys::PrintStackTraceOnErrorSignal() which is not being called here.

labath accepted this revision.Nov 9 2020, 1:04 AM

Ok, I understand what's happening now. The problem is calling PrintStackTrace without a previous PrintStackTraceOnErrorSignal. That seems reasonable. It would be nice to have a llvm test for this, but that would be quite tricky, as all gtests implicitly call PrintStackTraceOnErrorSignal, and all utilities call InitLLVM (which call PrintStackTraceOnErrorSignal)...

Herald added a project: Restricted Project. · View Herald TranscriptNov 9 2020, 2:37 AM