When GCC is bootstrapped with -fsanitize=address, I got ERROR: AddressSanitizer: global-buffer-overflow on address 0x00000297d2e4 at pc 0xe64e63 [hjl@gnu-mic-2 gcc]$ addr2line -e cc1plus 0xe64e63 /export/gnu/import/git/gcc/gcc/dwarf2cfi.c:909 [hjl@gnu-mic-2 gcc]$
Only happens with -m32 on Linux/x86-64.
==8030==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00000297d2e4 at pc 0xe64e63 bp 0x7fffe2f360f0 sp 0x7fffe2f360e8 READ of size 4 at 0x00000297d2e4 thread T0 #0 0xe64e62 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0xe64e62) #1 0xe69740 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0xe69740) #2 0xe6aee8 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0xe6aee8) #3 0x146e649 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0x146e649) #4 0x146f008 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0x146f008) #5 0x146f02e (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0x146f02e) #6 0x146f02e (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0x146f02e) #7 0xda6389 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0xda6389) #8 0xdabc84 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0xdabc84) #9 0xdaceea (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0xdaceea) #10 0x85a67a (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0x85a67a) #11 0x16535f4 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0x16535f4) #12 0x1658083 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0x1658083) #13 0x3cdda21b44 (/lib64/libc.so.6+0x3cdda21b44) #14 0x5b66e0 (/export/build/gnu/gcc-asan/build-x86_64-linux/gcc/cc1plus+0x5b66e0) 0x00000297d2e4 is located 60 bytes to the left of global variable 'dbx_register_map' from '/export/gnu/import/git/gcc/gcc/config/i386/i386.c' (0x297d320) of size 324 0x00000297d2e4 is located 0 bytes to the right of global variable 'dbx64_register_map' from '/export/gnu/import/git/gcc/gcc/config/i386/i386.c' (0x297d1a0) of size 324 Shadow bytes around the buggy address: 0x000080527a00: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00 0x000080527a10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x000080527a20: 00 00 00 00 00 00 00 00 00 00 00 00 04 f9 f9 f9 0x000080527a30: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00 0x000080527a40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x000080527a50: 00 00 00 00 00 00 00 00 00 00 00 00[04]f9 f9 f9 0x000080527a60: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00 0x000080527a70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x000080527a80: 00 00 00 00 00 00 00 00 00 00 00 00 04 f9 f9 f9 0x000080527a90: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00 0x000080527aa0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Heap right redzone: fb Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack partial redzone: f4 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 ASan internal: fe ==8030==ABORTING
(gdb) f 0 #0 dwarf2out_frame_debug (insn=0x7ffff5980ca8) at /export/gnu/import/git/gcc/gcc/dwarf2cfi.c:2000 2000 fde->vdrap_reg = dwf_regno (n); (gdb) p n $2 = (rtx_def *) 0x7ffff597cd40 (gdb) call debug_rtx (n) (reg:SI 177) (gdb) call debug_rtx (insn) (insn/f 202 254 2 2 (set (mem/c:SI (plus:SI (reg/f:SI 6 bp) (const_int -48 [0xffffffffffffffd0])) [0 %sfp+-48 S4 A32]) (reg:SI 2 cx)) 86 {*movsi_internal} (expr_list:REG_CFA_SET_VDRAP (reg:SI 177) (nil))) reg:SI 177 isn't a hard register and there is no DWARF register for it.
It looks like a LRA bug on x86. x.ii.212r.ira has insn/f 202 3 2 2 (set (reg:SI 177) (reg:SI 2 cx)) 86 {*movsi_internal} (expr_list:REG_DEAD (reg:SI 2 cx) (expr_list:REG_CFA_SET_VDRAP (reg:SI 177) (nil)))) x.ii.213r.reload has (insn/f 202 3 2 2 (set (mem/c:SI (plus:SI (reg/f:SI 6 bp) (const_int -48 [0xffffffffffffffd0])) [0 %sfp+-48 S4 A32]) (reg:SI 2 cx)) 86 {*movsi_internal} (expr_list:REG_CFA_SET_VDRAP (reg:SI 177) (nil))) Should the REG_CFA_SET_VDRAP note be dropped or should dwarf2out_frame_debug handle (gdb) call debug_rtx (insn) (insn/f 202 254 2 2 (set (mem/c:SI (plus:SI (reg/f:SI 6 bp) (const_int -48 [0xffffffffffffffd0])) [0 %sfp+-48 S4 A32]) (reg:SI 2 cx)) 86 {*movsi_internal} (expr_list:REG_CFA_SET_VDRAP (reg:SI 177) (nil))) (gdb) in case REG_CFA_SET_VDRAP: n = XEXP (note, 0); if (REG_P (n)) { dw_fde_ref fde = cfun->fde; if (fde) { gcc_assert (fde->vdrap_reg == INVALID_REGNUM); if (REG_P (n)) fde->vdrap_reg = dwf_regno (n); } } handled_one = true; break;
Disable LRA gives me (insn/f 202 3 2 2 (set (mem/c:SI (plus:SI (reg/f:SI 6 bp) (const_int -48 [0xffffffffffffffd0])) [0 %sfp+-24 S4 A32]) (reg:SI 2 cx)) 86 {*movsi_internal} (expr_list:REG_CFA_SET_VDRAP (mem/c:SI (plus:SI (reg/f:SI 6 bp) (const_int -48 [0xffffffffffffffd0])) [0 %sfp+-24 S4 A32]) (nil))) It looks like LRA forgets to update NOTE.
A small testcase compiled with -std=c++1y -m32: -- namespace std { typedef long unsigned int size_t; } namespace std { template<class _E> class initializer_list { public: typedef size_t size_type; typedef const _E* iterator; typedef const _E* const_iterator; private: iterator _M_array; size_type _M_len; constexpr initializer_list(const_iterator __a, size_type __l) : _M_array(__a), _M_len(__l) { } }; } struct A { int i; A(std::initializer_list<int>) { } A(int i): i{i} { } }; int x = 4; int main(int argc, char **argv) { { int i[x] = { 42, 42, 42, 42 }; } { A a[x] = { argc }; if (a[1].i != 42) __builtin_abort (); } } ---
LRA calls (gdb) bt #0 elimination_costs_in_insn (insn=0x7ffff1a30ee8) at /export/gnu/src/gcc/gcc/gcc/reload1.c:3694 #1 0x0000000000d0419f in calculate_elim_costs_all_insns () at /export/gnu/src/gcc/gcc/gcc/reload1.c:1635 #2 0x0000000000bcb88e in ira_costs () at /export/gnu/src/gcc/gcc/gcc/ira-costs.c:2100 #3 0x0000000000bc3851 in ira_build () at /export/gnu/src/gcc/gcc/gcc/ira-build.c:3426 #4 0x0000000000bba081 in ira (f=0x0) at /export/gnu/src/gcc/gcc/gcc/ira.c:5306 #5 0x0000000000bba5ea in rest_of_handle_ira () at /export/gnu/src/gcc/gcc/gcc/ira.c:5537 #6 0x0000000000bba635 in (anonymous namespace)::pass_ira::execute ( this=0x2036920) at /export/gnu/src/gcc/gcc/gcc/ira.c:5566 #7 0x0000000000c9e61a in execute_one_pass ( pass=<opt_pass* 0x2036920 "ira"(218)>) at /export/gnu/src/gcc/gcc/gcc/passes.c:2215 #8 0x0000000000c9e831 in execute_pass_list ( pass=<opt_pass* 0x2036920 "ira"(218)>) at /export/gnu/src/gcc/gcc/gcc/passes.c:2268 #9 0x0000000000c9e862 in execute_pass_list ( pass=<opt_pass* 0x20358a0 "*rest_of_compilation"(-1)>) at /export/gnu/src/gcc/gcc/gcc/passes.c:2269 #10 0x0000000000982df2 in expand_function ( ---Type <return> to continue, or q <return> to quit--- node=<cgraph_node* 0x7ffff1a0c7b0 "main">) at /export/gnu/src/gcc/gcc/gcc/cgraphunit.c:1763 #11 0x00000000009835fc in output_in_order () at /export/gnu/src/gcc/gcc/gcc/cgraphunit.c:1958 #12 0x0000000000983c07 in compile () at /export/gnu/src/gcc/gcc/gcc/cgraphunit.c:2198 #13 0x0000000000983d8c in finalize_compilation_unit () at /export/gnu/src/gcc/gcc/gcc/cgraphunit.c:2280 #14 0x000000000070ed36 in cp_write_global_declarations () at /export/gnu/src/gcc/gcc/gcc/cp/decl2.c:4431 #15 0x0000000000d88f3e in compile_file () Now INSN comes: (gdb) call debug_rtx (insn) (insn/f 184 3 2 2 (set (nil) (reg:SI 2 cx)) 86 {*movsi_internal} (expr_list:REG_DEAD (reg:SI 2 cx) (expr_list:REG_CFA_SET_VDRAP (reg:SI 171) (nil)))) (gdb) The iEG_CFA_SET_VDRAP note is out of sync.
/* Terminate the search in check_eliminable_occurrences at this point. */ *recog_data.operand_loc[i] = 0; sets DEST to NULL.
remove_pseudos in lra-spills.c failed to handle REG_CFA_SET_VDRAP note.
This patch: diff --git a/gcc/lra-spills.c b/gcc/lra-spills.c index 4ab10c2..f4dcbdd 100644 --- a/gcc/lra-spills.c +++ b/gcc/lra-spills.c @@ -477,9 +477,23 @@ spill_pseudos (void) FOR_BB_INSNS (bb, insn) if (bitmap_bit_p (&changed_insns, INSN_UID (insn))) { + rtx *link_loc, link; remove_pseudos (&PATTERN (insn), insn); if (CALL_P (insn)) remove_pseudos (&CALL_INSN_FUNCTION_USAGE (insn), insn); + for (link_loc = ®_NOTES (insn); + (link = *link_loc) != NULL_RTX; + link_loc = &XEXP (link, 1)) + { + switch (REG_NOTE_KIND (link)) + { + case REG_CFA_SET_VDRAP: + remove_pseudos (&XEXP (link, 0), insn); + break; + default: + break; + } + } if (lra_dump_file != NULL) fprintf (lra_dump_file, "Changing spilled pseudos to memory in insn #%u\n", fixes the testcase. Should it also handle other REG_NOTES?
Created attachment 31313 [details] A patch I am testing this patch.
Author: hjl Date: Wed Nov 27 23:54:26 2013 New Revision: 205468 URL: http://gcc.gnu.org/viewcvs?rev=205468&root=gcc&view=rev Log: Also handle REG_XXX notes in spill_pseudos PR rtl-optimization/59311 * dwarf2cfi.c (dwf_regno): Assert reg isn't pseudo register. * lra-spills.c (spill_pseudos): Handle REG_XXX notes. Modified: trunk/gcc/ChangeLog trunk/gcc/dwarf2cfi.c trunk/gcc/lra-spills.c
I couldn't find a testcase to fail with 4.8.