Bug 114116 - [14 Regression] Broken backtraces in bootstrapped x86_64 gcc
Summary: [14 Regression] Broken backtraces in bootstrapped x86_64 gcc
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 14.0
: P1 normal
Target Milestone: 14.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-02-26 14:56 UTC by Jakub Jelinek
Modified: 2024-03-05 09:43 UTC (History)
4 users (show)

See Also:
Host:
Target: x86_64-*-* i?86-*-*
Build:
Known to work:
Known to fail:
Last reconfirmed: 2024-02-26 00:00:00


Attachments
gcc14-pr114116.patch (1.67 KB, patch)
2024-02-26 16:29 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Jakub Jelinek 2024-02-26 14:56:05 UTC
The expected ICE on
void
foo (void)
{
  unsigned _BitInt (575) a = 3;
  __builtin_clzg (a);
}
with -fno-tree-dce -O1 (might go away soon when PR114044 is fixed) is from stage1-gcc/cc1
~/src/gcc/obj88/stage1-gcc/cc1 -quiet pr114044-2.c -fno-tree-dce -O1
during RTL pass: expand
pr114044-2.c: In function ‘foo’:
pr114044-2.c:5:3: internal compiler error: in expand_fn_using_insn, at internal-fn.cc:208
    5 |   __builtin_clzg (a);
      |   ^~~~~~~~~~~~~~~~~~
0x12e77f6 expand_fn_using_insn
	../../gcc/internal-fn.cc:208
0x12f6321 expand_direct_optab_fn
	../../gcc/internal-fn.cc:3817
0x12fce16 expand_CLZ
	../../gcc/internal-fn.def:444
0x12fdb14 expand_internal_call(internal_fn, gcall*)
	../../gcc/internal-fn.cc:4913
0x12fdb3f expand_internal_call(gcall*)
	../../gcc/internal-fn.cc:4921
0xf39343 expand_call_stmt
	../../gcc/cfgexpand.cc:2771
0xf3e2db expand_gimple_stmt_1
	../../gcc/cfgexpand.cc:3932
0xf3e99b expand_gimple_stmt
	../../gcc/cfgexpand.cc:4077
0xf48362 expand_gimple_basic_block
	../../gcc/cfgexpand.cc:6133
0xf4a9d2 execute
	../../gcc/cfgexpand.cc:6872
