Coverage Report

Created: 2026-04-03 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/haproxy/include/haproxy/bug.h
Line
Count
Source
1
/*
2
 * include/haproxy/bug.h
3
 * Assertions and instant crash macros needed everywhere.
4
 *
5
 * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining
8
 * a copy of this software and associated documentation files (the
9
 * "Software"), to deal in the Software without restriction, including
10
 * without limitation the rights to use, copy, modify, merge, publish,
11
 * distribute, sublicense, and/or sell copies of the Software, and to
12
 * permit persons to whom the Software is furnished to do so, subject to
13
 * the following conditions:
14
 *
15
 * The above copyright notice and this permission notice shall be
16
 * included in all copies or substantial portions of the Software.
17
 *
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
 * OTHER DEALINGS IN THE SOFTWARE.
26
 */
27
28
#ifndef _HAPROXY_BUG_H
29
#define _HAPROXY_BUG_H
30
31
#include <stddef.h>
32
#include <sys/types.h>
33
#include <haproxy/atomic.h>
34
#include <haproxy/compiler.h>
35
36
/* quick debugging hack, should really be removed ASAP */
37
#ifdef DEBUG_FULL
38
#define DPRINTF(x...) fprintf(x)
39
#else
40
#define DPRINTF(x...)
41
#endif
42
43
/* Let's make DEBUG_STRESS equal to zero if not set or not valid, or to
44
 * 1 if set. This way it is always set and should be easy to use in "if ()"
45
 * statements without requiring ifdefs, while remaining compatible with
46
 * "#if DEBUG_STRESS > 0". We also force DEBUG_STRICT and DEBUG_STRICT_ACTION
47
 * when stressed.
48
 */
49
#if !defined(DEBUG_STRESS)
50
# define DEBUG_STRESS 0
51
#elif DEBUG_STRESS != 0
52
# undef DEBUG_STRESS
53
# define DEBUG_STRESS 1        // make sure comparison >0 always works
54
# undef DEBUG_STRICT
55
# define DEBUG_STRICT 2        // enable BUG_ON
56
# undef DEBUG_STRICT_ACTION
57
# define DEBUG_STRICT_ACTION 3 // enable crash on match
58
#endif
59
60
0
#define DUMP_TRACE() do { extern void ha_backtrace_to_stderr(void); ha_backtrace_to_stderr(); } while (0)
61
62
/* First, let's try to handle some arch-specific crashing methods. We prefer
63
 * the macro to the function because when opening the core, the debugger will
64
 * directly show the calling point (e.g. the BUG_ON() condition) based on the
65
 * line number, while the function will create new line numbers. But the
66
 * function is needed e.g. if some pragmas are needed.
67
 */
68
69
#if defined(__i386__) || defined(__x86_64__)
70
0
#define ha_crash_now() do {           \
71
0
    /* ud2 opcode: 2 bytes, raises illegal instruction */ \
72
0
    __asm__ volatile(".byte 0x0f,0x0b\n");      \
73
0
    DO_NOT_FOLD();           \
74
0
    my_unreachable();         \
75
0
  } while (0)
76
77
#elif defined(__aarch64__)
78
#define ha_crash_now() do {           \
79
    /* udf#imm16: 4 bytes (), raises illegal instruction */ \
80
    __asm__ volatile(".byte 0x00,0x00,0x00,0x00\n");  \
81
    DO_NOT_FOLD();            \
82
    my_unreachable();         \
83
  } while (0)
84
85
#else // not x86
86
87
/* generic implementation, causes a segfault */
88
static inline __attribute((always_inline,noreturn,unused)) void ha_crash_now(void)
89
{
90
#if __GNUC_PREREQ__(5, 0)
91
#pragma GCC diagnostic push
92
#pragma GCC diagnostic ignored "-Warray-bounds"
93
#if __GNUC_PREREQ__(6, 0)
94
#pragma GCC diagnostic ignored "-Wnull-dereference"
95
#endif
96
#endif
97
  *(volatile char *)1 = 0;
98
#if __GNUC_PREREQ__(5, 0)
99
#pragma GCC diagnostic pop
100
#endif
101
  DO_NOT_FOLD();
102
  my_unreachable();
103
}
104
105
#endif // end of arch-specific ha_crash_now() definitions
106
107
108
/* ABORT_NOW() usually takes no argument and will cause the program to abort
109
 * exactly where it is. We prefer to emit an invalid instruction to preserve
110
 * all registers, but it may fall back to a regular abort depending on the
111
 * platform. An optional argument can be a message string that will cause
112
 * the emission of a message saying "ABORT at" followed by the file and line
113
 * number then that message followed by a final line feed. This can be helpful
114
 * in situations where the core cannot be retrieved for example. However it
115
 * will definitely cause the loss of some registers, so should be avoided when
116
 * not strictly necessary.
117
 */
118
#define ABORT_NOW(...)              \
119
0
  _ABORT_NOW(__FILE__, __LINE__, __VA_ARGS__)
120
121
#define _ABORT_NOW(file, line, ...)         \
122
0
  __ABORT_NOW(file, line, __VA_ARGS__)
123
124
#ifdef DEBUG_USE_ABORT
125
/* abort() is better recognized by code analysis tools */
126
127
/* abort() is generally tagged noreturn, so there's no 100% safe way to prevent
128
 * the compiler from doing a tail-merge here. Tests show that stopping folding
129
 * just before calling abort() does work in practice at -O2, increasing the
130
 * number of abort() calls in h3.o from 18 to 26, probably because there's no
131
 * more savings to be made by replacing a call with a jump. However, as -Os it
132
 * drops to 5 regardless of the build option. In order to help here, instead we
133
 * wrap abort() into another function, with the line number stored into a local
134
 * variable on the stack and we pretend to use it, so that unwinding the stack
135
 * from abort() will reveal its value even if the call was folded.
136
 */
137
static __attribute__((noinline,noreturn,unused)) void abort_with_line(uint line)
138
{
139
  DISGUISE(&line);
140
  abort();
141
}
142
143
#define __ABORT_NOW(file, line, ...) do {       \
144
    extern ssize_t write(int, const void *, size_t);  \
145
    extern size_t strlen(const char *s);      \
146
    const char *msg;          \
147
    if (sizeof("" __VA_ARGS__) > 1)       \
148
      complain(NULL, "\nABORT at " file ":" #line ": " __VA_ARGS__ "\n", 1); \
149
    DUMP_TRACE();           \
150
    msg = "\n"            \
151
          "Hint: when reporting this bug to developers, please check if a core file was\n" \
152
          "      produced, open it with 'gdb', issue 'bt' to produce a backtrace for the\n" \
153
          "      current thread only, then join it with the bug report.\n"; \
154
    DISGUISE(write(2, msg, strlen(msg)));     \
155
    abort_with_line(__LINE__);        \
156
  } while (0)
157
#else
158
/* More efficient than abort() because it does not mangle the
159
 * stack and stops at the exact location we need.
160
 */
161
0
#define __ABORT_NOW(file, line, ...) do {       \
162
0
    extern ssize_t write(int, const void *, size_t);  \
163
0
    extern size_t strlen(const char *s);      \
