abseil / abseil-cpp

Abseil Common Libraries (C++)
https://abseil.io
Apache License 2.0
15.1k stars 2.64k forks source link

absl::FailureSignalHandler does not produce useful results on assert() failures #769

Open shahms opened 4 years ago

shahms commented 4 years ago

Describe the bug

After setting up symbolization and installing a failure signal handler, a failing assert() with glibc does not produce a useful stack trace, consisting entirely of:

cxx_extractor: kythe/cxx/extractor/cxx_extractor.cc:922: virtual void kythe::KzipWriterSink::OpenIndex(const std::string &): Assertion `0 == 1' failed.
*** SIGABRT received at time=1597685134 ***
PC: @     0x7fbd21014761  (unknown)  raise
    @          0x14fe81d        144  absl::WriteFailureInfo()
    @          0x14fe5f7         64  absl::AbslFailureSignalHandler()
    @     0x7fbd211cf110  (unknown)  (unknown)
    @ 0x4173257325203a75  (unknown)  (unknown)
Aborted

Calling std::abort directly or CHECK-failing produces a useful stack trace:

*** SIGABRT received at time=1597685257 ***
PC: @     0x7ff5af672761  (unknown)  raise
    @          0x14fe81d        144  absl::WriteFailureInfo()
    @          0x14fe5f7         64  absl::AbslFailureSignalHandler()
    @     0x7ff5af82d110  184382256  (unknown)
    @           0x4111da        896  kythe::CompilationWriter::WriteIndex()
    @           0x41db08         80  std::_Function_handler<>::_M_invoke()
    @           0x416c22        144  kythe::(anonymous namespace)::ExtractorAction::EndSourceFileAction()
    @           0x5171fa        144  clang::FrontendAction::EndSourceFile()
    @           0x495cb8        160  clang::CompilerInstance::ExecuteAction()
    @           0x47b902        448  clang::tooling::FrontendActionFactory::runInvocation()
    @           0x47b494         80  clang::tooling::ToolInvocation::runInvocation()
    @           0x47a4c4       2400  clang::tooling::ToolInvocation::run()
    @           0x4130bb        272  kythe::ExtractorConfiguration::Extract()
    @           0x413449        112  kythe::ExtractorConfiguration::Extract()
    @           0x40d36a       1120  main
    @     0x7ff5af65de0b  (unknown)  __libc_start_main
    @ 0x5541d68949564100  (unknown)  (unknown)
Aborted

Steps to reproduce the bug

#include <cassert>
int main(int argc, char** argv) {
  google::InitGoogleLogging(argv[0]);
  absl::InitializeSymbolizer(argv[0]);
  absl::InstallFailureSignalHandler({});
  assert(false);
}

What version of Abseil are you using? 0033c9ea91a52ade7c6b725aa2ef3cbe15463421

What operating system and version are you using

If you are using a Linux distribution please include the name and version of the distribution as well.

What compiler and version are you using?

Debian GNU/Linux rodete

$ clang -v
clang version 9.0.1-12
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/6
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/6.5.0
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/7.5.0
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/i686-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/10
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/6.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/7.5.0
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/9
Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/9
Candidate multilib: .;@m64
Candidate multilib: 32;@m32
Candidate multilib: x32;@mx32
Selected multilib: .;@m64

What build system are you using?

$ bazel --version
bazel 3.4.1
derekmauro commented 4 years ago

What is happening here is that you are trying to unwind though glibc, which is compiled with optimization and without -fno-omit-frame-pointer. Without a frame pointer, you can't walk the stack any further.

There is a workaround that we use in our production logging library. In glibc, __assert_fail() is a weak function that you can replace with your own function, which you can build with frame pointers enabled.

Try adding something like this to your code:

extern "C" void __assert_fail(const char *assertion, const char *file, unsigned int line, const char *function) __THROW {
  // Print an assertion message
  abort();
}

I don't know what else we can do besides maybe documenting this.

shahms commented 4 years ago

After a fair amount of hunting around I found the internal workaround and added it myself, but some documentation would definitely have helped. I was hopeful that a more principled replacement might be possible based on detected libc version, but it's definitely not critical. Thanks!