Skip to content

Commit 074d0aa

Browse files
arndbgregkh
authored andcommitted
bug.h: work around GCC PR82365 in BUG()
[ Upstream commit 173a3ef ] Looking at functions with large stack frames across all architectures led me discovering that BUG() suffers from the same problem as fortify_panic(), which I've added a workaround for already. In short, variables that go out of scope by calling a noreturn function or __builtin_unreachable() keep using stack space in functions afterwards. A workaround that was identified is to insert an empty assembler statement just before calling the function that doesn't return. I'm adding a macro "barrier_before_unreachable()" to document this, and insert calls to that in all instances of BUG() that currently suffer from this problem. The files that saw the largest change from this had these frame sizes before, and much less with my patch: fs/ext4/inode.c:82:1: warning: the frame size of 1672 bytes is larger than 800 bytes [-Wframe-larger-than=] fs/ext4/namei.c:434:1: warning: the frame size of 904 bytes is larger than 800 bytes [-Wframe-larger-than=] fs/ext4/super.c:2279:1: warning: the frame size of 1160 bytes is larger than 800 bytes [-Wframe-larger-than=] fs/ext4/xattr.c:146:1: warning: the frame size of 1168 bytes is larger than 800 bytes [-Wframe-larger-than=] fs/f2fs/inode.c:152:1: warning: the frame size of 1424 bytes is larger than 800 bytes [-Wframe-larger-than=] net/netfilter/ipvs/ip_vs_core.c:1195:1: warning: the frame size of 1068 bytes is larger than 800 bytes [-Wframe-larger-than=] net/netfilter/ipvs/ip_vs_core.c:395:1: warning: the frame size of 1084 bytes is larger than 800 bytes [-Wframe-larger-than=] net/netfilter/ipvs/ip_vs_ftp.c:298:1: warning: the frame size of 928 bytes is larger than 800 bytes [-Wframe-larger-than=] net/netfilter/ipvs/ip_vs_ftp.c:418:1: warning: the frame size of 908 bytes is larger than 800 bytes [-Wframe-larger-than=] net/netfilter/ipvs/ip_vs_lblcr.c:718:1: warning: the frame size of 960 bytes is larger than 800 bytes [-Wframe-larger-than=] drivers/net/xen-netback/netback.c:1500:1: warning: the frame size of 1088 bytes is larger than 800 bytes [-Wframe-larger-than=] In case of ARC and CRIS, it turns out that the BUG() implementation actually does return (or at least the compiler thinks it does), resulting in lots of warnings about uninitialized variable use and leaving noreturn functions, such as: block/cfq-iosched.c: In function 'cfq_async_queue_prio': block/cfq-iosched.c:3804:1: error: control reaches end of non-void function [-Werror=return-type] include/linux/dmaengine.h: In function 'dma_maxpq': include/linux/dmaengine.h:1123:1: error: control reaches end of non-void function [-Werror=return-type] This makes them call __builtin_trap() instead, which should normally dump the stack and kill the current process, like some of the other architectures already do. I tried adding barrier_before_unreachable() to panic() and fortify_panic() as well, but that had very little effect, so I'm not submitting that patch. Vineet said: : For ARC, it is double win. : : 1. Fixes 3 -Wreturn-type warnings : : | ../net/core/ethtool.c:311:1: warning: control reaches end of non-void function : [-Wreturn-type] : | ../kernel/sched/core.c:3246:1: warning: control reaches end of non-void function : [-Wreturn-type] : | ../include/linux/sunrpc/svc_xprt.h:180:1: warning: control reaches end of : non-void function [-Wreturn-type] : : 2. bloat-o-meter reports code size improvements as gcc elides the : generated code for stack return. Link: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365 Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Arnd Bergmann <[email protected]> Acked-by: Vineet Gupta <[email protected]> [arch/arc] Tested-by: Vineet Gupta <[email protected]> [arch/arc] Cc: Mikael Starvik <[email protected]> Cc: Jesper Nilsson <[email protected]> Cc: Tony Luck <[email protected]> Cc: Fenghua Yu <[email protected]> Cc: Geert Uytterhoeven <[email protected]> Cc: "David S. Miller" <[email protected]> Cc: Christopher Li <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Kees Cook <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Josh Poimboeuf <[email protected]> Cc: Will Deacon <[email protected]> Cc: "Steven Rostedt (VMware)" <[email protected]> Cc: Mark Rutland <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]> Signed-off-by: Sasha Levin <[email protected]> [removed cris chunks - gregkh] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 39862cc commit 074d0aa