164
0
    const char *msg;          \
165
0
    if (sizeof("" __VA_ARGS__) > 1)       \
166
0
      complain(NULL, "\nABORT at " file ":" #line ": " __VA_ARGS__ "\n", 1); \
167
0
    DUMP_TRACE();           \
168
0
    msg = "\n"            \
169
0
          "Hint: when reporting this bug to developers, please check if a core file was\n" \
170
0
          "      produced, open it with 'gdb', issue 'bt' to produce a backtrace for the\n" \
171
0
          "      current thread only, then join it with the bug report.\n"; \
172
0
    DISGUISE(write(2, msg, strlen(msg)));     \
173
0
    ha_crash_now();           \
174
0
  } while (0)
175
#endif
176
177
/* Counting the number of matches on a given BUG_ON()/WARN_ON()/CHECK_IF()/
178
 * COUNT_IF() invocation requires a special section ("dbg_cnt") hence a modern
179
 * linker.
180
 */
181
extern unsigned int debug_enable_counters;
182
183
#if !defined(USE_OBSOLETE_LINKER)
184
185
/* type of checks that can be verified. We cannot really distinguish between
186
 * BUG/WARN/CHECK_IF as they all pass through __BUG_ON() at a different level,
187
 * but there's at least a difference between __BUG_ON() and __BUG_ON_ONCE()
188
 * (and of course COUNT_IF).
189
 */
190
enum debug_counter_type {
191
  DBG_BUG,
192
  DBG_BUG_ONCE,
193
  DBG_COUNT_IF,
194
  DBG_GLITCH,
195
  DBG_COUNTER_TYPES // must be last
196
};
197
198
/* this is the struct that we store in section "dbg_cnt". Better keep it
199
 * well aligned.
200
 */
201
struct debug_count {
202
  const char *file;
203
  const char *func;
204
  const char *desc;
205
  uint16_t    line;
206
  uint8_t     type;
207
  /* one-byte hole here */
208
  uint32_t   count;
209
};
210
211
/* Declare a section for condition counters. The start and stop pointers are
212
 * set by the linker itself, which is why they're declared extern here. The
213
 * weak attribute is used so that we declare them ourselves if the section is
214
 * empty. The corresponding section must contain exclusively struct debug_count
215
 * to make sure each location may safely be visited by incrementing a pointer.
216
 */
217
extern __attribute__((__weak__)) struct debug_count __start_dbg_cnt HA_SECTION_START("dbg_cnt");
218
extern __attribute__((__weak__)) struct debug_count __stop_dbg_cnt  HA_SECTION_STOP("dbg_cnt");
219
220
/* This macro adds a pass counter at the line where it's declared. It can be
221
 * used by the various BUG_ON, COUNT_IF etc flavors. The condition is only
222
 * passed for the sake of being turned into a string; the caller is expected
223
 * to have already verified it.
224
 */
225
0
#define __DBG_COUNT(_cond, _file, _line, _type, ...) do {     \
226
0
    static struct debug_count __dbg_cnt_##_line HA_SECTION("dbg_cnt") \
227
0
    __attribute__((__used__,__aligned__(sizeof(void*)))) = {  \
228
0
      .file = _file,            \
229
0
      .func = __func__,         \
230
0
      .line = _line,            \
231
0
      .type = _type,            \
232
0
      .desc = (sizeof("" #_cond) > 1) ?     \
233
0
          (sizeof("" __VA_ARGS__) > 1) ?    \
234
0
          "\"" #_cond "\" [" __VA_ARGS__ "]" :    \
235
0
          "\"" #_cond "\"" :        \
236
0
        "" __VA_ARGS__,         \
237
0
      .count = 0,           \
238
0
    };                \
239
0
    HA_WEAK(__start_dbg_cnt);          \
240
0
    HA_WEAK(__stop_dbg_cnt);         \
241
0
    _HA_ATOMIC_INC(&__dbg_cnt_##_line.count);     \
242
0
  } while (0)
243
244
245
/* Matrix for DEBUG_COUNTERS:
246
 *    0 : only BUG_ON() and CHECK_IF() are reported (super rare)
247
 *    1 : COUNT_GLITCH() are also reported (rare)
248
 *        COUNT_IF() are also reported only if debug_enable_counters was set
249
 *    2 : COUNT_IF() are also reported unless debug_enable_counters was reset
250
 */
251
252
/* Core of the COUNT_IF() macro, checks the condition and counts one hit if
253
 * true. It's only enabled at DEBUG_COUNTERS >= 1, and enabled by default if
254
 * DEBUG_COUNTERS >= 2.
255
 */
256
# if defined(DEBUG_COUNTERS) && (DEBUG_COUNTERS >= 1)
257
#  define _COUNT_IF(cond, file, line, ...)            \
258
0
  (unlikely(cond) ? ({                \
259
0
    if (debug_enable_counters)           \
260
0
      __DBG_COUNT(cond, file, line, DBG_COUNT_IF, __VA_ARGS__); \
261
0
    1; /* let's return the true condition */        \
262
0
  }) : 0)
263
# else
264
#  define _COUNT_IF(cond, file, line, ...) DISGUISE(unlikely(cond) ? 1 : 0)
265
# endif
266
267
/* DEBUG_COUNTERS enables counting the number of glitches per line of code. The
268
 * condition is empty (nothing to write there), except maybe __VA_ARGS at the
269
 * end.
270
 */
271
# if !defined(DEBUG_COUNTERS) || (DEBUG_COUNTERS == 0)
272
#  define _COUNT_GLITCH(file, line, ...) do { } while (0)
273
# else
274
#  define _COUNT_GLITCH(file, line, ...) do {           \
275
    __DBG_COUNT(, file, line, DBG_GLITCH, __VA_ARGS__);   \
276
  } while (0)
277
# endif
278
279
#else /* USE_OBSOLETE_LINKER not defined below  */
280
# define __DBG_COUNT(cond, file, line, type, ...) do { } while (0)
281
# define _COUNT_IF(cond, file, line, ...) DISGUISE(unlikely(cond) ? 1 : 0)
282
# define _COUNT_GLITCH(file, line, ...) do { } while (0)
283
#endif
284
285
/* reports a glitch for current file and line, optionally with an explanation */
286
#define COUNT_GLITCH(...) _COUNT_GLITCH(__FILE__, __LINE__, __VA_ARGS__)
287
288
/* This is the generic low-level macro dealing with conditional warnings and
289
 * bugs. The caller decides whether to crash or not and what prefix and suffix
290
 * to pass. The macro returns the boolean value of the condition as an int for
291
 * the case where it wouldn't die. The <crash> flag is made of:
292
 *  - crash & 1: crash yes/no;
293
 *  - crash & 2: taint as bug instead of warn
294
 * The optional argument must be a single constant string that will be appended
295
 * on a second line after the condition message, to give a bit more context
296
 * about the problem.
297
 */
298
#define _BUG_ON(cond, file, line, crash, pfx, sfx, ...)       \
299
123k
  (void)(unlikely(cond) ? ({            \
300
0
    __DBG_COUNT(cond, file, line, DBG_BUG, __VA_ARGS__);     \
301
0
    __BUG_ON(cond, file, line, crash, pfx, sfx, __VA_ARGS__); \
302
0
    1; /* let's return the true condition */      \
303
123k
  }) : 0)
304
305
0
#define __BUG_ON(cond, file, line, crash, pfx, sfx, ...) do {   \
306
0
    const char *msg;          \
307
0
    if (sizeof("" __VA_ARGS__) > 1)       \
308
0
      msg ="\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n" __VA_ARGS__ "\n"; \
309
0
    else              \
310
0
      msg = "\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n"; \
311
0
    complain(NULL, msg, crash);       \
312
0
    if (crash & 1)           \
313
0
      ABORT_NOW();         \
314
0
    else              \
315
0
      DUMP_TRACE();         \
316
0
  } while (0)
