GNU libmicrohttpd 1.0.9
Loading...
Searching...
No Matches
mhd_panic_tripwire.h
Go to the documentation of this file.
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2026 Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library.
17 If not, see <http://www.gnu.org/licenses/>.
18*/
19
116#ifndef MHD_PANIC_TRIPWIRE_H
117#define MHD_PANIC_TRIPWIRE_H 1
118
119#include <stdlib.h>
120#include <string.h>
121#include <signal.h>
122#ifdef _WIN32
123#include <io.h>
124#else /* ! _WIN32 */
125#include <unistd.h>
126#endif /* ! _WIN32 */
127
132#define MHD_PANIC_TRIPWIRE_MARKER "MHD-PANIC-TRIPWIRE"
133
138#define MHD_PANIC_TRIPWIRE_EXIT_STATUS 99
139
140/* Detect a usable backtrace() implementation. This must not depend on
141 configure, because this header is also used from test directories that do
142 not run any dedicated check for it. Degrade silently when absent. */
143#if ! defined(MHD_PANIC_TRIPWIRE_BACKTRACE_)
144# if defined(__has_include )
145# if __has_include (<execinfo.h>)
146# define MHD_PANIC_TRIPWIRE_BACKTRACE_ 1
147# endif /* __has_include(<execinfo.h>) */
148# elif defined(HAVE_EXECINFO_H) || defined(__GLIBC__)
149# define MHD_PANIC_TRIPWIRE_BACKTRACE_ 1
150# endif /* HAVE_EXECINFO_H || __GLIBC__ */
151#endif /* ! MHD_PANIC_TRIPWIRE_BACKTRACE_ */
152#ifdef MHD_PANIC_TRIPWIRE_BACKTRACE_
153#include <execinfo.h>
154#endif /* MHD_PANIC_TRIPWIRE_BACKTRACE_ */
155
156/* Weak references let this header be included by the unit tests that do not
157 link libmicrohttpd (test_str*, test_md5, test_sha*, test_auth_parse, ...).
158 Without weak-symbol support the MHD_PANIC() hook is simply not installed
159 and only the abort() hook remains. */
160#if defined(__GNUC__) && defined(__ELF__) && ! defined(_WIN32)
161# define MHD_PANIC_TRIPWIRE_WEAK_ __attribute__ ((weak))
162#endif /* __GNUC__ && __ELF__ && ! _WIN32 */
163
164#ifdef MHD_PANIC_TRIPWIRE_WEAK_
165/* Deliberately declared here instead of pulling in <microhttpd.h>: the
166 signature is identical to MHD_PanicCallback, so this declaration is
167 compatible with the one in <microhttpd.h> when that header is also
168 included, and it keeps this file usable in translation units that never
169 see the public header. */
170extern MHD_PANIC_TRIPWIRE_WEAK_ void
171MHD_set_panic_func (void (*cb)(void *cls,
172 const char *file,
173 unsigned int line,
174 const char *reason),
175 void *cls);
176
177#endif /* MHD_PANIC_TRIPWIRE_WEAK_ */
178
179#if defined(__GNUC__) || defined(__clang__)
180# define MHD_PANIC_TRIPWIRE_UNUSED_ __attribute__ ((unused))
181# define MHD_PANIC_TRIPWIRE_NORETURN_ __attribute__ ((noreturn))
182#else /* ! __GNUC__ */
183# define MHD_PANIC_TRIPWIRE_UNUSED_
184# define MHD_PANIC_TRIPWIRE_NORETURN_
185#endif /* ! __GNUC__ */
186
192static volatile sig_atomic_t mhd_panic_tripwire_reraise_ = 0;
193
197static volatile sig_atomic_t mhd_panic_tripwire_status_ =
199
204static volatile sig_atomic_t mhd_panic_tripwire_busy_ = 0;
205
206
212#define MHD_PANIC_TRIPWIRE_WRS_(str) \
213 mhd_panic_tripwire_wr_ (str, sizeof(str) - 1)
214
215
223static void
224mhd_panic_tripwire_wr_ (const char *buf,
225 size_t len)
226{
227 size_t off = 0;
228
229 while (off < len)
230 {
231#ifdef _WIN32
232 int res = _write (2, buf + off, (unsigned int) (len - off));
233#else /* ! _WIN32 */
234 ssize_t res = write (STDERR_FILENO, buf + off, len - off);
235#endif /* ! _WIN32 */
236 if (0 >= res)
237 return; /* Give up rather than spin. */
238 off += (size_t) res;
239 }
240}
241
242
249static void
251{
252 char chunk[256];
253 size_t used = 0;
254
255 if (NULL == str)
256 {
257 MHD_PANIC_TRIPWIRE_WRS_ ("(null)");
258 return;
259 }
260 while (0 != *str)
261 {
262 const unsigned char chr = (unsigned char) *str++;
263
264 chunk[used++] = (0x20 > chr) ? ' ' : (char) chr;
265 if (sizeof(chunk) == used)
266 {
267 mhd_panic_tripwire_wr_ (chunk, used);
268 used = 0;
269 }
270 }
271 if (0 != used)
272 mhd_panic_tripwire_wr_ (chunk, used);
273}
274
275
281static void
282mhd_panic_tripwire_wr_num_ (unsigned long val)
283{
284 char buf[24];
285 size_t pos = sizeof(buf);
286
287 do
288 {
289 buf[--pos] = (char) ('0' + (val % 10));
290 val /= 10;
291 } while (0 != val);
292 mhd_panic_tripwire_wr_ (buf + pos, sizeof(buf) - pos);
293}
294
295
300static void
302{
303#ifdef MHD_PANIC_TRIPWIRE_BACKTRACE_
304 void *frames[64];
305 int num;
306
307 num = backtrace (frames, (int) (sizeof(frames) / sizeof(frames[0])));
308 if (0 >= num)
309 return;
311 mhd_panic_tripwire_wr_num_ ((unsigned long) num);
312 MHD_PANIC_TRIPWIRE_WRS_ (" frames follow\n");
313 /* backtrace_symbols_fd() does not allocate, unlike backtrace_symbols(). */
314 backtrace_symbols_fd (frames, num, 2);
315#endif /* MHD_PANIC_TRIPWIRE_BACKTRACE_ */
316}
317
318
330 const char *file,
331 unsigned int line,
332 const char *reason)
333{
335 {
339 MHD_PANIC_TRIPWIRE_WRS_ (" file=");
340 mhd_panic_tripwire_wr_clean_ ((NULL != file) ? file : "(unknown)");
341 MHD_PANIC_TRIPWIRE_WRS_ (" line=");
342 mhd_panic_tripwire_wr_num_ ((unsigned long) line);
343 MHD_PANIC_TRIPWIRE_WRS_ (" reason=");
344 mhd_panic_tripwire_wr_clean_ ((NULL != reason) ? reason : "(none)");
348 {
350 ": terminating with exit status ");
353 }
354 else
356 ": re-raising SIGABRT for a core dump\n");
357 }
359 {
360 signal (SIGABRT, SIG_DFL);
361 raise (SIGABRT);
362 }
363 _exit ((int) mhd_panic_tripwire_status_);
364}
365
366
375static void
377 const char *file,
378 unsigned int line,
379 const char *reason)
380{
381 (void) cls; /* Mute compiler warning. */
382 mhd_panic_tripwire_report_ ("MHD_PANIC",
383 file,
384 line,
385 reason);
386}
387
388
396static void
398{
399 (void) sig; /* Mute compiler warning. */
401 NULL,
402 0,
403 "abort() reached; see the line above for the "
404 "failed assertion, if any");
405}
406
407
414static int
416{
417 if (NULL == val)
418 return 0;
419 return (0 == strcmp (val, "0")) ||
420 (0 == strcmp (val, "off")) ||
421 (0 == strcmp (val, "no")) ||
422 (0 == strcmp (val, "disable"));
423}
424
425
433{
434 const char *mode = getenv ("MHD_TEST_PANIC_TRIPWIRE");
435
437 return; /* Leave the stock behaviour completely untouched. */
438 if ((NULL != mode) && (0 == strcmp (mode, "abort")))
440 else if ((NULL != mode) && (0 == strncmp (mode, "exit:", 5)))
441 {
442 const long status = strtol (mode + 5, NULL, 10);
443
444 if ((0 <= status) && (255 >= status))
445 mhd_panic_tripwire_status_ = (sig_atomic_t) status;
446 }
447#ifdef MHD_PANIC_TRIPWIRE_WEAK_
450 NULL);
451#else /* ! MHD_PANIC_TRIPWIRE_WEAK_ */
453 NULL);
454#endif /* ! MHD_PANIC_TRIPWIRE_WEAK_ */
455 if (! mhd_panic_tripwire_is_off_ (getenv ("MHD_TEST_PANIC_TRIPWIRE_ABRT")))
456 signal (SIGABRT,
458}
459
460
461#if defined(__GNUC__) || defined(__clang__)
468__attribute__ ((constructor)) static void
469mhd_panic_tripwire_ctor_ (void)
470{
472}
473
474
475#endif /* __GNUC__ || __clang__ */
476
477#endif /* ! MHD_PANIC_TRIPWIRE_H */
_MHD_EXTERN void MHD_set_panic_func(MHD_PanicCallback cb, void *cls)
Definition mhd_panic.c:94
#define NULL
static int mhd_panic_tripwire_is_off_(const char *val)
static void mhd_panic_tripwire_wr_clean_(const char *str)
static volatile sig_atomic_t mhd_panic_tripwire_status_
#define MHD_PANIC_TRIPWIRE_UNUSED_
#define MHD_PANIC_TRIPWIRE_MARKER
static MHD_PANIC_TRIPWIRE_UNUSED_ void mhd_panic_tripwire_install(void)
static void mhd_panic_tripwire_wr_(const char *buf, size_t len)
static void mhd_panic_tripwire_abrt_cb_(int sig)
static volatile sig_atomic_t mhd_panic_tripwire_reraise_
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)
#define MHD_PANIC_TRIPWIRE_WRS_(str)
#define MHD_PANIC_TRIPWIRE_NORETURN_
#define MHD_PANIC_TRIPWIRE_EXIT_STATUS
static void mhd_panic_tripwire_panic_cb_(void *cls, const char *file, unsigned int line, const char *reason)
static void mhd_panic_tripwire_wr_num_(unsigned long val)
static volatile sig_atomic_t mhd_panic_tripwire_busy_