Please submit a full bug report, with preprocessed source (by using -freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.

but from gcc/cc1

during RTL pass: expand
pr114044-2.c: In function ‘foo’:
pr114044-2.c:5:3: internal compiler error: in expand_fn_using_insn, at internal-fn.cc:208
    5 |   __builtin_clzg (a);
      |   ^~~~~~~~~~~~~~~~~~
0x7d9246 expand_fn_using_insn
	../../gcc/internal-fn.cc:208

pr114044-2.c:5:3: internal compiler error: Segmentation fault
0x1554262 crash_signal
	../../gcc/toplev.cc:319
0x2b20320 x86_64_fallback_frame_state
	./md-unwind-support.h:63
0x2b20320 uw_frame_state_for
	../../../libgcc/unwind-dw2.c:1013
0x2b2165d _Unwind_Backtrace
	../../../libgcc/unwind.inc:303
0x2acbd69 backtrace_full
	../../libbacktrace/backtrace.c:127
0x2a32fa6 diagnostic_context::action_after_output(diagnostic_t)
	../../gcc/diagnostic.cc:781
0x2a331bb diagnostic_action_after_output(diagnostic_context*, diagnostic_t)
	../../gcc/diagnostic.h:1002
0x2a331bb diagnostic_context::report_diagnostic(diagnostic_info*)
	../../gcc/diagnostic.cc:1633
0x2a33543 diagnostic_impl
	../../gcc/diagnostic.cc:1767
0x2a33c26 internal_error(char const*, ...)
	../../gcc/diagnostic.cc:2225
0xe232c8 fancy_abort(char const*, int, char const*)
	../../gcc/diagnostic.cc:2336
0x7d9246 expand_fn_using_insn
	../../gcc/internal-fn.cc:208
Segmentation fault (core dumped)

I believe this is caused by the r14-8470 change.
The problem can be also seen when running the cc1 in the debugger.
When a breakpoint as added on fancy_abort (.gdbinit normally does that), the backtrace still looks sane:
#0  fancy_abort (file=file@entry=0x2bd70fb "../../gcc/internal-fn.cc", line=line@entry=208, function=function@entry=0x2bd76cf "expand_fn_using_insn") at ../../gcc/diagnostic.cc:2313
#1  0x00000000007d9247 in expand_fn_using_insn (stmt=<optimized out>, icode=CODE_FOR_nothing, ninputs=1, noutputs=1) at ../../gcc/internal-fn.cc:208
#2  0x0000000000fcd1d0 in expand_call_stmt (stmt=0x7fffea307000) at ../../gcc/cfgexpand.cc:2771
#3  expand_gimple_stmt_1 (stmt=<gimple_call 0x7fffea307000>) at ../../gcc/cfgexpand.cc:3932
#4  expand_gimple_stmt (stmt=<gimple_call 0x7fffea307000>) at ../../gcc/cfgexpand.cc:4077
#5  0x0000000000fcdf18 in expand_gimple_basic_block (bb=<optimized out>, disable_tail_calls=false) at ../../gcc/cfgexpand.cc:6133
#6  0x0000000000fd059f in (anonymous namespace)::pass_expand::execute (this=<optimized out>, fun=<optimized out>) at ../../gcc/cfgexpand.cc:6872
#7  0x000000000140bff8 in execute_one_pass (pass=<opt_pass* 0x3924c60 "expand"(271)>) at ../../gcc/passes.cc:2646
#8  0x000000000140c890 in execute_pass_list_1 (pass=<opt_pass* 0x3924c60 "expand"(271)>) at ../../gcc/passes.cc:2755
#9  0x000000000140c8c9 in execute_pass_list (fn=0x7fffea302000, pass=<optimized out>) at ../../gcc/passes.cc:2766
#10 0x0000000001011a26 in cgraph_node::expand (this=<cgraph_node * const 0x7fffea144220 "foo"/0>) at ../../gcc/context.h:48
#11 cgraph_node::expand (this=<cgraph_node * const 0x7fffea144220 "foo"/0>) at ../../gcc/cgraphunit.cc:1798
#12 0x00000000010137fb in expand_all_functions () at ../../gcc/cgraphunit.cc:2028
#13 symbol_table::compile (this=0x7fffea130000) at ../../gcc/cgraphunit.cc:2402
#14 0x0000000001015e18 in symbol_table::compile (this=0x7fffea130000) at ../../gcc/cgraphunit.cc:2315
#15 symbol_table::finalize_compilation_unit (this=0x7fffea130000) at ../../gcc/cgraphunit.cc:2587
#16 0x0000000001554742 in compile_file () at ../../gcc/toplev.cc:476
#17 0x0000000000e281cc in do_compile () at ../../gcc/toplev.cc:2154
#18 toplev::main (this=this@entry=0x7fffffffdd4e, argc=<optimized out>, argc@entry=5, argv=<optimized out>, argv@entry=0x7fffffffde78) at ../../gcc/toplev.cc:2310
#19 0x0000000000e299de in main (argc=5, argv=0x7fffffffde78) at ../../gcc/main.cc:39
and on fancy_abort's
=> 0x0000000000e2320f <+0>:	sub    $0x18,%rsp
   0x0000000000e23213 <+4>:	mov    0x28e7fd6(%rip),%rax        # 0x370b1f0 <global_dc>
   0x0000000000e2321a <+11>:	mov    %rdi,%r12
   0x0000000000e2321d <+14>:	mov    %esi,%ebp
   0x0000000000e2321f <+16>:	mov    %rdx,%rbx
prologue single stepping through the functions shows still correct backtrace at 0x0000000000e2321d but stepping one more yields:
#0  0x0000000000e2321f in fancy_abort (file=file@entry=0x2bd70fb "../../gcc/internal-fn.cc", line=line@entry=208, function=function@entry=0x2bd76cf "expand_fn_using_insn")
    at ../../gcc/diagnostic.cc:2303
#1  0x00000000007d9247 in expand_fn_using_insn (stmt=<optimized out>, icode=<error reading variable: Cannot access memory at address 0x8c>, 
    ninputs=<error reading variable: Cannot access memory at address 0x98>, noutputs=1) at ../../gcc/internal-fn.cc:208
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

