Bug 59311 - [4.9 Regression] LRA fails to update REG_CFA_SET_VDRAP note
Summary: [4.9 Regression] LRA fails to update REG_CFA_SET_VDRAP note
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: rtl-optimization (show other bugs)
Version: 4.9.0
: P3 normal
Target Milestone: 4.9.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-11-27 12:41 UTC by H.J. Lu
Modified: 2013-11-28 00:22 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2013-11-27 00:00:00


Attachments
A patch (659 bytes, patch)
2013-11-27 20:39 UTC, H.J. Lu
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2013-11-27 12:41:05 UTC
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]$
Comment 1 H.J. Lu 2013-11-27 12:48:34 UTC
Only happens with -m32 on Linux/x86-64.
Comment 2 H.J. Lu 2013-11-27 12:52:09 UTC
==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
Comment 3 H.J. Lu 2013-11-27 13:04:14 UTC
(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.
Comment 4 H.J. Lu 2013-11-27 13:51:20 UTC
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;
Comment 5 H.J. Lu 2013-11-27 13:54:20 UTC
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.
Comment 6 H.J. Lu 2013-11-27 18:50:02 UTC
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 ();
  }
}
---
Comment 7 H.J. Lu 2013-11-27 19:34:18 UTC
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.
Comment 8 H.J. Lu 2013-11-27 19:44:40 UTC
          /* Terminate the search in check_eliminable_occurrences at
             this point.  */
          *recog_data.operand_loc[i] = 0; 

sets DEST to NULL.
Comment 9 H.J. Lu 2013-11-27 20:09:22 UTC
remove_pseudos in lra-spills.c failed to handle
REG_CFA_SET_VDRAP note.
Comment 10 H.J. Lu 2013-11-27 20:26:49 UTC
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 = &REG_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?
Comment 11 H.J. Lu 2013-11-27 20:39:25 UTC
Created attachment 31313 [details]
A patch

I am testing this patch.
Comment 12 hjl@gcc.gnu.org 2013-11-27 23:54:28 UTC
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
Comment 13 H.J. Lu 2013-11-28 00:22:41 UTC
I couldn't find a testcase to fail with 4.8.