Index: base/logging.h |
diff --git a/base/logging.h b/base/logging.h |
index 714545c02bb06ac7f1b31e8a007b671e6dc11d6d..7f6febbb05f3138f20a889f1f279afdcfe63a784 100644 |
--- a/base/logging.h |
+++ b/base/logging.h |
@@ -15,6 +15,7 @@ |
#include <utility> |
#include "base/base_export.h" |
+#include "base/compiler_specific.h" |
#include "base/debug/debugger.h" |
#include "base/macros.h" |
#include "base/template_util.h" |
@@ -458,16 +459,43 @@ class CheckOpResult { |
// bloat, and improve performance, for official release builds. |
#if defined(COMPILER_GCC) || __clang__ |
-#define LOGGING_CRASH() __builtin_trap() |
-#else |
-#define LOGGING_CRASH() ((void)(*(volatile char*)0 = 0)) |
+ |
+// This is to make sure that the crash report can pinpoint to the right source |
+// line even in presence of multiple CHECK()s in the same function. See |
+// http://crbug.com/664209 for more context. |
+// There are three things we need to guarantee here: |
+// - The trap instructions, and hence the PC value at crash time, are distinct |
+// and don't get collapsed into the same op due to compiler optimizations. |
+// - The debug line info for the trap instructions get attributed to the caller |
+// of CHECK(), to make sure that crash reports show actionable data. This in |
+// practice rules out the ability of using a inline function, at least as |
+// long as clang doesn't support attribute(artificial). |
+// - The compiler should treat the CHECK as no-return instructions, so that the |
+// trap code can be efficiently packed in the prologue of the function and |
+// doesn't interfere with the main execution flow. |
+// Code-wise: |
+// - The asm volatile statement is a cross-architecture version of |
+// mov %eax, LINE. It guarantees that the assembly is unique for each line |
+// and the multiple crash instructions generated by CHECK() don't get folded. |
+// - __builtin_trap() is the instruction that actually causes the crash, |
+// either a SIGTRAP or a SIGABRT depending on the platform. |
+// - __builtin_unreachable() enables no-return optimizations. |
+#define LOGGING_CRASH(LINE) \ |
+ ({ \ |
+ asm volatile("" : : "r"(LINE) : "memory"); \ |
+ __builtin_trap(); \ |
+ __builtin_unreachable(); \ |
+ }) |
+ |
+#else // !(defined(COMPILER_GCC) || __clang__) |
+#define LOGGING_CRASH(LINE) ((void)(*(volatile char*)0 = 0)) |
Nico
2016/12/02 02:04:03
This doesn't help on Windows, does it. Would
((
|
#endif |
// This is not calling BreakDebugger since this is called frequently, and |
// calling an out-of-line function instead of a noreturn inline macro prevents |
// compiler optimizations. |
-#define CHECK(condition) \ |
- !(condition) ? LOGGING_CRASH() : EAT_STREAM_PARAMETERS |
+#define CHECK(condition) \ |
+ !(condition) ? LOGGING_CRASH(__LINE__) : EAT_STREAM_PARAMETERS |
#define PCHECK(condition) CHECK(condition) |