summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2016-06-19 12:10:45 +0200
committerBen Noordhuis <info@bnoordhuis.nl>2016-06-29 13:50:36 +0200
commit92dab4a2b24bf9d092485b09868ac3183c8998f8 (patch)
treee7a035fad3c8c9717e84714ab90667ce6c6c1402 /src
parentbe767cf885438d6c3d3f84b6a5e2185b62f60318 (diff)
downloadnode-new-92dab4a2b24bf9d092485b09868ac3183c8998f8.tar.gz
src: print backtrace on failed CHECK/ASSERT
Print a C backtrace on fatal errors to make it easier to debug issues. PR-URL: https://github.com/nodejs/node/pull/6734 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/node.cc25
-rw-r--r--src/util.h40
2 files changed, 59 insertions, 6 deletions
diff --git a/src/node.cc b/src/node.cc
index 468b9a957e..511a4a25fd 100644
--- a/src/node.cc
+++ b/src/node.cc
@@ -1741,6 +1741,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();
}
diff --git a/src/util.h b/src/util.h
index a02639affb..e57651c3a6 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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__
@@ -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))