|
GNU libmicrohttpd 1.0.9
|
Test-only tripwire that turns a fatal libmicrohttpd invariant failure into a loud, greppable, machine-classifiable test error. More...
#include <stdlib.h>#include <string.h>#include <signal.h>#include <unistd.h>
Go to the source code of this file.
Macros | |
| #define | MHD_PANIC_TRIPWIRE_MARKER "MHD-PANIC-TRIPWIRE" |
| #define | MHD_PANIC_TRIPWIRE_EXIT_STATUS 99 |
| #define | MHD_PANIC_TRIPWIRE_UNUSED_ |
| #define | MHD_PANIC_TRIPWIRE_NORETURN_ |
| #define | MHD_PANIC_TRIPWIRE_WRS_(str) |
Functions | |
| static void | mhd_panic_tripwire_wr_ (const char *buf, size_t len) |
| static void | mhd_panic_tripwire_wr_clean_ (const char *str) |
| static void | mhd_panic_tripwire_wr_num_ (unsigned long val) |
| static void | mhd_panic_tripwire_backtrace_ (void) |
| static MHD_PANIC_TRIPWIRE_NORETURN_ void | mhd_panic_tripwire_report_ (const char *kind, const char *file, unsigned int line, const char *reason) |
| static void | mhd_panic_tripwire_panic_cb_ (void *cls, const char *file, unsigned int line, const char *reason) |
| static void | mhd_panic_tripwire_abrt_cb_ (int sig) |
| static int | mhd_panic_tripwire_is_off_ (const char *val) |
| static MHD_PANIC_TRIPWIRE_UNUSED_ void | mhd_panic_tripwire_install (void) |
Variables | |
| static volatile sig_atomic_t | mhd_panic_tripwire_reraise_ = 0 |
| static volatile sig_atomic_t | mhd_panic_tripwire_status_ |
| static volatile sig_atomic_t | mhd_panic_tripwire_busy_ = 0 |
Test-only tripwire that turns a fatal libmicrohttpd invariant failure into a loud, greppable, machine-classifiable test error.
Rationale (TESTING.md, proposal P5): no network input must ever be able to reach MHD_PANIC() or a failing mhd_assert(). When it does, the test suite should say so in a way that a CI job or the option-matrix driver can pick out mechanically, instead of leaving behind an anonymous SIGABRT that is indistinguishable from an ordinary test failure.
Add exactly one line to a test program:
#include "mhd_panic_tripwire.h"
Nothing else is needed: on GCC/clang the header installs itself from a __attribute__((constructor)), which runs after the libmicrohttpd shared object has run its own initialiser (and therefore after MHD_init() has installed the stock panic handler), so the tripwire wins. On toolchains without constructor support, call mhd_panic_tripwire_install() as the first statement of main() instead.
MHD_PANIC(msg) expands to mhd_panic (...); BUILTIN_NOT_REACHED;, i.e. __builtin_unreachable(). A panic handler that returns therefore drops the caller straight into undefined behaviour - the compiler has already been told that the following code is dead and may have deleted it. So the handler has to terminate the process.
longjmp() back into main() is not an option either: MHD_PANIC() is reached from library code that may be running on a daemon worker thread or on a thread-per-connection thread, and a longjmp() across threads is undefined. Even on the right thread it would leave the daemon's mutexes locked and its connection lists half-updated, so any "recording" done afterwards would run in a process whose state is already corrupt. We therefore report and terminate rather than recover.
The default is _exit(99). The automake parallel test harness classifies exit status 99 as a hard ERROR rather than an ordinary FAIL, which is exactly the "this is not a normal test failure, a fatal invariant was reached" signal wanted here. Note that this also applies to tests listed in XFAIL_TESTS - a test that is expected to trip an assertion (such as src/microhttpd/test_known_bugs.c) must therefore NOT include this header.
MHD_TEST_PANIC_TRIPWIRE
0 / off / no / disable: completely disabled; the stock libmicrohttpd behaviour (mhd_panic_std(), plain abort()) is left in place. Use this when a debugger or an external tool wants the original behaviour.abort: print the marker and the stack trace, then re-raise SIGABRT with the default disposition so that a core dump is produced.exit:N (0 <= N <= 255): print the marker and the stack trace, then terminate with status N instead of 99.MHD_TEST_PANIC_TRIPWIRE_ABRT
0 / off / no / disable: do not install the SIGABRT handler; only MHD_PANIC() is intercepted. Failing mhd_assert()s then abort as usual.A single greppable marker line is written to stderr, followed (where available) by a stack trace and a final status line:
MHD-PANIC-TRIPWIRE: kind=MHD_PANIC file=connection.c line=1234 \ reason=Data offset exceeds limit. MHD-PANIC-TRIPWIRE-FRAME: ... MHD-PANIC-TRIPWIRE: terminating with exit status 99
Grep for MHD_PANIC_TRIPWIRE_MARKER ("MHD-PANIC-TRIPWIRE") to classify a failure. Everything is emitted with write(2) and without allocating, so the same code path is usable from the SIGABRT handler.
Definition in file mhd_panic_tripwire.h.
| #define MHD_PANIC_TRIPWIRE_EXIT_STATUS 99 |
The exit status used by default. The automake test harness reports this as a hard ERROR instead of a FAIL.
Definition at line 138 of file mhd_panic_tripwire.h.
| #define MHD_PANIC_TRIPWIRE_MARKER "MHD-PANIC-TRIPWIRE" |
The distinctive, greppable marker that prefixes every line printed by the tripwire.
Definition at line 132 of file mhd_panic_tripwire.h.
Referenced by mhd_panic_tripwire_backtrace_(), and mhd_panic_tripwire_report_().
| #define MHD_PANIC_TRIPWIRE_NORETURN_ |
Definition at line 184 of file mhd_panic_tripwire.h.
| #define MHD_PANIC_TRIPWIRE_UNUSED_ |
Definition at line 183 of file mhd_panic_tripwire.h.
| #define MHD_PANIC_TRIPWIRE_WRS_ | ( | str | ) |
Write a string literal to stderr.
| str | a string literal |
Definition at line 212 of file mhd_panic_tripwire.h.
Referenced by mhd_panic_tripwire_backtrace_(), mhd_panic_tripwire_report_(), and mhd_panic_tripwire_wr_clean_().
|
static |
The SIGABRT handler installed by the tripwire. Catches a failing mhd_assert() (which goes through assert(3) and abort(3)) and any other abort(), for example from the C library's own consistency checks.
| sig | the signal number, always SIGABRT |
Definition at line 397 of file mhd_panic_tripwire.h.
References mhd_panic_tripwire_report_(), and NULL.
Referenced by mhd_panic_tripwire_install().


