]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: debug: support passing an optional message in ABORT_NOW()
authorWilly Tarreau <w@1wt.eu>
Mon, 5 Feb 2024 15:16:08 +0000 (16:16 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 5 Feb 2024 16:09:00 +0000 (17:09 +0100)
The ABORT_NOW() macro is not much used since we have BUG_ON(), but
there are situations where it makes sense, typically if the program
must always die regardless od DEBUG_STRICT, or if the condition must
always be evaluated (e.g. decompress something and check it).

It's not convenient not to have any hint about what happened there. But
providing too much info also results in wiping some registers, making
the trace less exploitable, so a compromise must be found.

What this patch does is to provide the support for an optional argument
to ABORT_NOW(). When an argument is passed (a string), then a message
will be emitted with the file name, line number, the message and a
trailing LF, before the stack dump and the crash. It should be used
reasonably, for example in functions that have multiple calls that need
to be more easily distinguished.

include/haproxy/bug.h

index 1356acf13b09b5a55026cf497d7c851c43fcb4b2..18914ca7ba11008a345177f3ef7c509cfb6d8f3b 100644 (file)
@@ -85,6 +85,23 @@ static inline __attribute((always_inline)) void ha_crash_now(void)
 
 #endif // end of arch-specific ha_crash_now() definitions
 
+
+/* ABORT_NOW() usually takes no argument and will cause the program to abort
+ * exactly where it is. We prefer to emit an invalid instruction to preserve
+ * all registers, but it may fall back to a regular abort depending on the
+ * platform. An optional argument can be a message string that will cause
+ * the emission of a message saying "ABORT at" followed by the file and line
+ * number then that message followed by a final line feed. This can be helpful
+ * in situations where the core cannot be retrieved for example. However it
+ * will definitely cause the loss of some registers, so should be avoided when
+ * not strictly necessary.
+ */
+#define ABORT_NOW(...)                                                 \
+       _ABORT_NOW(__FILE__, __LINE__, __VA_ARGS__)
+
+#define _ABORT_NOW(file, line, ...)                                    \
+       __ABORT_NOW(file, line, __VA_ARGS__)
+
 #ifdef DEBUG_USE_ABORT
 /* abort() is better recognized by code analysis tools */
 
@@ -104,12 +121,22 @@ static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line)
        abort();
 }
 
-#define ABORT_NOW() do { DUMP_TRACE(); abort_with_line(__LINE__); } while (0)
+#define __ABORT_NOW(file, line, ...) do {                              \
+               if (sizeof("" __VA_ARGS__) > 1)                         \
+                       complain(NULL, "\nABORT at " file ":" #line ": " __VA_ARGS__ "\n", 1); \
+               DUMP_TRACE();                                           \
+               abort_with_line(__LINE__);                              \
+       } while (0)
 #else
 /* More efficient than abort() because it does not mangle the
  * stack and stops at the exact location we need.
  */
-#define ABORT_NOW() do { DUMP_TRACE(); ha_crash_now(); } while (0)
+#define __ABORT_NOW(file, line, ...) do {                              \
+               if (sizeof("" __VA_ARGS__) > 1)                         \
+                       complain(NULL, "\nABORT at " file ":" #line ": " __VA_ARGS__ "\n", 1); \
+               DUMP_TRACE();                                           \
+               ha_crash_now();                                         \
+       } while (0)
 #endif
 
 /* This is the generic low-level macro dealing with conditional warnings and