The bug is obvious.  The caller of fancy_abort, expand_fn_using_insn starts with
   0x000000000122f2e0 <+0>:	push   %rbp
   0x000000000122f2e1 <+1>:	mov    %rsp,%rbp
   0x000000000122f2e4 <+4>:	push   %r15
   0x000000000122f2e6 <+6>:	push   %r14
   0x000000000122f2e8 <+8>:	push   %r13
   0x000000000122f2ea <+10>:	push   %r12
   0x000000000122f2ec <+12>:	push   %rbx
   0x000000000122f2ed <+13>:	sub    $0x48,%rsp
in its unwind info says that CFA is based on the %rbp register:
0008a2c4 000000000000002c 0008a2c8 FDE cie=00000000 pc=000000000122f2e0..000000000122f695
  DW_CFA_advance_loc: 1 to 000000000122f2e1
  DW_CFA_def_cfa_offset: 16
  DW_CFA_offset: r6 (rbp) at cfa-16
  DW_CFA_advance_loc: 3 to 000000000122f2e4
  DW_CFA_def_cfa_register: r6 (rbp)
  DW_CFA_advance_loc: 13 to 000000000122f2f1
  DW_CFA_offset: r15 (r15) at cfa-24
  DW_CFA_offset: r14 (r14) at cfa-32
  DW_CFA_offset: r13 (r13) at cfa-40
  DW_CFA_offset: r12 (r12) at cfa-48
  DW_CFA_offset: r3 (rbx) at cfa-56
But then fancy_abort, being a noreturn function, since it doesn't bother to save call saved registers, doesn't save %rbp and so backtrace from it is impossible.

So, I think for the case where the user didn't use no_callee_saved_registers attribute we should be saving at least hard frame pointer if the noreturn function modifies it.
Backtraces still might not work properly if some caller decides to use some other call saved register as CFA or use it in the computation of CFA, but that should be fairly rare.  While using %rbp for CFA happens pretty much in every function which needs a frame pointer.  And it doesn't have to be the immediate caller, if the immediate caller doesn't use frame pointer and doesn't use %rbp register for anything, it can be its caller, etc.
Comment 1 Jakub Jelinek 2024-02-26 15:10:45 UTC
Maybe introduce TYPE_NO_CALLEE_SAVED_REGISTERS_EXCEPT_BP or something similar?
Comment 2 Jakub Jelinek 2024-02-26 16:29:21 UTC
Created attachment 57545 [details]
gcc14-pr114116.patch