File tree

7 files changed

+35
-4
lines changed

7 files changed

+35
-4
lines changed

arch/arc/include/asm/bug.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ void die(const char *str, struct pt_regs *regs, unsigned long address);
2323

2424
#define BUG() do { \
2525
pr_warn("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
26-
dump_stack(); \
26+
barrier_before_unreachable(); \
27+
__builtin_trap(); \
2728
} while (0)
2829

2930
#define HAVE_ARCH_BUG

arch/ia64/include/asm/bug.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33

44
#ifdef CONFIG_BUG
55
#define ia64_abort() __builtin_trap()
6-
#define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0)
6+
#define BUG() do { \
7+
printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
8+
barrier_before_unreachable(); \
9+
ia64_abort(); \
10+
} while (0)
711

812
/* should this BUG be made generic? */
913
#define HAVE_ARCH_BUG

arch/m68k/include/asm/bug.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@
77
#ifndef CONFIG_SUN3
88
#define BUG() do { \
99
printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
10+
barrier_before_unreachable(); \
1011
__builtin_trap(); \
1112
} while (0)
1213
#else
1314
#define BUG() do { \
1415
printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
16+
barrier_before_unreachable(); \
1517
panic("BUG!"); \
1618
} while (0)
1719
#endif
1820
#else
1921
#define BUG() do { \
22+
barrier_before_unreachable(); \
2023
__builtin_trap(); \
2124
} while (0)
2225
#endif

arch/sparc/include/asm/bug.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@
88
void do_BUG(const char *file, int line);
99
#define BUG() do { \
1010
do_BUG(__FILE__, __LINE__); \
11+
barrier_before_unreachable(); \
1112
__builtin_trap(); \
1213
} while (0)
1314
#else
14-
#define BUG() __builtin_trap()
15+
#define BUG() do { \
16+
barrier_before_unreachable(); \
17+
__builtin_trap(); \
18+
} while (0)
1519
#endif
1620

1721
#define HAVE_ARCH_BUG

include/asm-generic/bug.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct bug_entry {
4747
#ifndef HAVE_ARCH_BUG
4848
#define BUG() do { \
4949
printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
50+
barrier_before_unreachable(); \
5051
panic("BUG!"); \
5152
} while (0)
5253
#endif

include/linux/compiler-gcc.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,15 @@
233233
#define annotate_unreachable()
234234
#endif
235235

236+
/*
237+
* calling noreturn functions, __builtin_unreachable() and __builtin_trap()
238+
* confuse the stack allocation in gcc, leading to overly large stack
239+
* frames, see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82365
240+
*
241+
* Adding an empty inline assembly before it works around the problem
242+
*/
243+
#define barrier_before_unreachable() asm volatile("")
244+
236245
/*
237246
* Mark a position in code as unreachable. This can be used to
238247
* suppress control flow warnings after asm blocks that transfer
@@ -243,7 +252,11 @@
243252
* unreleased. Really, we need to have autoconf for the kernel.
244253
*/
245254
#define unreachable() \
246-
do { annotate_unreachable(); __builtin_unreachable(); } while (0)
255+
do { \
256+
annotate_unreachable(); \
257+
barrier_before_unreachable(); \
258+
__builtin_unreachable(); \
259+
} while (0)
247260

248261
/* Mark a function definition as prohibited from being cloned. */
249262
#define __noclone __attribute__((__noclone__, __optimize__("no-tracer")))

include/linux/compiler.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
177177
# define barrier_data(ptr) barrier()
178178
#endif
179179

180+
/* workaround for GCC PR82365 if needed */
181+
#ifndef barrier_before_unreachable
182+
# define barrier_before_unreachable() do { } while (0)
183+
#endif
184+
180185
/* Unreachable code */
181186
#ifndef unreachable
182187
# define unreachable() do { } while (1)

0 commit comments

Comments
 (0)