Bug 6743 - addr2line frees an invalid pointer
Summary: addr2line frees an invalid pointer
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.19
: P2 normal
Target Milestone: ---
Assignee: unassigned
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-07-13 15:47 UTC by H.J. Lu
Modified: 2008-07-14 00:12 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description H.J. Lu 2008-07-13 15:47:32 UTC
As of Sat Jul 12 08:46:21 PDT 2008, on Fedora 9/x86-64,
I got

bash-3.2$ ./addr2line -e addr2line 0x401f49
??:0
*** glibc detected *** ./addr2line: munmap_chunk(): invalid pointer:
0x00007f850706909c ***
======= Backtrace: =========
/lib64/libc.so.6[0x3362278158]
./addr2line[0x41f87a]
./addr2line[0x40a719]
./addr2line[0x4025d4]
/lib64/libc.so.6(__libc_start_main+0xfa)[0x336221e32a]
./addr2line(calloc+0x149)[0x401f49]
======= Memory map: ========
00400000-004c9000 r-xp 00000000 08:11 14418847                          
/export/build/gnu/binutils/build-x86_64-linux.old/binutils/addr2line
006c8000-006cb000 rw-p 000c8000 08:11 14418847                          
/export/build/gnu/binutils/build-x86_64-linux.old/binutils/addr2line
006cb000-006cf000 rw-p 006cb000 00:00 0 
021c0000-0228e000 rw-p 021c0000 00:00 0                                  [heap]
3361000000-336101d000 r-xp 00000000 08:06 9297034                       
/lib64/ld-2.8.so
336121c000-336121d000 r--p 0001c000 08:06 9297034                       
/lib64/ld-2.8.so
336121d000-336121e000 rw-p 0001d000 08:06 9297034                       
/lib64/ld-2.8.so
3362200000-3362362000 r-xp 00000000 08:06 9297035                       
/lib64/libc-2.8.so
3362362000-3362562000 ---p 00162000 08:06 9297035                       
/lib64/libc-2.8.so
3362562000-3362566000 r--p 00162000 08:06 9297035                       
/lib64/libc-2.8.so
3362566000-3362567000 rw-p 00166000 08:06 9297035                       
/lib64/libc-2.8.so
3362567000-336256c000 rw-p 3362567000 00:00 0 
3363600000-3363615000 r-xp 00000000 08:06 9297066                       
/lib64/libz.so.1.2.3
3363615000-3363814000 ---p 00015000 08:06 9297066                       
/lib64/libz.so.1.2.3
3363814000-3363815000 rw-p 00014000 08:06 9297066                       
/lib64/libz.so.1.2.3
3368a00000-3368a16000 r-xp 00000000 08:06 9297068                       
/lib64/libgcc_s-4.3.0-20080428.so.1
3368a16000-3368c15000 ---p 00016000 08:06 9297068                       
/lib64/libgcc_s-4.3.0-20080428.so.1
3368c15000-3368c16000 rw-p 00015000 08:06 9297068                       
/lib64/libgcc_s-4.3.0-20080428.so.1
7f8506ed9000-7f850709a000 rw-p 7f8506ed9000 00:00 0 
7f85070be000-7f85070c2000 rw-p 7f85070be000 00:00 0 
7fff0f0ad000-7fff0f0c2000 rw-p 7ffffffea000 00:00 0                      [stack]
7fff0f1fe000-7fff0f200000 r-xp 7fff0f1fe000 00:00 0                      [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted
bash-3.2$
Comment 1 H.J. Lu 2008-07-13 15:56:21 UTC
Hi Craig, your patch:

http://sourceware.org/ml/binutils/2008-06/msg00203.html

caused this regression.
Comment 2 H.J. Lu 2008-07-13 16:38:41 UTC
The correct behaviour should be

bash-3.2$ ./addr2line -e addr2line 0x401f49
/export/gnu/import/binutils-last/src/binutils/addr2line.c:341
bash-3.2$ 
Comment 3 H.J. Lu 2008-07-13 19:56:48 UTC
bash-3.2$ ./addr2line -e ./addr2line `nm  -n  --defined-only  ./addr2line  |head
-1 | awk '{print $1}'`
??:0
*** glibc detected *** ./addr2line: munmap_chunk(): invalid pointer:
0x00007f60c57010a2 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3362278158]
./addr2line[0x41f87a]
./addr2line[0x40a719]
./addr2line[0x4025d4]
/lib64/libc.so.6(__libc_start_main+0xfa)[0x336221e32a]
./addr2line(calloc+0x149)[0x401f49]
======= Memory map: ========
00400000-004c9000 r-xp 00000000 08:11 14549834                          
/export/build/gnu/binutils/next/binutils/addr2line
006c9000-006cc000 rw-p 000c9000 08:11 14549834                          
/export/build/gnu/binutils/next/binutils/addr2line
006cc000-006d0000 rw-p 006cc000 00:00 0 
02603000-026d1000 rw-p 02603000 00:00 0                                  [heap]
3361000000-336101d000 r-xp 00000000 08:06 9297034                       
/lib64/ld-2.8.so
336121c000-336121d000 r--p 0001c000 08:06 9297034                       
/lib64/ld-2.8.so
336121d000-336121e000 rw-p 0001d000 08:06 9297034                       
/lib64/ld-2.8.so
3362200000-3362362000 r-xp 00000000 08:06 9297035                       
/lib64/libc-2.8.so
3362362000-3362562000 ---p 00162000 08:06 9297035                       
/lib64/libc-2.8.so
3362562000-3362566000 r--p 00162000 08:06 9297035                       
/lib64/libc-2.8.so
3362566000-3362567000 rw-p 00166000 08:06 9297035                       
/lib64/libc-2.8.so
3362567000-336256c000 rw-p 3362567000 00:00 0 
3363600000-3363615000 r-xp 00000000 08:06 9297066                       
/lib64/libz.so.1.2.3
3363615000-3363814000 ---p 00015000 08:06 9297066                       
/lib64/libz.so.1.2.3
3363814000-3363815000 rw-p 00014000 08:06 9297066                       
/lib64/libz.so.1.2.3
3368a00000-3368a16000 r-xp 00000000 08:06 9297068                       
/lib64/libgcc_s-4.3.0-20080428.so.1
3368a16000-3368c15000 ---p 00016000 08:06 9297068                       
/lib64/libgcc_s-4.3.0-20080428.so.1
3368c15000-3368c16000 rw-p 00015000 08:06 9297068                       
/lib64/libgcc_s-4.3.0-20080428.so.1
7f60c5571000-7f60c5732000 rw-p 7f60c5571000 00:00 0 
7f60c5756000-7f60c575a000 rw-p 7f60c5756000 00:00 0 
7fffcd745000-7fffcd75a000 rw-p 7ffffffea000 00:00 0                      [stack]
7fffcd7fe000-7fffcd800000 r-xp 7fffcd7fe000 00:00 0                      [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted
bash-3.2$ /usr/bin/addr2line -e ./addr2line `nm  -n  --defined-only  ./addr2line
 |head -1 | awk '{print $1}'`
??:0
bash-3.2$ 
Comment 4 H.J. Lu 2008-07-13 23:43:09 UTC
On Linux, to reproduce it, you may try

[hjl@gnu-26 binutils]$ MALLOC_CHECK_=1 ./addr2line -e ./addr2line `nm  -n 
--defined-only  ./addr2line |head -1 | awk '{print $1}'`
malloc: using debugging hooks
??:0
*** glibc detected *** free(): invalid pointer: 0x0000002a95734d53 ***
[hjl@gnu-26 binutils]$
Comment 5 Craig 2008-07-13 23:46:47 UTC
I've figured out the crashing bug, and can fix that.  I tried your test and it
gave a different line number than you got, but I assume that's due to build
differences.  But just to make sure, do you mind applying the following patch,
and verifying it fixes things at your end?

craig
---

Index: bfd/dwarf2.c
===================================================================
RCS file: /cvs/src/src/bfd/dwarf2.c,v
retrieving revision 1.110
diff -u -r1.110 dwarf2.c
--- bfd/dwarf2.c        11 Jul 2008 09:18:19 -0000      1.110
+++ bfd/dwarf2.c        13 Jul 2008 23:45:20 -0000
@@ -104,6 +104,12 @@
   asection *sec;
   bfd_byte *sec_info_ptr;
 
+  /* A pointer to the memory block allocated for info_ptr.  Neither
+     info_ptr nor sec_info_ptr are guaranteed to stay pointing to the
+     beginning of the malloc block.  This is used only to free the
+     memory later.  */
+  bfd_byte *info_ptr_memory;
+
   /* Pointer to the symbol table.  */
   asymbol **syms;
 
@@ -2915,8 +2921,9 @@
           total_size = msec->size;
           if (! read_section (debug_bfd, ".debug_info", ".zdebug_info",
                               symbols, 0,
-                              &stash->info_ptr, &total_size))
+                              &stash->info_ptr_memory, &total_size))
             goto done;