This seems to fix it, so far tested just on the small testcase, back to the expected backtrace there.
Comment 3 H.J. Lu 2024-02-26 16:37:57 UTC
(In reply to Jakub Jelinek from comment #2)
> Created attachment 57545 [details]
> gcc14-pr114116.patch
> 
> This seems to fix it, so far tested just on the small testcase, back to the
> expected backtrace there.

Should we check -g? Without -g, I don't think we need to save FP.
Comment 4 Andrew Pinski 2024-02-26 16:38:58 UTC
(In reply to H.J. Lu from comment #3)
> (In reply to Jakub Jelinek from comment #2)
> > Created attachment 57545 [details]
> > gcc14-pr114116.patch
> > 
> > This seems to fix it, so far tested just on the small testcase, back to the
> > expected backtrace there.
> 
> Should we check -g? Without -g, I don't think we need to save FP.

NO, the code generated with -g should be the same as without ...
Comment 5 Jakub Jelinek 2024-02-26 16:41:06 UTC
Yeah.  Not to mention, one can call backtrace even if -g0; you just don't get nice names for the addresses.  Without the patch you get crashes in the unwinder when doing backtrace.
Comment 6 H.J. Lu 2024-02-26 17:48:15 UTC
(In reply to Jakub Jelinek from comment #5)
> Yeah.  Not to mention, one can call backtrace even if -g0; you just don't
> get nice names for the addresses.  Without the patch you get crashes in the
> unwinder when doing backtrace.

Should we generate REG_CFA_UNDEFINED for unsaved callee-saved registers to
help unwinder:

https://patchwork.sourceware.org/project/gcc/list/?series=30327
Comment 7 Lukas Grätz 2024-02-29 13:58:02 UTC
(In reply to H.J. Lu from comment #6)
> (In reply to Jakub Jelinek from comment #5)
> > Yeah.  Not to mention, one can call backtrace even if -g0; you just don't
> > get nice names for the addresses.  Without the patch you get crashes in the
> > unwinder when doing backtrace.
> 
> Should we generate REG_CFA_UNDEFINED for unsaved callee-saved registers to
> help unwinder:
> 
> https://patchwork.sourceware.org/project/gcc/list/?series=30327

Yes. Also for gdb this is needed.

Perhaps I did something wrong. On my computer, I could get the first patch working to save rbp, I also applied the patch which should omit the .cfi_undefined. But somehow, I still not get .cfi_undefined for any of the examples.


$ ./gcc/host-x86_64-pc-linux-gnu/gcc/cc1 -O3 gcc/gcc/testsuite/gcc.target/i386/pr38534-7.c -o pr38534-7.S

$ cat pr38534-7.S
[...]
no_return_to_caller:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movl	$array+67108860, %eax
	xorl	%r13d, %r13d
[...]


The ".cfi_undefined 13" is still missing...
Comment 8 H.J. Lu 2024-02-29 14:21:06 UTC
(In reply to Lukas Grätz from comment #7)
> (In reply to H.J. Lu from comment #6)
> > (In reply to Jakub Jelinek from comment #5)
> > > Yeah.  Not to mention, one can call backtrace even if -g0; you just don't
> > > get nice names for the addresses.  Without the patch you get crashes in the
> > > unwinder when doing backtrace.
> > 
> > Should we generate REG_CFA_UNDEFINED for unsaved callee-saved registers to
> > help unwinder:
> > 
> > https://patchwork.sourceware.org/project/gcc/list/?series=30327
> 
> Yes. Also for gdb this is needed.
> 
> Perhaps I did something wrong. On my computer, I could get the first patch
> working to save rbp, I also applied the patch which should omit the
> .cfi_undefined. But somehow, I still not get .cfi_undefined for any of the
> examples.
> 
> 
> $ ./gcc/host-x86_64-pc-linux-gnu/gcc/cc1 -O3
> gcc/gcc/testsuite/gcc.target/i386/pr38534-7.c -o pr38534-7.S
> 
> $ cat pr38534-7.S
> [...]
> no_return_to_caller:
> .LFB0:
> 	.cfi_startproc
> 	pushq	%rbp
> 	.cfi_def_cfa_offset 16
> 	.cfi_offset 6, -16
> 	movl	$array+67108860, %eax
> 	xorl	%r13d, %r13d
> [...]
> 
> 
> The ".cfi_undefined 13" is still missing...

It is generated only when -g is used.
Comment 9 Lukas Grätz 2024-02-29 14:31:20 UTC
(In reply to H.J. Lu from comment #8)
> (In reply to Lukas Grätz from comment #7)
> > (In reply to H.J. Lu from comment #6)
> > > (In reply to Jakub Jelinek from comment #5)
> > > > Yeah.  Not to mention, one can call backtrace even if -g0; you just don't
> > > > get nice names for the addresses.  Without the patch you get crashes in the
> > > > unwinder when doing backtrace.
> > > 
> > > Should we generate REG_CFA_UNDEFINED for unsaved callee-saved registers to
> > > help unwinder:
> > > 
> > > https://patchwork.sourceware.org/project/gcc/list/?series=30327
> > 
> > Yes. Also for gdb this is needed.
> > 
> > Perhaps I did something wrong. On my computer, I could get the first patch
> > working to save rbp, I also applied the patch which should omit the
> > .cfi_undefined. But somehow, I still not get .cfi_undefined for any of the
> > examples.
> > 
> > 
> > $ ./gcc/host-x86_64-pc-linux-gnu/gcc/cc1 -O3
> > gcc/gcc/testsuite/gcc.target/i386/pr38534-7.c -o pr38534-7.S
> > 
> > $ cat pr38534-7.S
> > [...]
> > no_return_to_caller:
> > .LFB0:
> > 	.cfi_startproc
> > 	pushq	%rbp
> > 	.cfi_def_cfa_offset 16
> > 	.cfi_offset 6, -16
> > 	movl	$array+67108860, %eax
> > 	xorl	%r13d, %r13d
> > [...]
> > 
> > 
> > The ".cfi_undefined 13" is still missing...
> 
> It is generated only when -g is used.


Not on my computer. When I used -g I got:


no_return_to_caller:
.LFB0:
	.loc 1 16 1 view -0
	.cfi_startproc
	.loc 1 17 3 view .LVU1
	.loc 1 18 3 view .LVU2
.LVL0:
	.loc 1 18 26 discriminator 1 view .LVU3
	.loc 1 16 1 is_stmt 0 view .LVU4
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movl	$array+67108860, %eax
	.loc 1 21 31 view .LVU5
	xorl	%r13d, %r13d
	.loc 1 16 1 view .LVU6


Still no .cfi_undefined 13. In principle, it should also be generated without -g, as the rest of .cfi_offset and friends.
Comment 10 H.J. Lu 2024-02-29 14:32:48 UTC
(In reply to Lukas Grätz from comment #9)

> 
> Not on my computer. When I used -g I got:
> 
> 
> no_return_to_caller:
> .LFB0:
> 	.loc 1 16 1 view -0
> 	.cfi_startproc
> 	.loc 1 17 3 view .LVU1
> 	.loc 1 18 3 view .LVU2
> .LVL0:
> 	.loc 1 18 26 discriminator 1 view .LVU3
> 	.loc 1 16 1 is_stmt 0 view .LVU4
> 	pushq	%rbp
> 	.cfi_def_cfa_offset 16
> 	.cfi_offset 6, -16
> 	movl	$array+67108860, %eax
> 	.loc 1 21 31 view .LVU5
> 	xorl	%r13d, %r13d
> 	.loc 1 16 1 view .LVU6
> 
> 
> Still no .cfi_undefined 13. In principle, it should also be generated
> without -g, as the rest of .cfi_offset and friends.

Did you apply my patch?  I got

	.globl	no_return_to_caller
	.type	no_return_to_caller, @function
no_return_to_caller:
.LFB0:
	.file 1 "pr38534-1.c"
	.loc 1 16 1 view -0
	.cfi_startproc
	.loc 1 17 3 view .LVU1
	.loc 1 18 3 view .LVU2
.LVL0:
	.loc 1 18 26 discriminator 1 view .LVU3
	.loc 1 16 1 is_stmt 0 view .LVU4
	subq	$24, %rsp
	.cfi_undefined 15
	.cfi_undefined 14
	.cfi_undefined 13
	.cfi_undefined 12
	.cfi_undefined 6
...
Comment 11 Lukas Grätz 2024-02-29 14:42:29 UTC
(In reply to H.J. Lu from comment #10)
> (In reply to Lukas Grätz from comment #9)
> 
> > 
> > Not on my computer. When I used -g I got:
> > 
> > 
> > no_return_to_caller:
> > .LFB0:
> > 	.loc 1 16 1 view -0
> > 	.cfi_startproc
> > 	.loc 1 17 3 view .LVU1
> > 	.loc 1 18 3 view .LVU2
> > .LVL0:
> > 	.loc 1 18 26 discriminator 1 view .LVU3
> > 	.loc 1 16 1 is_stmt 0 view .LVU4
> > 	pushq	%rbp
> > 	.cfi_def_cfa_offset 16
> > 	.cfi_offset 6, -16
> > 	movl	$array+67108860, %eax
> > 	.loc 1 21 31 view .LVU5
> > 	xorl	%r13d, %r13d
> > 	.loc 1 16 1 view .LVU6
> > 
> > 
> > Still no .cfi_undefined 13. In principle, it should also be generated
> > without -g, as the rest of .cfi_offset and friends.
> 
> Did you apply my patch?  I got
> 
> 	.globl	no_return_to_caller
> 	.type	no_return_to_caller, @function
> no_return_to_caller:
> .LFB0:
> 	.file 1 "pr38534-1.c"
> 	.loc 1 16 1 view -0
> 	.cfi_startproc
> 	.loc 1 17 3 view .LVU1
> 	.loc 1 18 3 view .LVU2
> .LVL0:
> 	.loc 1 18 26 discriminator 1 view .LVU3
> 	.loc 1 16 1 is_stmt 0 view .LVU4
> 	subq	$24, %rsp
> 	.cfi_undefined 15
> 	.cfi_undefined 14
> 	.cfi_undefined 13
> 	.cfi_undefined 12
> 	.cfi_undefined 6
> ...

I applied it, double checked, make distclean, configure, make again.

But your result seems different. Have you applied Jakub Jelinek's patch to save %rbp? I applied both patches. Perhaps there was some subtle merge-conflict with the two patches.
Comment 12 H.J. Lu 2024-02-29 14:43:51 UTC
(In reply to Lukas Grätz from comment #11)
> 
> I applied it, double checked, make distclean, configure, make again.
> 
> But your result seems different. Have you applied Jakub Jelinek's patch to

No.

> save %rbp? I applied both patches. Perhaps there was some subtle
> merge-conflict with the two patches.

Please try just my patch.
Comment 13 Lukas Grätz 2024-03-01 04:39:58 UTC
(In reply to H.J. Lu from comment #12)
> (In reply to Lukas Grätz from comment #11)
> > 
> > I applied it, double checked, make distclean, configure, make again.
> > 
> > But your result seems different. Have you applied Jakub Jelinek's patch to
> 
> No.
> 
> > save %rbp? I applied both patches. Perhaps there was some subtle
> > merge-conflict with the two patches.
> 
> Please try just my patch.

Thanks, that worked!
Comment 14 Lukas Grätz 2024-03-01 06:44:53 UTC
(In reply to Jakub Jelinek from comment #2)
> Created attachment 57545 [details]
> gcc14-pr114116.patch
> 
> This seems to fix it, so far tested just on the small testcase, back to the
> expected backtrace there.

As I said in PR 38534, comment [1], the rsp could be saved to rbp due to an unknown-sized stack-frame:

	movq	%rsp, %rbp
	.cfi_def_cfa_register 6

Therefore, if we want the backtrace in such situations, we would need to save rbp, too, as your patch does. The patch might even not be enough, if there is the possibility that we could .cfi_def_cfa_register with a register other than rbp/6. In that case, the patch can be ignored and it is left to disable the optimization by default, as you already suggested, I think you already have a patch for that.

H.J. Lu's patch to emit .cfi_undefined is needed in any case. Only that both patches are currently incompatible.


There also seems to be a bug in libgcc/unwind-dw2.c:249, causing a SEGV when register values are unavailable due to .cfi_undefined. This is already known, as the comment there suggests. This happens during a call to glibc's backtrace(), even though the registers are not needed for the backtrace (in that case, gdb's backtrace is fine, glibc's backtrace crashes in libgcc). It should be possible to print best-effort-traces without crashing, in fact, calling backtrace() should never lead to a crash. Bug 103510 might be related and this should be fixed independently.

Thanks for the work putting in this and I am sorry for the mess on my side!

[1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38534#c45
Comment 15 GCC Commits 2024-03-05 09:26:29 UTC
The master branch has been updated by Jakub Jelinek <jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:8ee6d13e32279faf9ef4fd8eabfba0adfca0dfb9

commit r14-9313-g8ee6d13e32279faf9ef4fd8eabfba0adfca0dfb9
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Tue Mar 5 10:24:51 2024 +0100

    i386: For noreturn functions save at least the bp register if it is used [PR114116]
    
    As mentioned in the PR, on x86_64 currently a lot of ICEs end up
    with crashes in the unwinder like:
    during RTL pass: expand
    pr114044-2.c: In function âfooâ:
    pr114044-2.c:5:3: internal compiler error: in expand_fn_using_insn, at internal-fn.cc:208
        5 |   __builtin_clzg (a);
          |   ^~~~~~~~~~~~~~~~~~
    0x7d9246 expand_fn_using_insn
            ../../gcc/internal-fn.cc:208
    
    pr114044-2.c:5:3: internal compiler error: Segmentation fault
    0x1554262 crash_signal
            ../../gcc/toplev.cc:319
    0x2b20320 x86_64_fallback_frame_state
            ./md-unwind-support.h:63
    0x2b20320 uw_frame_state_for
            ../../../libgcc/unwind-dw2.c:1013
    0x2b2165d _Unwind_Backtrace
            ../../../libgcc/unwind.inc:303
    0x2acbd69 backtrace_full
            ../../libbacktrace/backtrace.c:127
    0x2a32fa6 diagnostic_context::action_after_output(diagnostic_t)
            ../../gcc/diagnostic.cc:781
    0x2a331bb diagnostic_action_after_output(diagnostic_context*, diagnostic_t)
            ../../gcc/diagnostic.h:1002
    0x2a331bb diagnostic_context::report_diagnostic(diagnostic_info*)
            ../../gcc/diagnostic.cc:1633
    0x2a33543 diagnostic_impl
            ../../gcc/diagnostic.cc:1767
    0x2a33c26 internal_error(char const*, ...)
            ../../gcc/diagnostic.cc:2225
    0xe232c8 fancy_abort(char const*, int, char const*)
            ../../gcc/diagnostic.cc:2336
    0x7d9246 expand_fn_using_insn
            ../../gcc/internal-fn.cc:208
    Segmentation fault (core dumped)
    
    The problem are the PR38534 r14-8470 changes which avoid saving call-saved
    registers in noreturn functions.  If such functions ever touch the
    bp register but because of the r14-8470 changes don't save it in the
    prologue, the caller or any other function in the backtrace uses a frame
    pointer and the noreturn function or anything it calls directly or
    indirectly calls backtrace, then the unwinder crashes, because bp register
    contains some unrelated value, but in the frames which do use frame pointer
    CFA is based on the bp register.
    
    In theory this could happen with any other call-saved register, e.g. code
    written by hand in assembly with .cfi_* directives could use any other
    call-saved register as register into which store the CFA or something
    related to that, but in reality at least compiler generated code and usual
    assembly probably just making sure bp doesn't contain garbage could be
    enough for backtrace purposes.  In the debugger of course it will not be
    enough, the values of the arguments etc. can be lost (if DW_CFA_undefined
    is emitted) or garbage.
    
    So, I think for noreturn function we should at least save the bp register
    if we use it.  If user asks for it using no_callee_saved_registers
    attribute, let's honor what is asked for (but then it is up to the user
    to make sure e.g. backtrace isn't called from the function or anything it
    calls).  As discussed in the PR, whether to save bp or not shouldn't be
    based on whether compiling with -g or -g0, because we don't want code
    generation changes without/with debugging, it would also break
    -fcompare-debug, and users can call backtrace(3), that doesn't use debug
    info, just unwind info, even backtrace_symbols{,_fd}(3) don't use debug info
    but just looks at dynamic symbol table.
    
    The patch also adds check for no_caller_saved_registers
    attribute in the implicit addition of not saving callee saved register
    in noreturn functions, because on I think
    __attribute__((no_caller_saved_registers, noreturn)) will otherwise
    error that no_caller_saved_registers and no_callee_saved_registers
    attributes are incompatible (but user didn't specify anything like that).
    
    2024-03-05  Jakub Jelinek  <jakub@redhat.com>
    
            PR target/114116
            * config/i386/i386.h (enum call_saved_registers_type): Add
            TYPE_NO_CALLEE_SAVED_REGISTERS_EXCEPT_BP enumerator.
            * config/i386/i386-options.cc (ix86_set_func_type): Remove
            has_no_callee_saved_registers variable, add no_callee_saved_registers
            instead, initialize it depending on whether it is
            no_callee_saved_registers function or not.  Don't set it if
            no_caller_saved_registers attribute is present.  Adjust users.
            * config/i386/i386.cc (ix86_function_ok_for_sibcall): Handle
            TYPE_NO_CALLEE_SAVED_REGISTERS_EXCEPT_BP like
            TYPE_NO_CALLEE_SAVED_REGISTERS.
            (ix86_save_reg): Handle TYPE_NO_CALLEE_SAVED_REGISTERS_EXCEPT_BP.
    
            * gcc.target/i386/pr38534-1.c: Allow push/pop of bp.
            * gcc.target/i386/pr38534-4.c: Likewise.
            * gcc.target/i386/pr38534-2.c: Likewise.
            * gcc.target/i386/pr38534-3.c: Likewise.
            * gcc.target/i386/pr114097-1.c: Likewise.
            * gcc.target/i386/stack-check-17.c: Expect no pop on ! ia32.
Comment 16 Jakub Jelinek 2024-03-05 09:43:20 UTC
Fixed.