317
318
/* This one is equivalent except that it only emits the message once by
319
 * maintaining a static counter. This may be used with warnings to detect
320
 * certain unexpected conditions in field. Later on, in cores it will be
321
 * possible to verify these counters.
322
 */
323
#define _BUG_ON_ONCE(cond, file, line, crash, pfx, sfx, ...)      \
324
0
  (void)(unlikely(cond) ? ({            \
325
0
    __DBG_COUNT(cond, file, line, DBG_BUG_ONCE, __VA_ARGS__);  \
326
0
    __BUG_ON_ONCE(cond, file, line, crash, pfx, sfx, __VA_ARGS__); \
327
0
    1; /* let's return the true condition */      \
328
0
  }) : 0)
329
330
0
#define __BUG_ON_ONCE(cond, file, line, crash, pfx, sfx, ...) do { \
331
0
    static int __match_count_##line;      \
332
0
    const char *msg;          \
333
0
    if (sizeof("" __VA_ARGS__) > 1)       \
334
0
      msg ="\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n" __VA_ARGS__ "\n"; \
335
0
    else              \
336
0
      msg = "\n" pfx "condition \"" #cond "\" matched at " file ":" #line "" sfx "\n"; \
337
0
    complain(&__match_count_##line, msg, crash);    \
338
0
    if (crash & 1)           \
339
0
      ABORT_NOW();         \
340
0
    else              \
341
0
      DUMP_TRACE();         \
342
0
  } while (0)
343
344
345
/* DEBUG_STRICT enables/disables runtime checks on condition <cond>
346
 * DEBUG_STRICT_ACTION indicates the level of verification on the rules when
347
 * <cond> is true:
348
 *
349
 *    macro   BUG_ON()    WARN_ON()    CHECK_IF()
350
 * value  0    warn         warn         warn
351
 *        1    CRASH        warn         warn
352
 *        2    CRASH        CRASH        warn
353
 *        3    CRASH        CRASH        CRASH
354
 */
355
356
/* The macros below are for general use */
357
#if defined(DEBUG_STRICT) && (DEBUG_STRICT > 0)
358
# if defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION < 1)
359
/* Lowest level: BUG_ON() warns, WARN_ON() warns, CHECK_IF() warns */
360
#  define BUG_ON(cond, ...)   _BUG_ON     (cond, __FILE__, __LINE__, 2, "WARNING: bug ",   " (not crashing but process is untrusted now, please report to developers)", __VA_ARGS__)
361
#  define WARN_ON(cond, ...)  _BUG_ON     (cond, __FILE__, __LINE__, 0, "WARNING: warn ",  " (please report to developers)", __VA_ARGS__)
362
#  define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__)
363
#  define COUNT_IF(cond, ...) _COUNT_IF   (cond, __FILE__, __LINE__, __VA_ARGS__)
364
# elif !defined(DEBUG_STRICT_ACTION) || (DEBUG_STRICT_ACTION == 1)
365
/* default level: BUG_ON() crashes, WARN_ON() warns, CHECK_IF() warns */
366
123k
#  define BUG_ON(cond, ...)   _BUG_ON     (cond, __FILE__, __LINE__, 3, "FATAL: bug ",     "", __VA_ARGS__)
367
0
#  define WARN_ON(cond, ...)  _BUG_ON     (cond, __FILE__, __LINE__, 0, "WARNING: warn ",  " (please report to developers)", __VA_ARGS__)
368
0
#  define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__)
369
0
#  define COUNT_IF(cond, ...) _COUNT_IF   (cond, __FILE__, __LINE__, __VA_ARGS__)
370
# elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION == 2)
371
/* Stricter level: BUG_ON() crashes, WARN_ON() crashes, CHECK_IF() warns */
372
#  define BUG_ON(cond, ...)   _BUG_ON     (cond, __FILE__, __LINE__, 3, "FATAL: bug ",     "", __VA_ARGS__)
373
#  define WARN_ON(cond, ...)  _BUG_ON     (cond, __FILE__, __LINE__, 1, "FATAL: warn ",    "", __VA_ARGS__)
374
#  define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__)
375
#  define COUNT_IF(cond, ...) _COUNT_IF   (cond, __FILE__, __LINE__, __VA_ARGS__)
376
# elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION >= 3)
377
/* Developer/CI level: BUG_ON() crashes, WARN_ON() crashes, CHECK_IF() crashes */
378
#  define BUG_ON(cond, ...)   _BUG_ON     (cond, __FILE__, __LINE__, 3, "FATAL: bug ",     "", __VA_ARGS__)
379
#  define WARN_ON(cond, ...)  _BUG_ON     (cond, __FILE__, __LINE__, 1, "FATAL: warn ",    "", __VA_ARGS__)
380
#  define CHECK_IF(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 1, "FATAL: check ",   "", __VA_ARGS__)
381
#  define COUNT_IF(cond, ...) _COUNT_IF   (cond, __FILE__, __LINE__, __VA_ARGS__)
382
# endif
383
#else
384
/* We want BUG_ON() to evaluate the expression sufficiently for next lines
385
 * of codes not to complain about suspicious dereferences for example.
386
 * GCC-11 tends to fail to validate that in combined expressions such as
387
 * "BUG_ON(!a || !b)", but it works fine when using a temporary assignment
388
 * like below, without hurting the generated code.
389
 */
390
#  define BUG_ON(cond, ...)   ({ typeof(cond) __cond = (cond); ASSUME(!__cond); })
391
#  define WARN_ON(cond, ...)  do { (void)sizeof(cond); } while (0)
392
#  define CHECK_IF(cond, ...) do { (void)sizeof(cond); } while (0)
393
#  define COUNT_IF(cond, ...) DISGUISE(cond)
394
#endif
395
396
/* These macros are only for hot paths and remain disabled unless DEBUG_STRICT is 2 or above.
397
 * Only developers/CI should use these levels as they may significantly impact performance by
398
 * enabling checks in sensitive areas.
399
 */