+          stash->info_ptr = stash->info_ptr_memory;
           stash->info_ptr_end = stash->info_ptr + total_size;
         }
       else
@@ -2931,10 +2938,11 @@
           if (all_uncompressed)
             {
               /* Case 2: multiple sections, but none is compressed.  */
-              stash->info_ptr = bfd_malloc (total_size);
-              if (stash->info_ptr == NULL)
+              stash->info_ptr_memory = bfd_malloc (total_size);
+              if (stash->info_ptr_memory == NULL)
                goto done;
 
+              stash->info_ptr = stash->info_ptr_memory;
               stash->info_ptr_end = stash->info_ptr;
 
               for (msec = find_debug_info (debug_bfd, NULL);
@@ -2963,7 +2971,8 @@
           else
             {
               /* Case 3: multiple sections, some or all compressed.  */
-              stash->info_ptr = bfd_malloc (1);
+              stash->info_ptr_memory = bfd_malloc (1);
+              stash->info_ptr = stash->info_ptr_memory;
               stash->info_ptr_end = stash->info_ptr;
               for (msec = find_debug_info (debug_bfd, NULL);
                   msec;
@@ -3292,5 +3301,5 @@
   free (stash->dwarf_abbrev_buffer);
   free (stash->dwarf_line_buffer);
   free (stash->dwarf_ranges_buffer);
-  free (stash->sec_info_ptr);
+  free (stash->info_ptr_memory);
 }
Comment 6 H.J. Lu 2008-07-13 23:52:09 UTC
(In reply to comment #5)
> I've figured out the crashing bug, and can fix that.  I tried your test and it
> gave a different line number than you got, but I assume that's due to build
> differences.  But just to make sure, do you mind applying the following patch,
> and verifying it fixes things at your end?
> 

Yes, it fixed the crash.  Thanks.
Comment 7 Craig 2008-07-14 00:12:46 UTC
OK, I've committed it to the CVS repository.  Thanks for the report.
Comment 8 Craig 2008-07-14 00:12:47 UTC
Subject: Re:  PATCH COMMITTED: new variable for malloc

It turns out a variable I thought would always point to the beginning
of the malloc-block, can actually change value.  This was causing
crashes in some cases.  I've fixed this by adding a new pointer, that
always points to the malloc-location, so we can always free it safely.

I'm comitting this under the "obvious fix" principle.  This is
probably the least obvious of the obvious fixes I've done so far, but
I hope it still safely falls into that category.

craig

--cut here--

2008-07-13  Craig Silverstein  <csilvers@google.com>

	* dwarf2.c (struct dwarf2_debug): New variable info_ptr_memory.
	(find_line): Use info_ptr_memory instead of sec_info_ptr.
	(_bfd_dwarf2_cleanup_debug_info): Likewise.


Index: bfd/dwarf2.c
===================================================================
RCS file: /cvs/src/src/bfd/dwarf2.c,v
retrieving revision 1.110
diff -u -r1.110 dwarf2.c
--- bfd/dwarf2.c	11 Jul 2008 09:18:19 -0000	1.110
+++ bfd/dwarf2.c	14 Jul 2008 00:09:17 -0000
@@ -104,6 +104,12 @@
   asection *sec;
   bfd_byte *sec_info_ptr;
 
+  /* A pointer to the memory block allocated for info_ptr.  Neither
+     info_ptr nor sec_info_ptr are guaranteed to stay pointing to the
+     beginning of the malloc block.  This is used only to free the
+     memory later.  */
+  bfd_byte *info_ptr_memory;
+
   /* Pointer to the symbol table.  */
   asymbol **syms;
 
@@ -2915,8 +2921,9 @@
           total_size = msec->size;
           if (! read_section (debug_bfd, ".debug_info", ".zdebug_info",
                               symbols, 0,
-                              &stash->info_ptr, &total_size))
+                              &stash->info_ptr_memory, &total_size))
             goto done;
+          stash->info_ptr = stash->info_ptr_memory;
           stash->info_ptr_end = stash->info_ptr + total_size;
         }
       else
@@ -2931,10 +2938,11 @@
           if (all_uncompressed)
             {
               /* Case 2: multiple sections, but none is compressed.  */
-              stash->info_ptr = bfd_malloc (total_size);
-              if (stash->info_ptr == NULL)
+              stash->info_ptr_memory = bfd_malloc (total_size);
+              if (stash->info_ptr_memory == NULL)
         	goto done;
 
+              stash->info_ptr = stash->info_ptr_memory;
               stash->info_ptr_end = stash->info_ptr;
 
               for (msec = find_debug_info (debug_bfd, NULL);
@@ -2963,7 +2971,8 @@
           else
             {
               /* Case 3: multiple sections, some or all compressed.  */
-              stash->info_ptr = bfd_malloc (1);
+              stash->info_ptr_memory = bfd_malloc (1);
+              stash->info_ptr = stash->info_ptr_memory;
               stash->info_ptr_end = stash->info_ptr;
               for (msec = find_debug_info (debug_bfd, NULL);
         	   msec;
@@ -3292,5 +3301,5 @@
   free (stash->dwarf_abbrev_buffer);
   free (stash->dwarf_line_buffer);
   free (stash->dwarf_ranges_buffer);
-  free (stash->sec_info_ptr);
+  free (stash->info_ptr_memory);
 }