diff --git a/src/node.cc b/src/node.cc index fe53b9629e..c9485af171 100644 --- a/src/node.cc +++ b/src/node.cc @@ -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& 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 using remove_reference = std::remove_reference; #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))