400
#if defined(DEBUG_STRICT) && (DEBUG_STRICT > 1)
401
# if defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION < 1)
402
/* Lowest level: BUG_ON() warns, CHECK_IF() warns */
403
#  define BUG_ON_HOT(cond, ...)   _BUG_ON_ONCE(cond, __FILE__, __LINE__, 2, "WARNING: bug ",   " (not crashing but process is untrusted now, please report to developers)", __VA_ARGS__)
404
#  define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__)
405
#  define COUNT_IF_HOT(cond, ...) _COUNT_IF   (cond, __FILE__, __LINE__, __VA_ARGS__)
406
# elif !defined(DEBUG_STRICT_ACTION) || (DEBUG_STRICT_ACTION < 3)
407
/* default level: BUG_ON() crashes, CHECK_IF() warns */
408
#  define BUG_ON_HOT(cond, ...)   _BUG_ON     (cond, __FILE__, __LINE__, 3, "FATAL: bug ",     "", __VA_ARGS__)
409
#  define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 0, "WARNING: check ", " (please report to developers)", __VA_ARGS__)
410
#  define COUNT_IF_HOT(cond, ...) _COUNT_IF   (cond, __FILE__, __LINE__, __VA_ARGS__)
411
# elif defined(DEBUG_STRICT_ACTION) && (DEBUG_STRICT_ACTION >= 3)
412
/* Developer/CI level: BUG_ON() crashes, CHECK_IF() crashes */
413
#  define BUG_ON_HOT(cond, ...)   _BUG_ON     (cond, __FILE__, __LINE__, 3, "FATAL: bug ",     "", __VA_ARGS__)
414
#  define CHECK_IF_HOT(cond, ...) _BUG_ON_ONCE(cond, __FILE__, __LINE__, 1, "FATAL: check ",   "", __VA_ARGS__)
415
#  define COUNT_IF_HOT(cond, ...) _COUNT_IF   (cond, __FILE__, __LINE__, __VA_ARGS__)
416
# endif
417
#else
418
/* Contrary to BUG_ON(), we do *NOT* want BUG_ON_HOT() to evaluate the
419
 * expression unless explicitly enabled, since it is located in hot code paths.
420
 * We just validate that the expression results in a valid type.
421
 */
422
3.48k
#  define BUG_ON_HOT(cond, ...)   do { (void)sizeof(cond) ; } while (0)
423
0
#  define CHECK_IF_HOT(cond, ...) do { (void)sizeof(cond) ; } while (0)
424
#  define COUNT_IF_HOT(cond, ...) DISGUISE(cond)
425
#endif
426
427
/* turn BUG_ON_STRESS() into a real statement when DEBUG_STRESS is set,
428
 * otherwise simply ignore it, at the risk of failing to notice if the
429
 * condition would build at all. We don't really care if BUG_ON_STRESS
430
 * doesn't always build, because it's meant to be used only in certain
431
 * scenarios, possibly requiring certain combinations of options. We
432
 * just want to be certain that the condition is not implemented at all
433
 * when not used, so as to encourage developers to put a lot of them at
434
 * zero cost.
435
 */
436
#if DEBUG_STRESS > 0
437
# define BUG_ON_STRESS(cond, ...)  BUG_ON(cond, __VA_ARGS__)
438
#else
439
0
# define BUG_ON_STRESS(cond, ...)  do { } while (0)
440
#endif
441
442
/* When not optimizing, clang won't remove that code, so only compile it in when optimizing */
443
#if defined(__GNUC__) && defined(__OPTIMIZE__)
444
#define HA_LINK_ERROR(what)                                                  \
445
0
  do {                                                                 \
446
0
    /* provoke a build-time error */                             \
447
0
    extern volatile int what;                                    \
448
0
    what = 1;                                                    \
449
0
  } while (0)
450
#else
451
#define HA_LINK_ERROR(what)                                                  \
452
  do {                                                                 \
453
  } while (0)
454
#endif /* __OPTIMIZE__ */
455
456
/* more reliable free() that clears the pointer */
457
0
#define ha_free(x) do {             \
458
0
    typeof(x) __x = (x);          \
459
0
    if (__builtin_constant_p((x)) || __builtin_constant_p(*(x))) { \
460
0
      HA_LINK_ERROR(call_to_ha_free_attempts_to_free_a_constant); \
461
0
    }             \
462
0
    free(*__x);           \
463
0
    *__x = NULL;            \
464
0
  } while (0)
465
466
/* describes a call place in the code, for example for tracing memory
467
 * allocations or task wakeups. These must be declared static const.
468
 */
469
struct ha_caller {
470
  const char *func;  // function name
471
  const char *file;  // file name
472
  uint16_t line;     // line number
473
  uint8_t what;      // description of the call, usage specific
474
  uint8_t arg8;      // optional argument, usage specific
475
  uint32_t arg32;    // optional argument, usage specific
476
};
477
478
#define MK_CALLER(_what, _arg8, _arg32)         \
479
0
  ({ static const struct ha_caller _ = {        \
480
0
    .func = __func__, .file = __FILE__, .line = __LINE__, \
481
0
    .what = _what, .arg8 = _arg8, .arg32 = _arg32 };  \
482
0
    &_; })
