Bug 13449 - ARM: Unwind tables are created based on uninitialized memory
Summary: ARM: Unwind tables are created based on uninitialized memory
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: gas (show other bugs)
Version: 2.24
: P2 critical
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-11-29 12:32 UTC by Alexander Graf
Modified: 2011-12-21 17:10 UTC (History)
3 users (show)

See Also:
Host: ARMv7 with HF
Target: ARMv7 with HF
Build:
Last reconfirmed:


Attachments
source, broken and properly compiled binary (5.36 KB, application/octet-stream)
2011-11-29 17:20 UTC, Alexander Graf
Details
possible bug fix (310 bytes, patch)
2011-12-01 17:52 UTC, Nick Clifton
Details | Diff
exc.s and working/broken .o files (2.06 KB, application/octet-stream)
2011-12-01 18:19 UTC, Alexander Graf
Details
Another possible fix (604 bytes, patch)
2011-12-02 17:51 UTC, Nick Clifton
Details | Diff
Third possible fix (567 bytes, patch)
2011-12-06 11:02 UTC, Nick Clifton
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Graf 2011-11-29 12:32:22 UTC
Hi,

While building packages for openSUSE-ARM, we realized that every time a program wanted to throw an exception, hell broke lose. After a lot of debugging and valgrind'ing, we found out that the ARM unwind tables contain garbage because they get written out without being initialized to 0.

A simple failing test program:

#include <stdio.h>

int main(int argc, char **argv)
{
  try { throw -1; }
  catch (int) { fprintf(stderr, "We caught an exception of type int\n"); }
  return 0;
}

Working test output:

  We caught an exception of type int

Working unwind tables:

0x8640 <main>: @0x8734
  Personality routine: 0x85bc <__gxx_personality_v0@@CXXABI_1.3>
  0x97      vsp = r7
  0x03      vsp = vsp + 16
  0x84 0x08 pop {r7, r14}
  0xb0      finish
  0xb0      finish
  0xb0      finish

Failing test output:

  terminate called after throwing an instance of 'int'
  terminate called recursively
  Aborted (core dumped)

Failing unwind tables:

0x8634 <main>: 0xffffffd0
  Compact model 127
  [reserved]



valgrind output of gas:

==2009== Syscall param write(buf) points to uninitialised byte(s)
==2009==    at 0x48EE56C: write (in /lib/libc-2.14.1.so)
==2009==    by 0x48B51BB: _IO_file_write@@GLIBC_2.4 (fileops.c:1281)
==2009==    by 0x48B510F: new_do_write (fileops.c:535)
==2009==    by 0x48B5E1D: _IO_do_write@@GLIBC_2.4 (fileops.c:508)
==2009==    by 0x48B6907: _IO_switch_to_get_mode (genops.c:189)
==2009==    by 0x48B52D3: _IO_file_seekoff@@GLIBC_2.4 (fileops.c:991)
==2009==    by 0x48AF0AB: _IO_seekoff_unlocked (ioseekoff.c:71)
==2009==    by 0x48B4031: fseeko64 (fseeko64.c:42)
==2009==    by 0x73A79: bfd_seek (bfdio.c:315)
==2009==    by 0x5CB6F: _bfd_elf_write_object_contents (elf.c:5217)
==2009==    by 0x4099F: bfd_close (opncls.c:701)
==2009==    by 0x16E51: output_file_close (output-file.c:65)
==2009==  Address 0x4d500d7 is not stack'd, malloc'd or (recently) free'd
==2009==  Uninitialised value was created by a heap allocation
==2009==    at 0x482F694: malloc (vg_replace_malloc.c:263)
==2009==    by 0x7F353: xmalloc (xmalloc.c:147)
==2009==    by 0x48BE1D7: _obstack_begin (obstack.c:186)
==2009==    by 0x1C3E9: subseg_set_rest (subsegs.c:110)
==2009==    by 0x1C50D: subseg_force_new (subsegs.c:195)
==2009==    by 0x3B257: obj_elf_change_section (obj-elf.c:583)
==2009==    by 0x25A47: start_unwind_section (tc-arm.c:19828)
==2009==    by 0x3240D: create_unwind_entry (tc-arm.c:19857)
==2009==    by 0x1B59D: read_a_source_file (read.c:919)
==2009==    by 0xAEC1: main (as.c:1089)


