/* * include/haproxy/bug.h * Assertions and instant crash macros needed everywhere. * * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _HAPROXY_BUG_H #define _HAPROXY_BUG_H #include /* quick debugging hack, should really be removed ASAP */ #ifdef DEBUG_FULL #define DPRINTF(x...) fprintf(x) #else #define DPRINTF(x...) #endif #ifdef DEBUG_USE_ABORT /* abort() is better recognized by code analysis tools */ #define ABORT_NOW() abort() #else /* More efficient than abort() because it does not mangle the * stack and stops at the exact location we need. */ #define ABORT_NOW() (*(volatile int*)1=0) #endif /* BUG_ON: complains if is true when DEBUG_STRICT or DEBUG_STRICT_NOCRASH * are set, does nothing otherwise. With DEBUG_STRICT in addition it immediately * crashes using ABORT_NOW() above. */ #if defined(DEBUG_STRICT) || defined(DEBUG_STRICT_NOCRASH) #if defined(DEBUG_STRICT) #define CRASH_NOW() ABORT_NOW() #else #define CRASH_NOW() #endif #define BUG_ON(cond) _BUG_ON(cond, __FILE__, __LINE__) #define _BUG_ON(cond, file, line) __BUG_ON(cond, file, line) #define __BUG_ON(cond, file, line) \ do { \ if (unlikely(cond)) { \ const char msg[] = "\nFATAL: bug condition \"" #cond "\" matched at " file ":" #line "\n"; \ DISGUISE(write(2, msg, __builtin_strlen(msg))); \ CRASH_NOW(); \ } \ } while (0) #else #undef CRASH_NOW #define BUG_ON(cond) #endif #if defined(DEBUG_MEM_STATS) #include #include /* Memory allocation statistics are centralized into a global "mem_stats" * section. This will not work with some linkers. */ enum { MEM_STATS_TYPE_UNSET = 0, MEM_STATS_TYPE_CALLOC, MEM_STATS_TYPE_FREE, MEM_STATS_TYPE_MALLOC, MEM_STATS_TYPE_REALLOC, MEM_STATS_TYPE_STRDUP, }; struct mem_stats { size_t calls; size_t size; const char *file; int line; int type; }; #undef calloc #define calloc(x,y) ({ \ size_t __x = (x); size_t __y = (y); \ static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \ .file = __FILE__, .line = __LINE__, \ .type = MEM_STATS_TYPE_CALLOC, \ }; \ __asm__(".globl __start_mem_stats"); \ __asm__(".globl __stop_mem_stats"); \ _HA_ATOMIC_ADD(&_.calls, 1); \ _HA_ATOMIC_ADD(&_.size, __x * __y); \ calloc(__x,__y); \ }) /* note: we can't redefine free() because we have a few variables and struct * members called like this. */ #undef __free #define __free(x) ({ \ void *__x = (x); \ static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \ .file = __FILE__, .line = __LINE__, \ .type = MEM_STATS_TYPE_FREE, \ }; \ __asm__(".globl __start_mem_stats"); \ __asm__(".globl __stop_mem_stats"); \ if (__x) \ _HA_ATOMIC_ADD(&_.calls, 1); \ free(__x); \ }) #undef malloc #define malloc(x) ({ \ size_t __x = (x); \ static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \ .file = __FILE__, .line = __LINE__, \ .type = MEM_STATS_TYPE_MALLOC, \ }; \ __asm__(".globl __start_mem_stats"); \ __asm__(".globl __stop_mem_stats"); \ _HA_ATOMIC_ADD(&_.calls, 1); \ _HA_ATOMIC_ADD(&_.size, __x); \ malloc(__x); \ }) #undef realloc #define realloc(x,y) ({ \ void *__x = (x); size_t __y = (y); \ static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \ .file = __FILE__, .line = __LINE__, \ .type = MEM_STATS_TYPE_REALLOC, \ }; \ __asm__(".globl __start_mem_stats"); \ __asm__(".globl __stop_mem_stats"); \ _HA_ATOMIC_ADD(&_.calls, 1); \ _HA_ATOMIC_ADD(&_.size, __y); \ realloc(__x,__y); \ }) #undef strdup #define strdup(x) ({ \ const char *__x = (x); size_t __y = strlen(__x); \ static struct mem_stats _ __attribute__((used,__section__("mem_stats"))) = { \ .file = __FILE__, .line = __LINE__, \ .type = MEM_STATS_TYPE_STRDUP, \ }; \ __asm__(".globl __start_mem_stats"); \ __asm__(".globl __stop_mem_stats"); \ _HA_ATOMIC_ADD(&_.calls, 1); \ _HA_ATOMIC_ADD(&_.size, __y); \ strdup(__x); \ }) #endif /* DEBUG_MEM_STATS*/ #endif /* _HAPROXY_BUG_H */ /* * Local variables: * c-indent-level: 8 * c-basic-offset: 8 * End: */