483
484
/* handle 'tainted' status */
485
enum tainted_flags {
486
  TAINTED_CONFIG_EXP_KW_DECLARED = 0x00000001,
487
  TAINTED_ACTION_EXP_EXECUTED    = 0x00000002,
488
  TAINTED_CLI_EXPERT_MODE        = 0x00000004,
489
  TAINTED_CLI_EXPERIMENTAL_MODE  = 0x00000008,
490
  TAINTED_WARN                   = 0x00000010, /* a WARN_ON triggered */
491
  TAINTED_BUG                    = 0x00000020, /* a BUG_ON triggered */
492
  TAINTED_SHARED_LIBS            = 0x00000040, /* a shared library was loaded */
493
  TAINTED_REDEFINITION           = 0x00000080, /* symbol redefinition detected */
494
  TAINTED_REPLACED_MEM_ALLOCATOR = 0x00000100, /* memory allocator was replaced using LD_PRELOAD */
495
  TAINTED_PANIC                  = 0x00000200, /* a panic dump has started */
496
  TAINTED_LUA_STUCK              = 0x00000400, /* stuck in a Lua context */
497
  TAINTED_LUA_STUCK_SHARED       = 0x00000800, /* stuck in a shared Lua context */
498
  TAINTED_MEM_TRIMMING_STUCK     = 0x00001000, /* stuck while trimming memory */
499
  TAINTED_WARN_BLOCKED_TRAFFIC   = 0x00002000, /* emitted a warning about blocked traffic */
500
};
501
502
/* this is a bit field made of TAINTED_*, and is declared in haproxy.c */
503
extern unsigned int tainted;
504
505
void complain(int *counter, const char *msg, int taint);
506
507
static inline unsigned int mark_tainted(const enum tainted_flags flag)
508
0
{
509
0
  return HA_ATOMIC_FETCH_OR(&tainted, flag);
510
0
}
Unexecuted instantiation: fuzz_h1_htx.c:mark_tainted
Unexecuted instantiation: chunk.c:mark_tainted
Unexecuted instantiation: debug.c:mark_tainted
Unexecuted instantiation: ebtree.c:mark_tainted
Unexecuted instantiation: fd.c:mark_tainted
Unexecuted instantiation: h1_htx.c:mark_tainted
Unexecuted instantiation: haproxy.c:mark_tainted
Unexecuted instantiation: http.c:mark_tainted
Unexecuted instantiation: http_htx.c:mark_tainted
Unexecuted instantiation: htx.c:mark_tainted
Unexecuted instantiation: init.c:mark_tainted
Unexecuted instantiation: limits.c:mark_tainted
Unexecuted instantiation: listener.c:mark_tainted
Unexecuted instantiation: log.c:mark_tainted
Unexecuted instantiation: mworker.c:mark_tainted
Unexecuted instantiation: peers.c:mark_tainted
Unexecuted instantiation: pool.c:mark_tainted
Unexecuted instantiation: proto_sockpair.c:mark_tainted
Unexecuted instantiation: protocol.c:mark_tainted
Unexecuted instantiation: proxy.c:mark_tainted
Unexecuted instantiation: resolvers.c:mark_tainted
Unexecuted instantiation: ring.c:mark_tainted
Unexecuted instantiation: sample.c:mark_tainted
Unexecuted instantiation: server.c:mark_tainted
Unexecuted instantiation: session.c:mark_tainted
Unexecuted instantiation: signal.c:mark_tainted
Unexecuted instantiation: sink.c:mark_tainted
Unexecuted instantiation: sock.c:mark_tainted
Unexecuted instantiation: sock_inet.c:mark_tainted
Unexecuted instantiation: stats.c:mark_tainted
Unexecuted instantiation: stconn.c:mark_tainted
Unexecuted instantiation: stick_table.c:mark_tainted
Unexecuted instantiation: stream.c:mark_tainted
Unexecuted instantiation: systemd.c:mark_tainted
Unexecuted instantiation: task.c:mark_tainted
Unexecuted instantiation: tcp_rules.c:mark_tainted
Unexecuted instantiation: tcpcheck.c:mark_tainted
Unexecuted instantiation: thread.c:mark_tainted
Unexecuted instantiation: time.c:mark_tainted
Unexecuted instantiation: tools.c:mark_tainted
Unexecuted instantiation: trace.c:mark_tainted
Unexecuted instantiation: uri_auth.c:mark_tainted
Unexecuted instantiation: vars.c:mark_tainted
Unexecuted instantiation: version.c:mark_tainted
Unexecuted instantiation: acl.c:mark_tainted
Unexecuted instantiation: action.c:mark_tainted
Unexecuted instantiation: activity.c:mark_tainted
Unexecuted instantiation: applet.c:mark_tainted
Unexecuted instantiation: arg.c:mark_tainted
Unexecuted instantiation: auth.c:mark_tainted
Unexecuted instantiation: backend.c:mark_tainted
Unexecuted instantiation: base64.c:mark_tainted
Unexecuted instantiation: buf.c:mark_tainted
Unexecuted instantiation: cfgparse-listen.c:mark_tainted
Unexecuted instantiation: cfgparse.c:mark_tainted
Unexecuted instantiation: channel.c:mark_tainted
Unexecuted instantiation: check.c:mark_tainted
Unexecuted instantiation: cli.c:mark_tainted
Unexecuted instantiation: clock.c:mark_tainted
Unexecuted instantiation: connection.c:mark_tainted
Unexecuted instantiation: counters.c:mark_tainted
Unexecuted instantiation: dgram.c:mark_tainted
Unexecuted instantiation: dict.c:mark_tainted
Unexecuted instantiation: dns.c:mark_tainted
Unexecuted instantiation: dns_ring.c:mark_tainted
Unexecuted instantiation: dynbuf.c:mark_tainted
Unexecuted instantiation: eb32tree.c:mark_tainted
Unexecuted instantiation: eb64tree.c:mark_tainted
Unexecuted instantiation: ebimtree.c:mark_tainted
Unexecuted instantiation: ebistree.c:mark_tainted
Unexecuted instantiation: ebmbtree.c:mark_tainted
Unexecuted instantiation: ebsttree.c:mark_tainted
Unexecuted instantiation: errors.c:mark_tainted
Unexecuted instantiation: event_hdl.c:mark_tainted
Unexecuted instantiation: extcheck.c:mark_tainted
Unexecuted instantiation: filters.c:mark_tainted
Unexecuted instantiation: fix.c:mark_tainted
Unexecuted instantiation: flt_http_comp.c:mark_tainted
Unexecuted instantiation: freq_ctr.c:mark_tainted
Unexecuted instantiation: frontend.c:mark_tainted
Unexecuted instantiation: guid.c:mark_tainted
Unexecuted instantiation: h1.c:mark_tainted
Unexecuted instantiation: haterm.c:mark_tainted
Unexecuted instantiation: http_ana.c:mark_tainted
Unexecuted instantiation: http_ext.c:mark_tainted
Unexecuted instantiation: http_fetch.c:mark_tainted
Unexecuted instantiation: http_rules.c:mark_tainted
Unexecuted instantiation: lb_chash.c:mark_tainted
Unexecuted instantiation: lb_fas.c:mark_tainted
Unexecuted instantiation: lb_fwlc.c:mark_tainted
Unexecuted instantiation: lb_fwrr.c:mark_tainted
Unexecuted instantiation: lb_map.c:mark_tainted
Unexecuted instantiation: lb_ss.c:mark_tainted
Unexecuted instantiation: mailers.c:mark_tainted
Unexecuted instantiation: mqtt.c:mark_tainted
Unexecuted instantiation: mux_spop.c:mark_tainted
Unexecuted instantiation: pattern.c:mark_tainted
Unexecuted instantiation: payload.c:mark_tainted
Unexecuted instantiation: pipe.c:mark_tainted
Unexecuted instantiation: proto_rhttp.c:mark_tainted
Unexecuted instantiation: proto_tcp.c:mark_tainted
Unexecuted instantiation: queue.c:mark_tainted
Unexecuted instantiation: regex.c:mark_tainted
Unexecuted instantiation: stats-file.c:mark_tainted
Unexecuted instantiation: stats-html.c:mark_tainted
Unexecuted instantiation: stats-json.c:mark_tainted
Unexecuted instantiation: stats-proxy.c:mark_tainted
Unexecuted instantiation: cache.c:mark_tainted
Unexecuted instantiation: cfgcond.c:mark_tainted
Unexecuted instantiation: cfgparse-global.c:mark_tainted
Unexecuted instantiation: compression.c:mark_tainted
Unexecuted instantiation: fcgi-app.c:mark_tainted
Unexecuted instantiation: flt_spoe.c:mark_tainted
Unexecuted instantiation: lru.c:mark_tainted
Unexecuted instantiation: shctx.c:mark_tainted
511
512
static inline unsigned int get_tainted()
513
0
{
514
0
  return HA_ATOMIC_LOAD(&tainted);
515
0
}
Unexecuted instantiation: fuzz_h1_htx.c:get_tainted
Unexecuted instantiation: chunk.c:get_tainted
Unexecuted instantiation: debug.c:get_tainted
Unexecuted instantiation: ebtree.c:get_tainted
Unexecuted instantiation: fd.c:get_tainted
Unexecuted instantiation: h1_htx.c:get_tainted
Unexecuted instantiation: haproxy.c:get_tainted
Unexecuted instantiation: http.c:get_tainted
Unexecuted instantiation: http_htx.c:get_tainted
Unexecuted instantiation: htx.c:get_tainted
Unexecuted instantiation: init.c:get_tainted
Unexecuted instantiation: limits.c:get_tainted
Unexecuted instantiation: listener.c:get_tainted
Unexecuted instantiation: log.c:get_tainted
Unexecuted instantiation: mworker.c:get_tainted
Unexecuted instantiation: peers.c:get_tainted
Unexecuted instantiation: pool.c:get_tainted
Unexecuted instantiation: proto_sockpair.c:get_tainted
Unexecuted instantiation: protocol.c:get_tainted
Unexecuted instantiation: proxy.c:get_tainted
Unexecuted instantiation: resolvers.c:get_tainted
Unexecuted instantiation: ring.c:get_tainted
Unexecuted instantiation: sample.c:get_tainted
Unexecuted instantiation: server.c:get_tainted
Unexecuted instantiation: session.c:get_tainted
Unexecuted instantiation: signal.c:get_tainted
Unexecuted instantiation: sink.c:get_tainted
Unexecuted instantiation: sock.c:get_tainted
Unexecuted instantiation: sock_inet.c:get_tainted
Unexecuted instantiation: stats.c:get_tainted
Unexecuted instantiation: stconn.c:get_tainted
Unexecuted instantiation: stick_table.c:get_tainted
Unexecuted instantiation: stream.c:get_tainted
Unexecuted instantiation: systemd.c:get_tainted
Unexecuted instantiation: task.c:get_tainted
Unexecuted instantiation: tcp_rules.c:get_tainted
Unexecuted instantiation: tcpcheck.c:get_tainted
Unexecuted instantiation: thread.c:get_tainted
Unexecuted instantiation: time.c:get_tainted
Unexecuted instantiation: tools.c:get_tainted
Unexecuted instantiation: trace.c:get_tainted
Unexecuted instantiation: uri_auth.c:get_tainted
Unexecuted instantiation: vars.c:get_tainted
Unexecuted instantiation: version.c:get_tainted
Unexecuted instantiation: acl.c:get_tainted
Unexecuted instantiation: action.c:get_tainted
Unexecuted instantiation: activity.c:get_tainted
Unexecuted instantiation: applet.c:get_tainted
Unexecuted instantiation: arg.c:get_tainted
Unexecuted instantiation: auth.c:get_tainted
Unexecuted instantiation: backend.c:get_tainted
Unexecuted instantiation: base64.c:get_tainted
Unexecuted instantiation: buf.c:get_tainted
Unexecuted instantiation: cfgparse-listen.c:get_tainted
Unexecuted instantiation: cfgparse.c:get_tainted
Unexecuted instantiation: channel.c:get_tainted
Unexecuted instantiation: check.c:get_tainted
Unexecuted instantiation: cli.c:get_tainted
Unexecuted instantiation: clock.c:get_tainted
Unexecuted instantiation: connection.c:get_tainted
Unexecuted instantiation: counters.c:get_tainted
Unexecuted instantiation: dgram.c:get_tainted
Unexecuted instantiation: dict.c:get_tainted
Unexecuted instantiation: dns.c:get_tainted
Unexecuted instantiation: dns_ring.c:get_tainted
Unexecuted instantiation: dynbuf.c:get_tainted
Unexecuted instantiation: eb32tree.c:get_tainted
Unexecuted instantiation: eb64tree.c:get_tainted
Unexecuted instantiation: ebimtree.c:get_tainted
Unexecuted instantiation: ebistree.c:get_tainted
Unexecuted instantiation: ebmbtree.c:get_tainted
Unexecuted instantiation: ebsttree.c:get_tainted
Unexecuted instantiation: errors.c:get_tainted
Unexecuted instantiation: event_hdl.c:get_tainted
Unexecuted instantiation: extcheck.c:get_tainted
Unexecuted instantiation: filters.c:get_tainted
Unexecuted instantiation: fix.c:get_tainted
Unexecuted instantiation: flt_http_comp.c:get_tainted
Unexecuted instantiation: freq_ctr.c:get_tainted
Unexecuted instantiation: frontend.c:get_tainted
Unexecuted instantiation: guid.c:get_tainted
Unexecuted instantiation: h1.c:get_tainted
Unexecuted instantiation: haterm.c:get_tainted
Unexecuted instantiation: http_ana.c:get_tainted
Unexecuted instantiation: http_ext.c:get_tainted
Unexecuted instantiation: http_fetch.c:get_tainted
Unexecuted instantiation: http_rules.c:get_tainted
Unexecuted instantiation: lb_chash.c:get_tainted
Unexecuted instantiation: lb_fas.c:get_tainted
Unexecuted instantiation: lb_fwlc.c:get_tainted
Unexecuted instantiation: lb_fwrr.c:get_tainted
Unexecuted instantiation: lb_map.c:get_tainted
Unexecuted instantiation: lb_ss.c:get_tainted
Unexecuted instantiation: mailers.c:get_tainted
Unexecuted instantiation: mqtt.c:get_tainted
Unexecuted instantiation: mux_spop.c:get_tainted
Unexecuted instantiation: pattern.c:get_tainted
Unexecuted instantiation: payload.c:get_tainted
Unexecuted instantiation: pipe.c:get_tainted
Unexecuted instantiation: proto_rhttp.c:get_tainted
Unexecuted instantiation: proto_tcp.c:get_tainted
Unexecuted instantiation: queue.c:get_tainted
Unexecuted instantiation: regex.c:get_tainted
Unexecuted instantiation: stats-file.c:get_tainted
Unexecuted instantiation: stats-html.c:get_tainted
Unexecuted instantiation: stats-json.c:get_tainted
Unexecuted instantiation: stats-proxy.c:get_tainted
Unexecuted instantiation: cache.c:get_tainted
Unexecuted instantiation: cfgcond.c:get_tainted
Unexecuted instantiation: cfgparse-global.c:get_tainted
Unexecuted instantiation: compression.c:get_tainted
Unexecuted instantiation: fcgi-app.c:get_tainted
Unexecuted instantiation: flt_spoe.c:get_tainted
Unexecuted instantiation: lru.c:get_tainted
Unexecuted instantiation: shctx.c:get_tainted
516
517
#if defined(DEBUG_MEM_STATS)
518
#include <stdlib.h>
519
#include <string.h>
520
521
/* Memory allocation statistics are centralized into a global "mem_stats"
522
 * section. This will not work with some linkers.
523
 */
