mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-24 21:52:17 +00:00
BUILD: debug: work around gcc-12 excessive -Warray-bounds warnings
As was first reported by Ilya in issue #1513, compiling with gcc-12 adds warnings about size 0 around each BUG_ON() call due to the ABORT_NOW() macro that tries to dereference pointer value 1. The problem is known, seems to be complex inside gcc and could only be worked around for now by adjusting a pointer limit so that the warning still catches NULL derefs in the first page but not other values commonly used in kernels and boot loaders: https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=91f7d7e1b It's described in more details here: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104657 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99578 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103768 And some projects had to work around it using various approaches, some of which are described in the bugs reports above, plus another one here: https://mail.coreboot.org/hyperkitty/list/seabios@seabios.org/thread/HLK3BHP2T3FN6FZ46BIPIK3VD5FOU74Z/ In haproxy we can hide it by hiding the pointer in a DISGUISE() macro, but this forces the pointer to be loaded into a register, so that register is lost precisely where we want to get the maximum of them. In our case we purposely use a low-value non-null pointer because: - it's mandatory that this value fits within an unmapped page and only the lowest one has this property - we really want to avoid register loads for the address, as these will be lost and will complicate the bug analysis, and they tend to be used for large addresses (i.e. instruction length limit). - the compiler may decide to optimize away the null deref when it sees it (seen in the past already) As such, the current workaround merged in gcc-12 is not effective for us. Another approach consists in using pragmas to silently disable -Warray-bounds and -Wnull-dereference only for this part. The problem is that pragmas cannot be placed into macros. The resulting solution consists in defining a forced-inlined function only to trigger the crash, and surround the dereference with pragmas, themselves conditionned to gcc >= 5 since older versions don't understand them (but they don't complain on the dereference at least). This way the code remains the same even at -O0, without the stack pointer being modified nor any address register being modified on common archs (x86 at least). A variation could have been to rely on __builtin_trap() but it's not everywhere and it behaves differently on different platforms (undefined opcode or a nasty abort()) while the segv remains uniform and effective. This may need to be backported to older releases once users start to complain about gcc-12 breakage.
This commit is contained in:
parent
393e42ae5f
commit
8a0fd3a36c
@ -40,14 +40,28 @@
|
||||
|
||||
#define DUMP_TRACE() do { extern void ha_backtrace_to_stderr(void); ha_backtrace_to_stderr(); } while (0)
|
||||
|
||||
static inline __attribute((always_inline)) void ha_crash_now(void)
|
||||
{
|
||||
#if __GNUC_PREREQ__(5, 0)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#pragma GCC diagnostic ignored "-Wnull-dereference"
|
||||
#endif
|
||||
*(volatile char *)1 = 0;
|
||||
#if __GNUC_PREREQ__(5, 0)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
my_unreachable();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_USE_ABORT
|
||||
/* abort() is better recognized by code analysis tools */
|
||||
#define ABORT_NOW() do { DUMP_TRACE(); abort(); } while (0)
|
||||
#else
|
||||
/* More efficient than abort() because it does not mangle the
|
||||
* stack and stops at the exact location we need.
|
||||
*/
|
||||
#define ABORT_NOW() do { DUMP_TRACE(); (*(volatile int*)1=0); my_unreachable(); } while (0)
|
||||
* stack and stops at the exact location we need.
|
||||
*/
|
||||
#define ABORT_NOW() do { DUMP_TRACE(); ha_crash_now(); } while (0)
|
||||
#endif
|
||||
|
||||
/* This is the generic low-level macro dealing with conditional warnings and
|
||||
|
Loading…
Reference in New Issue
Block a user