Skip to content

Commit

Permalink
src: print backtrace on failed CHECK/ASSERT
Browse files Browse the repository at this point in the history
Print a C backtrace on fatal errors to make it easier to debug issues.

PR-URL: #6734
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information
bnoordhuis authored and Fishrock123 committed Jul 5, 2016
1 parent b8919b1 commit 57cc4e3
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 6 deletions.
25 changes: 25 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1795,6 +1795,31 @@ NO_RETURN void Abort() {
}


NO_RETURN void Assert(const char* const (*args)[4]) {
auto filename = (*args)[0];
auto linenum = (*args)[1];
auto message = (*args)[2];
auto function = (*args)[3];

char exepath[256];
size_t exepath_size = sizeof(exepath);
if (uv_exepath(exepath, &exepath_size))
snprintf(exepath, sizeof(exepath), "node");

char pid[12] = {0};
#ifndef _WIN32
snprintf(pid, sizeof(pid), "[%u]", getpid());
#endif

fprintf(stderr, "%s%s: %s:%s:%s%s Assertion `%s' failed.\n",
exepath, pid, filename, linenum,
function, *function ? ":" : "", message);
fflush(stderr);

Abort();
}


static void Abort(const FunctionCallbackInfo<Value>& args) {
Abort();
}
Expand Down
40 changes: 34 additions & 6 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ namespace node {
#define NO_RETURN
#endif

// The slightly odd function signature for Assert() is to ease
// instruction cache pressure in calls from ASSERT and CHECK.
NO_RETURN void Abort();
NO_RETURN void Assert(const char* const (*args)[4]);
void DumpBacktrace(FILE* fp);

#ifdef __APPLE__
Expand All @@ -52,15 +55,40 @@ template <typename T> using remove_reference = std::remove_reference<T>;

#define ABORT() node::Abort()

#if defined(NDEBUG)
# define ASSERT(expression)
# define CHECK(expression) \
#ifdef __GNUC__
#define LIKELY(expr) __builtin_expect(!!(expr), 1)
#define UNLIKELY(expr) __builtin_expect(!!(expr), 0)
#define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
#else
#define LIKELY(expr) expr
#define UNLIKELY(expr) expr
#define PRETTY_FUNCTION_NAME ""
#endif

#define STRINGIFY_(x) #x
#define STRINGIFY(x) STRINGIFY_(x)

#define CHECK(expr) \
do { \
if (!(expression)) ABORT(); \
if (UNLIKELY(!(expr))) { \
static const char* const args[] = { __FILE__, STRINGIFY(__LINE__), \
#expr, PRETTY_FUNCTION_NAME }; \
node::Assert(&args); \
} \
} while (0)

// FIXME(bnoordhuis) cctests don't link in node::Abort() and node::Assert().
#ifdef GTEST_DONT_DEFINE_ASSERT_EQ
#undef ABORT
#undef CHECK
#define ABORT ABORT_NO_BACKTRACE
#define CHECK assert
#endif

#ifdef NDEBUG
#define ASSERT(expr)
#else
# define ASSERT(expression) assert(expression)
# define CHECK(expression) assert(expression)
#define ASSERT(expr) CHECK(expr)
#endif

#define ASSERT_EQ(a, b) ASSERT((a) == (b))
Expand Down

0 comments on commit 57cc4e3

Please sign in to comment.