524
enum {
525
  MEM_STATS_TYPE_UNSET  = 0,
526
  MEM_STATS_TYPE_CALLOC,
527
  MEM_STATS_TYPE_FREE,
528
  MEM_STATS_TYPE_MALLOC,
529
  MEM_STATS_TYPE_REALLOC,
530
  MEM_STATS_TYPE_STRDUP,
531
  MEM_STATS_TYPE_P_ALLOC,
532
  MEM_STATS_TYPE_P_FREE,
533
};
534
535
struct mem_stats {
536
  size_t calls;
537
  size_t size;
538
  struct ha_caller caller;
539
  const void *extra; // extra info specific to this call (e.g. pool ptr)
540
} ALIGNED(sizeof(void*));
541
542
#undef calloc
543
#define calloc(x,y)  ({             \
544
  size_t __x = (x); size_t __y = (y);       \
545
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
546
    .caller = {           \
547
      .file = __FILE__, .line = __LINE__,   \
548
      .what = MEM_STATS_TYPE_CALLOC,      \
549
      .func = __func__,       \
550
    },              \
551
  };                \
552
  HA_WEAK(__start_mem_stats);         \
553
  HA_WEAK(__stop_mem_stats);          \
554
  _HA_ATOMIC_INC(&_.calls);         \