We also created a temporary patch to make it work by just initializing all memory properly:

Index: libiberty/xmalloc.c
===================================================================
--- libiberty/xmalloc.c.orig
+++ libiberty/xmalloc.c
@@ -60,6 +60,7 @@ function will be called to print an erro
 
 */
 
+#include <string.h>
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -145,6 +146,7 @@ xmalloc (size_t size)
   if (size == 0)
     size = 1;
   newmem = malloc (size);
+  memset(newmem, 0, size);
   if (!newmem)
     xmalloc_failed (size);


With that patch applied, unwind tables are created successfully.
Comment 1 Nick Clifton 2011-11-29 16:38:29 UTC
Hi Alexander,

   Would it be possible for you to upload a copy of the broken test 
executable ?  I want to be able to look at the unwind information it 
contains, and to compare it against executables that I build locally. 
(I do not have an ARM system so I cannot run any executables.  I just 
have a cross-hosted toolchain).

Cheers
   Nick
Comment 2 Alexander Graf 2011-11-29 17:20:05 UTC
Created attachment 6080 [details]
source, broken and properly compiled binary

Sure, please beware that the unwind table generation depends heavily on the contents of your host RAM though. I had one box where compilation worked just fine and one where it was constantly broken, which was how I ended up narrowing down the problem.

So even if it works for your on your system it doesn't mean that it would always work.
Comment 3 Nick Clifton 2011-12-01 17:51:03 UTC
Hi Alexander,

  Thanks for the binaries - they really help.

  If you compare a hex dump of the .ARM.exidx sections in the two binaries, you will see that the broken binary does not contain garbage, just two erroneous set bits:

  % readelf -x17 exc
  Hex dump of section '.ARM.exidx':
    0x00008758 70feffff 01000000 e0feff7f d0ffff7f p...............
    0x00008768 54ffffff ad08b180 90ffffff b0b0b080 T...............
    0x00008778 8cffff7f 01000000                   ........

  % readelf -x17 exc.broken
  Hex dump of section '.ARM.exidx':
    0x0000874c 70feffff 01000000 e0feffff d0ffffff p...............
    0x0000875c 54ffffff ad08b180 90ffffff b0b0b080 T...............
    0x0000876c 8cffff7f 01000000                   ........

(It would be very interesting to compare the exc.o files for the broken and working builds to see if these bits are the same there.  Ie I am wondering if the linker might be the problem rather than the assembler - and the valgrind detection of an uninitialised write might just be a red herring).

I am still investigating, but in the meantime would you mind trying out the small patch that I am about to upload and let me know if it makes any difference ?

Cheers
  Nick
Comment 4 Nick Clifton 2011-12-01 17:52:41 UTC
Created attachment 6083 [details]
possible bug fix
Comment 5 Alexander Graf 2011-12-01 18:10:14 UTC
I can easily create the .o files for you. I'm very sure that gas is broken. Please see the following commands:


panda1:/binutils/gas> ./as-new -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -meabi=5 -o /exc.o /exc.s
panda1:/binutils/gas> readelf -u /exc.o

Unwind table index '.ARM.exidx' at offset 0xf8 contains 1 entries:

0x0: 0xfffffffc
  Compact model 127
  [reserved]

-----

wichary:/binutils/gas> ./as-new -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -meabi=5 -o /exc.o /exc.s
wichary:/binutils/gas> readelf -u /exc.o

Unwind table index '.ARM.exidx' at offset 0xf8 contains 1 entries:

0x0: @0x0
  Personality routine: 0x0 <main>

-----

