yassert.cpp 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #include "yassert.h"
  2. #include "backtrace.h"
  3. #include "guard.h"
  4. #include "spinlock.h"
  5. #include "src_root.h"
  6. #include <util/datetime/base.h>
  7. #include <util/generic/singleton.h>
  8. #include <util/generic/strbuf.h>
  9. #include <util/generic/string.h>
  10. #include <util/stream/output.h>
  11. #include <util/stream/str.h>
  12. #include <util/string/printf.h>
  13. #include <cstdlib>
  14. #include <stdarg.h>
  15. #include <stdio.h>
  16. #ifdef CLANG_COVERAGE
  17. extern "C" {
  18. // __llvm_profile_write_file may not be provided if the executable target uses NO_CLANG_COVERAGE() macro and
  19. // arrives as test's dependency via DEPENDS() macro.
  20. // That's why we provide a weak no-op implementation for __llvm_profile_write_file,
  21. // which is used below in the code, to correctly save codecoverage profile before program exits using abort().
  22. Y_WEAK int __llvm_profile_write_file(void) {
  23. return 0;
  24. }
  25. }
  26. #endif
  27. namespace {
  28. struct TPanicLockHolder: public TAdaptiveLock {
  29. };
  30. } // namespace
  31. namespace NPrivate {
  32. [[noreturn]] Y_NO_INLINE void InternalPanicImpl(int line, const char* function, const char* expr, int, int, int, const TStringBuf file, const char* errorMessage, size_t errorMessageSize) noexcept;
  33. } // namespace NPrivate
  34. void ::NPrivate::Panic(const TStaticBuf& file, int line, const char* function, const char* expr, const char* format, ...) noexcept {
  35. try {
  36. // We care of panic of first failed thread only
  37. // Otherwise stderr could contain multiple messages and stack traces shuffled
  38. auto guard = Guard(*Singleton<TPanicLockHolder>());
  39. TString errorMsg;
  40. va_list args;
  41. va_start(args, format);
  42. // format has " " prefix to mute GCC warning on empty format
  43. vsprintf(errorMsg, format[0] == ' ' ? format + 1 : format, args);
  44. va_end(args);
  45. constexpr int abiPlaceholder = 0;
  46. ::NPrivate::InternalPanicImpl(line, function, expr, abiPlaceholder, abiPlaceholder, abiPlaceholder, file.As<TStringBuf>(), errorMsg.c_str(), errorMsg.size());
  47. } catch (...) {
  48. // ¯\_(ツ)_/¯
  49. }
  50. abort();
  51. }
  52. namespace NPrivate {
  53. [[noreturn]] Y_NO_INLINE void InternalPanicImpl(int line, const char* function, const char* expr, int, int, int, const TStringBuf file, const char* errorMessage, size_t errorMessageSize) noexcept try {
  54. TStringBuf errorMsg{errorMessage, errorMessageSize};
  55. const TString now = TInstant::Now().ToStringLocal();
  56. TString r;
  57. TStringOutput o(r);
  58. if (expr) {
  59. o << "VERIFY failed (" << now << "): " << errorMsg << Endl;
  60. } else {
  61. o << "FAIL (" << now << "): " << errorMsg << Endl;
  62. }
  63. o << " " << file << ":" << line << Endl;
  64. if (expr) {
  65. o << " " << function << "(): requirement " << expr << " failed" << Endl;
  66. } else {
  67. o << " " << function << "() failed" << Endl;
  68. }
  69. Cerr << r << Flush;
  70. #ifndef WITH_VALGRIND
  71. PrintBackTrace();
  72. #endif
  73. #ifdef CLANG_COVERAGE
  74. if (__llvm_profile_write_file()) {
  75. Cerr << "Failed to dump clang coverage" << Endl;
  76. }
  77. #endif
  78. abort();
  79. } catch (...) {
  80. abort();
  81. }
  82. } // namespace NPrivate