555
  _HA_ATOMIC_ADD(&_.size, __x * __y);       \
556
  calloc(__x,__y);            \
557
})
558
559
/* note: we can't redefine free() because we have a few variables and struct
560
 * members called like this. This one may be used before a call to free(),
561
 * and when known, the size should be indicated, otherwise pass zero. The
562
 * pointer is used to know whether the call should be accounted for (null is
563
 * ignored).
564
 */
565
#undef will_free
566
#define will_free(x, y)  ({           \
567
  void *__x = (x); size_t __y = (y);        \
568
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
569
    .caller = {           \
570
      .file = __FILE__, .line = __LINE__,   \
571
      .what = MEM_STATS_TYPE_FREE,      \
572
      .func = __func__,       \
573
    },              \
574
  };                \
575
  HA_WEAK(__start_mem_stats);         \
576
  HA_WEAK(__stop_mem_stats);          \
577
  if (__x) {              \
578
    _HA_ATOMIC_INC(&_.calls);       \
579
    _HA_ATOMIC_ADD(&_.size, __y);       \
580
  }               \
581
})
582
583
#undef ha_free
584
#define ha_free(x)  ({              \
585
  typeof(x) __x = (x);            \
586
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
587
    .caller = {           \
588
      .file = __FILE__, .line = __LINE__,   \
589
      .what = MEM_STATS_TYPE_FREE,      \
590
      .func = __func__,       \
591
    },              \
592
  };                \
593
  HA_WEAK(__start_mem_stats);         \
594
  HA_WEAK(__stop_mem_stats);          \
595
  if (__builtin_constant_p((x)) || __builtin_constant_p(*(x))) {  \
596
    HA_LINK_ERROR(call_to_ha_free_attempts_to_free_a_constant); \
597
  }               \
598
  if (*__x)             \
599
    _HA_ATOMIC_INC(&_.calls);       \
600
  free(*__x);             \
601
  *__x = NULL;              \
602
})
603
604
#undef malloc
605
#define malloc(x)  ({             \
606
  size_t __x = (x);           \
607
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
608
    .caller = {           \
609
      .file = __FILE__, .line = __LINE__,   \
610
      .what = MEM_STATS_TYPE_MALLOC,      \
611
      .func = __func__,       \
612
    },              \
613
  };                \
614
  HA_WEAK(__start_mem_stats);         \
615
  HA_WEAK(__stop_mem_stats);          \
616
  _HA_ATOMIC_INC(&_.calls);         \
617
  _HA_ATOMIC_ADD(&_.size, __x);         \
618
  malloc(__x);              \
619
})
620
621
#undef realloc
622
#define realloc(x,y)  ({            \
623
  void *__x = (x); size_t __y = (y);        \
624
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
625
    .caller = {           \
626
      .file = __FILE__, .line = __LINE__,   \
627
      .what = MEM_STATS_TYPE_REALLOC,     \
628
      .func = __func__,       \
629
    },              \
630
  };                \
631
  HA_WEAK(__start_mem_stats);         \
632
  HA_WEAK(__stop_mem_stats);          \
633
  _HA_ATOMIC_INC(&_.calls);         \
634
  _HA_ATOMIC_ADD(&_.size, __y);         \
635
  realloc(__x,__y);           \
636
})
637
638
#undef strdup
639
#define strdup(x)  ({             \
640
  const char *__x = (x); size_t __y = strlen(__x);    \
641
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
642
    .caller = {           \
643
      .file = __FILE__, .line = __LINE__,   \
644
      .what = MEM_STATS_TYPE_STRDUP,      \
645
      .func = __func__,       \
646
    },              \
647
  };                \
648
  HA_WEAK(__start_mem_stats);         \
649
  HA_WEAK(__stop_mem_stats);          \
650
  _HA_ATOMIC_INC(&_.calls);         \
651
  _HA_ATOMIC_ADD(&_.size, __y);         \
652
  strdup(__x);              \
653
})
654
655
#undef ha_aligned_alloc
656
#define ha_aligned_alloc(a,s)  ({         \
657
  size_t __a = (a);           \
658
  size_t __s = (s);           \
659
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
660
    .caller = {           \
661
      .file = __FILE__, .line = __LINE__,   \
662
      .what = MEM_STATS_TYPE_MALLOC,      \
663
      .func = __func__,       \
664
    },              \
665
  };                \
666
  HA_WEAK(__start_mem_stats);         \
667
  HA_WEAK(__stop_mem_stats);          \
668
  _HA_ATOMIC_INC(&_.calls);         \
669
  _HA_ATOMIC_ADD(&_.size, __s);         \
670
  _ha_aligned_alloc(__a, __s);          \
671
})
672
673
#undef ha_aligned_zalloc
674
#define ha_aligned_zalloc(a,s)  ({          \
675
  size_t __a = (a);           \
676
  size_t __s = (s);           \
677
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
678
    .caller = {           \
679
      .file = __FILE__, .line = __LINE__,   \
680
      .what = MEM_STATS_TYPE_CALLOC,      \
681
      .func = __func__,       \
682
    },              \
683
  };                \
684
  HA_WEAK(__start_mem_stats);         \
685
  HA_WEAK(__stop_mem_stats);          \
686
  _HA_ATOMIC_INC(&_.calls);         \
687
  _HA_ATOMIC_ADD(&_.size, __s);         \
688
  _ha_aligned_zalloc(__a, __s);         \
689
})
690
691
#undef ha_aligned_alloc_safe
692
#define ha_aligned_alloc_safe(a,s)  ({          \
693
  size_t __a = (a);           \
694
  size_t __s = (s);           \
695
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
696
    .caller = {           \
697
      .file = __FILE__, .line = __LINE__,   \
698
      .what = MEM_STATS_TYPE_MALLOC,      \
699
      .func = __func__,       \
700
    },              \
701
  };                \
702
  HA_WEAK(__start_mem_stats);         \
703
  HA_WEAK(__stop_mem_stats);          \
704
  _HA_ATOMIC_INC(&_.calls);         \
705
  _HA_ATOMIC_ADD(&_.size, __s);         \
706
  _ha_aligned_alloc_safe(__a, __s);       \
707
})
708
709
#undef ha_aligned_zalloc_safe
710
#define ha_aligned_zalloc_safe(a,s)  ({         \
711
  size_t __a = (a);           \
712
  size_t __s = (s);           \
713
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
714
    .caller = {           \
715
      .file = __FILE__, .line = __LINE__,   \
716
      .what = MEM_STATS_TYPE_CALLOC,      \
717
      .func = __func__,       \
718
    },              \
719
  };                \
720
  HA_WEAK(__start_mem_stats);         \