Both are running inside the exact same rootfs mounted via NFS. This is with your patch applied btw :).
Comment 6 Alexander Graf 2011-12-01 18:17:10 UTC
Another data point I forgot to mention: Running gas inside of valgrind generates correct unwind tables even on panda1.
Comment 7 Alexander Graf 2011-12-01 18:19:26 UTC
Created attachment 6084 [details]
exc.s and working/broken .o files
Comment 8 Nick Clifton 2011-12-02 17:51:57 UTC
Created attachment 6086 [details]
Another possible fix
Comment 9 Nick Clifton 2011-12-02 17:54:11 UTC
Hi Alexander,

  Thanks for the .s and .o files.  I agree - the problem must be with GAS.

  Please could you try out the newly uploaded patch and let me know if it makes a difference ?

  I still cannot reproduce the bug locally, but at least I am able to improve readelf so that it produces more helpful output when decoding the unwind tables.

Cheers
  Nick
Comment 10 Nick Clifton 2011-12-06 11:02:24 UTC
Created attachment 6090 [details]
Third possible fix
Comment 11 Nick Clifton 2011-12-06 11:05:05 UTC
Hi Alexander,

  Thinking about this some more over the weekend, I now suspect that my second patch will not work.  But I have thought of another possible cause, and uploaded a third patch.  Please could you try out both patches and let me know if they make any difference.

Cheers
  Nick
Comment 12 Alexander Graf 2011-12-20 14:55:20 UTC
Hi Nick,

Sorry for the late reply. I fetched today's CVS and realized that you already applied patch 3. I now get the following output when compiling on panda1:

Unwind table index '.ARM.exidx' at offset 0xf8 contains 1 entries:

0x0: @0x0
  Compact model 0
  0x00      vsp = vsp + 4
  0x00      vsp = vsp + 4
  0x00      vsp = vsp + 4

The difference in the two outputs is obviously the compact model bit:

--- exc.good.o.hex	2011-12-20 14:54:09.000000000 +0000
+++ exc.bad.o.hex	2011-12-20 14:54:13.000000000 +0000
@@ -11,7 +11,7 @@
 000000a0  fe ff 4f f0 00 03 18 46  07 f1 10 07 bd 46 80 bd  |..O....F.....F..|
 000000b0  57 65 20 63 61 75 67 68  74 20 61 6e 20 65 78 63  |We caught an exc|
 000000c0  65 70 74 69 6f 6e 20 6f  66 20 74 79 70 65 20 69  |eption of type i|
-000000d0  6e 74 0a 00 00 00 00 00  84 03 97 01 b0 b0 b0 08  |nt..............|
+000000d0  6e 74 0a 00 00 00 00 80  84 03 97 01 b0 b0 b0 08  |nt..............|
 000000e0  ff 00 15 01 0c 28 04 34  01 30 10 00 00 66 04 2c  |.....(.4.0...f.,|
 000000f0  00 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 00000100  00 47 43 43 3a 20 28 53  55 53 45 20 4c 69 6e 75  |.GCC: (SUSE Linu|
Comment 13 Alexander Graf 2011-12-20 15:04:07 UTC
This patch fixes the test case for me:

Index: config/tc-arm.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-arm.c,v
retrieving revision 1.512
diff -u -r1.512 tc-arm.c
--- config/tc-arm.c	15 Dec 2011 10:21:49 -0000	1.512
+++ config/tc-arm.c	20 Dec 2011 15:03:02 -0000
@@ -19944,6 +19944,7 @@
 
   /* Allocate the table entry.	*/
   ptr = frag_more ((size << 2) + 4);
+  memset (ptr, 0, (size << 2) + 4);
   where = frag_now_fix () - ((size << 2) + 4);
 
   switch (unwind.personality_index)
Comment 14 cvs-commit@gcc.gnu.org 2011-12-21 17:07:33 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	nickc@sourceware.org	2011-12-21 17:07:27

Modified files:
	gas            : ChangeLog 
	gas/config     : tc-arm.c 

Log message:
	PR gas/13449
	* config/tc-arm.c (create_unwind_entry): Zero allocated table
	entries.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gas/ChangeLog.diff?cvsroot=src&r1=1.4638&r2=1.4639
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gas/config/tc-arm.c.diff?cvsroot=src&r1=1.512&r2=1.513
Comment 15 Nick Clifton 2011-12-21 17:10:37 UTC
Patch applied.