GNU libmicrohttpd
1.0.10
Toggle main menu visibility
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
115
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. */
170
extern
MHD_PANIC_TRIPWIRE_WEAK_
void
171
MHD_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
192
static
volatile
sig_atomic_t
mhd_panic_tripwire_reraise_
= 0;
193
197
static
volatile
sig_atomic_t
mhd_panic_tripwire_status_
=
198
MHD_PANIC_TRIPWIRE_EXIT_STATUS
;
199
204
static
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
223
static
void
224
mhd_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
249
static
void
250
mhd_panic_tripwire_wr_clean_
(
const
char
*str)
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
281
static
void
282
mhd_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
300
static
void
301
mhd_panic_tripwire_backtrace_
(
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
;
310
MHD_PANIC_TRIPWIRE_WRS_
(
MHD_PANIC_TRIPWIRE_MARKER
"-FRAMES: "
);
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
328
MHD_PANIC_TRIPWIRE_NORETURN_
static
void
329
mhd_panic_tripwire_report_
(
const
char
*kind,
330
const
char
*file,
331
unsigned
int
line,
332
const
char
*reason)
333
{
334
if
(0 ==
mhd_panic_tripwire_busy_
)
335
{
336
mhd_panic_tripwire_busy_
= 1;
337
MHD_PANIC_TRIPWIRE_WRS_
(
"\n"
MHD_PANIC_TRIPWIRE_MARKER
": kind="
);
338
mhd_panic_tripwire_wr_clean_
(kind);
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)"
);
345
MHD_PANIC_TRIPWIRE_WRS_
(
"\n"
);
346
mhd_panic_tripwire_backtrace_
();
347
if
(0 ==
mhd_panic_tripwire_reraise_
)
348
{
349
MHD_PANIC_TRIPWIRE_WRS_
(
MHD_PANIC_TRIPWIRE_MARKER
350
": terminating with exit status "
);
351
mhd_panic_tripwire_wr_num_
((
unsigned
long
)
mhd_panic_tripwire_status_
);
352
MHD_PANIC_TRIPWIRE_WRS_
(
"\n"
);
353
}
354
else
355
MHD_PANIC_TRIPWIRE_WRS_
(
MHD_PANIC_TRIPWIRE_MARKER
356
": re-raising SIGABRT for a core dump\n"
);
357
}
358
if
(0 !=
mhd_panic_tripwire_reraise_
)
359
{
360
signal (SIGABRT, SIG_DFL);
361
raise (SIGABRT);
362
}
363
_exit ((
int
)
mhd_panic_tripwire_status_
);
364
}
365
366
375
static
void
376
mhd_panic_tripwire_panic_cb_
(
void
*cls,
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
396
static
void
397
mhd_panic_tripwire_abrt_cb_
(
int
sig)
398
{
399
(void) sig;
/* Mute compiler warning. */
400
mhd_panic_tripwire_report_
(
"abort"
,
401
NULL
,
402
0,
403
"abort() reached; see the line above for the "
404
"failed assertion, if any"
);
405
}
406
407
414
static
int
415
mhd_panic_tripwire_is_off_
(
const
char
*val)
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
431
MHD_PANIC_TRIPWIRE_UNUSED_
static
void
432
mhd_panic_tripwire_install
(
void
)
433
{
434
const
char
*mode = getenv (
"MHD_TEST_PANIC_TRIPWIRE"
);
435
436
if
(
mhd_panic_tripwire_is_off_
(mode))
437
return
;
/* Leave the stock behaviour completely untouched. */
438
if
((
NULL
!= mode) && (0 == strcmp (mode,
"abort"
)))
439
mhd_panic_tripwire_reraise_
= 1;
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_
448
if
(
NULL
!=
MHD_set_panic_func
)
449
MHD_set_panic_func
(&
mhd_panic_tripwire_panic_cb_
,
450
NULL
);
451
#else
/* ! MHD_PANIC_TRIPWIRE_WEAK_ */
452
MHD_set_panic_func
(&
mhd_panic_tripwire_panic_cb_
,
453
NULL
);
454
#endif
/* ! MHD_PANIC_TRIPWIRE_WEAK_ */
455
if
(!
mhd_panic_tripwire_is_off_
(getenv (
"MHD_TEST_PANIC_TRIPWIRE_ABRT"
)))
456
signal (SIGABRT,
457
&
mhd_panic_tripwire_abrt_cb_
);
458
}
459
460
461
#if defined(__GNUC__) || defined(__clang__)
468
__attribute__ ((constructor))
static
void
469
mhd_panic_tripwire_ctor_ (
void
)
470
{
471
mhd_panic_tripwire_install
();
472
}
473
474
475
#endif
/* __GNUC__ || __clang__ */
476
477
#endif
/* ! MHD_PANIC_TRIPWIRE_H */
MHD_set_panic_func
_MHD_EXTERN void MHD_set_panic_func(MHD_PanicCallback cb, void *cls)
Definition
mhd_panic.c:94
NULL
#define NULL
Definition
mhd_mono_clock.c:66
mhd_panic_tripwire_is_off_
static int mhd_panic_tripwire_is_off_(const char *val)
Definition
mhd_panic_tripwire.h:415
mhd_panic_tripwire_wr_clean_
static void mhd_panic_tripwire_wr_clean_(const char *str)
Definition
mhd_panic_tripwire.h:250
mhd_panic_tripwire_status_
static volatile sig_atomic_t mhd_panic_tripwire_status_
Definition
mhd_panic_tripwire.h:197
MHD_PANIC_TRIPWIRE_UNUSED_
#define MHD_PANIC_TRIPWIRE_UNUSED_
Definition
mhd_panic_tripwire.h:183
MHD_PANIC_TRIPWIRE_MARKER
#define MHD_PANIC_TRIPWIRE_MARKER
Definition
mhd_panic_tripwire.h:132
mhd_panic_tripwire_install
static MHD_PANIC_TRIPWIRE_UNUSED_ void mhd_panic_tripwire_install(void)
Definition
mhd_panic_tripwire.h:432
mhd_panic_tripwire_wr_
static void mhd_panic_tripwire_wr_(const char *buf, size_t len)
Definition
mhd_panic_tripwire.h:224
mhd_panic_tripwire_abrt_cb_
static void mhd_panic_tripwire_abrt_cb_(int sig)
Definition
mhd_panic_tripwire.h:397
mhd_panic_tripwire_reraise_
static volatile sig_atomic_t mhd_panic_tripwire_reraise_
Definition
mhd_panic_tripwire.h:192
mhd_panic_tripwire_backtrace_
static void mhd_panic_tripwire_backtrace_(void)
Definition
mhd_panic_tripwire.h:301
mhd_panic_tripwire_report_
static MHD_PANIC_TRIPWIRE_NORETURN_ void mhd_panic_tripwire_report_(const char *kind, const char *file, unsigned int line, const char *reason)
Definition
mhd_panic_tripwire.h:329
MHD_PANIC_TRIPWIRE_WRS_
#define MHD_PANIC_TRIPWIRE_WRS_(str)
Definition
mhd_panic_tripwire.h:212
MHD_PANIC_TRIPWIRE_NORETURN_
#define MHD_PANIC_TRIPWIRE_NORETURN_
Definition
mhd_panic_tripwire.h:184
MHD_PANIC_TRIPWIRE_EXIT_STATUS
#define MHD_PANIC_TRIPWIRE_EXIT_STATUS
Definition
mhd_panic_tripwire.h:138
mhd_panic_tripwire_panic_cb_
static void mhd_panic_tripwire_panic_cb_(void *cls, const char *file, unsigned int line, const char *reason)
Definition
mhd_panic_tripwire.h:376
mhd_panic_tripwire_wr_num_
static void mhd_panic_tripwire_wr_num_(unsigned long val)
Definition
mhd_panic_tripwire.h:282
mhd_panic_tripwire_busy_
static volatile sig_atomic_t mhd_panic_tripwire_busy_
Definition
mhd_panic_tripwire.h:204
src
microhttpd
mhd_panic_tripwire.h
Generated by
1.17.0