721
  HA_WEAK(__stop_mem_stats);          \
722
  _HA_ATOMIC_INC(&_.calls);         \
723
  _HA_ATOMIC_ADD(&_.size, __s);         \
724
  _ha_aligned_zalloc_safe(__a, __s);        \
725
})
726
727
// Since the type is known, the .extra field will contain its name
728
#undef ha_aligned_alloc_typed
729
#define ha_aligned_alloc_typed(cnt,type)  ({        \
730
  size_t __a = __alignof__(type);         \
731
  size_t __s = ((size_t)cnt) * sizeof(type);      \
732
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
733
    .caller = {           \
734
      .file = __FILE__, .line = __LINE__,   \
735
      .what = MEM_STATS_TYPE_MALLOC,      \
736
      .func = __func__,       \
737
    },              \
738
    .extra = #type,           \
739
  };                \
740
  HA_WEAK(__start_mem_stats);         \
741
  HA_WEAK(__stop_mem_stats);          \
742
  _HA_ATOMIC_INC(&_.calls);         \
743
  _HA_ATOMIC_ADD(&_.size, __s);         \
744
  (type*)_ha_aligned_alloc(__a, __s);       \
745
})
746
747
// Since the type is known, the .extra field will contain its name
748
#undef ha_aligned_zalloc_typed
749
#define ha_aligned_zalloc_typed(cnt,type)  ({       \
750
  size_t __a = __alignof__(type);         \
751
  size_t __s = ((size_t)cnt) * sizeof(type);      \
752
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
753
    .caller = {           \
754
      .file = __FILE__, .line = __LINE__,   \
755
      .what = MEM_STATS_TYPE_CALLOC,      \
756
      .func = __func__,       \
757
    },              \
758
    .extra = #type,           \
759
  };                \
760
  HA_WEAK(__start_mem_stats);         \
761
  HA_WEAK(__stop_mem_stats);          \
762
  _HA_ATOMIC_INC(&_.calls);         \
763
  _HA_ATOMIC_ADD(&_.size, __s);         \
764
  (type*)_ha_aligned_zalloc_safe(__a, __s);     \
765
})
766
767
#undef ha_aligned_free
768
#define ha_aligned_free(x)  ({              \
769
  typeof(x) __x = (x);            \
770
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
771
    .caller = {           \
772
      .file = __FILE__, .line = __LINE__,   \
773
      .what = MEM_STATS_TYPE_FREE,      \
774
      .func = __func__,       \
775
    },              \
776
  };                \
777
  HA_WEAK(__start_mem_stats);         \
778
  HA_WEAK(__stop_mem_stats);          \
779
  if (__builtin_constant_p((x))) {  \
780
    HA_LINK_ERROR(call_to_ha_aligned_free_attempts_to_free_a_constant); \
781
  }               \
782
  if (__x)              \
783
    _HA_ATOMIC_INC(&_.calls);       \
784
  _ha_aligned_free(__x);            \
785
})
786
787
#undef ha_aligned_free_size
788
#define ha_aligned_free_size(p,s)  ({         \
789
  void *__p = (p); size_t __s = (s);        \
790
  static struct mem_stats _ __attribute__((used,__section__("mem_stats"),__aligned__(sizeof(void*)))) = { \
791
    .caller = {           \
792
      .file = __FILE__, .line = __LINE__,   \
793
      .what = MEM_STATS_TYPE_FREE,      \
794
      .func = __func__,       \
795
    },              \
796
  };                \
797
  HA_WEAK(__start_mem_stats);         \
798
  HA_WEAK(__stop_mem_stats);          \
799
  if (__builtin_constant_p((p))) {  \
800
    HA_LINK_ERROR(call_to_ha_aligned_free_attempts_to_free_a_constant); \
801
  }               \
802
  if (__p) {              \
803
    _HA_ATOMIC_INC(&_.calls);       \
804
    _HA_ATOMIC_ADD(&_.size, __s);       \
805
  }               \
806
  _ha_aligned_free(__p);            \
807
})
808
809
#else // DEBUG_MEM_STATS
810
811
#define will_free(x, y) do { } while (0)
812
0
#define ha_aligned_alloc(a,s) _ha_aligned_alloc(a, s)
813
0
#define ha_aligned_zalloc(a,s) _ha_aligned_zalloc(a, s)
814
#define ha_aligned_alloc_safe(a,s) _ha_aligned_alloc_safe(a, s)
815
#define ha_aligned_zalloc_safe(a,s) _ha_aligned_zalloc_safe(a, s)
816
0
#define ha_aligned_alloc_typed(cnt,type) ((type*)_ha_aligned_alloc(__alignof__(type), ((size_t)cnt) * sizeof(type)))
817
0
#define ha_aligned_zalloc_typed(cnt,type) ((type*)_ha_aligned_zalloc(__alignof__(type), ((size_t)cnt) * sizeof(type)))
818
0
#define ha_aligned_free(p) _ha_aligned_free(p)
819
0
#define ha_aligned_free_size(p,s) _ha_aligned_free(p)
820
821
#endif /* DEBUG_MEM_STATS*/
822
823
/* Add warnings to users of such functions. These will be reported at link time
824
 * indicating what file name and line used them. The goal is to remind their
825
 * users that these are extremely unsafe functions that never have a valid
826
 * reason for being used.
827
 */
828
#undef strcat
829
__attribute__warning("\n"
830
"  * WARNING! strcat() must never be used, because there is no convenient way\n"
831
"  *          to use it that is safe. Use memcpy() instead!\n")
832
extern char *strcat(char *__restrict dest, const char *__restrict src);
833
834
#undef strcpy
835
__attribute__warning("\n"
836
"  * WARNING! strcpy() must never be used, because there is no convenient way\n"
837
"  *          to use it that is safe. Use memcpy() or strlcpy2() instead!\n")
838
extern char *strcpy(char *__restrict dest, const char *__restrict src);
839
840
#undef strncat
841
__attribute__warning("\n"
842
"  * WARNING! strncat() must never be used, because there is no convenient way\n"
843
"  *          to use it that is safe. Use memcpy() instead!\n")
844
extern char *strncat(char *__restrict dest, const char *__restrict src, size_t n);
845
846
#undef sprintf
847
__attribute__warning("\n"
848
"  * WARNING! sprintf() must never be used, because there is no convenient way\n"
849
"  *          to use it that is safe. Use snprintf() instead!\n")
850
extern int sprintf(char *__restrict dest, const char *__restrict fmt, ...);
851
852
#if defined(_VA_LIST_DEFINED) || defined(_VA_LIST_DECLARED) || defined(_VA_LIST)
853
#undef vsprintf
854
__attribute__warning("\n"
855
"  * WARNING! vsprintf() must never be used, because there is no convenient way\n"
856
"  *          to use it that is safe. Use vsnprintf() instead!\n")
857
extern int vsprintf(char *__restrict dest, const char *__restrict fmt, va_list ap);
858
#endif
859
860
#endif /* _HAPROXY_BUG_H */
861
862
/*
863
 * Local variables:
864
 *  c-indent-level: 8
865
 *  c-basic-offset: 8
866
 * End:
867
 */