|
static |
Print the stack trace of the calling thread, if the platform provides one. Silently does nothing otherwise.
Definition at line 301 of file mhd_panic_tripwire.h.
References MHD_PANIC_TRIPWIRE_MARKER, mhd_panic_tripwire_wr_num_(), and MHD_PANIC_TRIPWIRE_WRS_.
Referenced by mhd_panic_tripwire_report_().


|
static |
Install the panic tripwire. Called automatically from a constructor on GCC-compatible toolchains; call it explicitly as the first statement of main() on any other toolchain. Idempotent.
Definition at line 432 of file mhd_panic_tripwire.h.
References mhd_panic_tripwire_abrt_cb_(), mhd_panic_tripwire_is_off_(), mhd_panic_tripwire_panic_cb_(), mhd_panic_tripwire_reraise_, mhd_panic_tripwire_status_, MHD_set_panic_func(), and NULL.

|
static |
Test whether an environment variable value means "off".
| val | the value to test, may be NULL |
Definition at line 415 of file mhd_panic_tripwire.h.
References NULL.
Referenced by mhd_panic_tripwire_install().

|
static |
The MHD_PanicCallback installed by the tripwire.
| cls | unused |
| file | the name of the file with the problem |
| line | the line number with the problem |
| reason | the error message with details |
Definition at line 376 of file mhd_panic_tripwire.h.
References mhd_panic_tripwire_report_().
Referenced by mhd_panic_tripwire_install().


|
static |
Print the marker line and the stack trace, then terminate the process. Never returns; see the file comment for why recovering is not an option.
| kind | a short token naming what was intercepted |
| file | the source file of the failure, may be NULL |
| line | the source line of the failure |
| reason | the human-readable reason, may be NULL |
Definition at line 329 of file mhd_panic_tripwire.h.
References mhd_panic_tripwire_backtrace_(), mhd_panic_tripwire_busy_, MHD_PANIC_TRIPWIRE_MARKER, mhd_panic_tripwire_reraise_, mhd_panic_tripwire_status_, mhd_panic_tripwire_wr_clean_(), mhd_panic_tripwire_wr_num_(), MHD_PANIC_TRIPWIRE_WRS_, and NULL.
Referenced by mhd_panic_tripwire_abrt_cb_(), and mhd_panic_tripwire_panic_cb_().


|
static |
Write a buffer to stderr. Async-signal-safe: no locking, no allocation, no stdio.
| buf | the bytes to write |
| len | the number of bytes to write |
Definition at line 224 of file mhd_panic_tripwire.h.
Referenced by mhd_panic_tripwire_wr_clean_(), and mhd_panic_tripwire_wr_num_().

|
static |
Write a NUL-terminated string to stderr, replacing every control character by a space so that the marker always stays on a single line.
| str | the string to write, may be NULL |
Definition at line 250 of file mhd_panic_tripwire.h.
References mhd_panic_tripwire_wr_(), MHD_PANIC_TRIPWIRE_WRS_, and NULL.
Referenced by mhd_panic_tripwire_report_().


|
static |
Write an unsigned number in decimal to stderr.
| val | the value to print |
Definition at line 282 of file mhd_panic_tripwire.h.
References mhd_panic_tripwire_wr_().
Referenced by mhd_panic_tripwire_backtrace_(), and mhd_panic_tripwire_report_().


|
static |
Set once a report is in progress, so that a second thread tripping at the same time does not interleave its output with the first one.
Definition at line 204 of file mhd_panic_tripwire.h.
Referenced by mhd_panic_tripwire_report_().
|
static |
Selected action, resolved once by the installer so that the handlers themselves never have to call getenv(). 0: terminate with mhd_panic_tripwire_status_; 1: re-raise SIGABRT.
Definition at line 192 of file mhd_panic_tripwire.h.
Referenced by mhd_panic_tripwire_install(), and mhd_panic_tripwire_report_().
|
static |
The exit status to use when mhd_panic_tripwire_reraise_ is zero.
Definition at line 197 of file mhd_panic_tripwire.h.
Referenced by mhd_panic_tripwire_install(), and mhd_panic_tripwire_report_().