Source: emacs24
Severity: normal
Tags: upstream patch
User: debian-sp...@lists.debian.org
Usertags: sparc64

Dear Maintainer,

The emacs24 build is currently failing on sparc64 with a Bus
Error. You can see an example build log here:

https://buildd.debian.org/status/fetch.php?pkg=emacs24&arch=sparc64&ver=24.5%2B1-5&stamp=1448688813

I've attached a patch that corrects an unaligned pointer dereference
in src/unexelf.c. But my fix is more of a hack and probably not suitable
for submitting to upstream.

I'm going to continue looking at this issue to try to create a 
more robust fix to offer upstream.

Below is a short explaination of what I've found looking into this
build failure.


The lucid build is failing with this error:

Loading /«BUILDDIR»/emacs24-24.5+1/debian/build-lucid/lisp/electric.el 
(source)...
Loading /«BUILDDIR»/emacs24-24.5+1/debian/build-lucid/lisp/tooltip.el 
(source)...
Finding pointers to doc strings...
Finding pointers to doc strings...done
Dumping under the name emacs
/bin/bash: line 7: 19090 Bus error               ./temacs --batch --load loadup 
bootstrap
make[3]: *** [bootstrap-emacs] Error 1
Makefile:815: recipe for target 'bootstrap-emacs' failed
make[3]: Leaving directory '/«BUILDDIR»/emacs24-24.5+1/debian/build-lucid/src'
make[2]: *** [src] Error 2
Makefile:389: recipe for target 'src' failed

Loading 'temacs' in gdb the bus error occurs in the file
src/unexelf.c, around line 980:

          */

          if (NEW_SECTION_H (nn).sh_offset >= old_bss_offset
              || (NEW_SECTION_H (nn).sh_offset + NEW_SECTION_H (nn).sh_size
                  > new_data2_offset))
            NEW_SECTION_H (nn).sh_offset += new_data2_incr;

With this instruction:

    0x294c20 <unexec+1204>  ldx  [ %g4 + 0x18 ], %g2

   // info reg g4 => 0xffff80011458013b -140732852076229

So it's trying to load an extended word (64bits, 8 bytes) from an
unaligned address.

NEW_SECTION_H is a macro that generates a pointer offset from
'new_section_h'.

    static void * 
   entry_address (void *section_h, ptrdiff_t idx, ptrdiff_t entsize)
    {
      char *h = section_h;
      return h + idx * entsize;
    }
    
    #define NEW_SECTION_H(n) \
      (*(ElfW (Shdr) *) entry_address (new_section_h, n, 
new_file_h->e_shentsize))

If 'new_section_h' is properly aligned this should be ok because it's
adding multiples of 'e_shentsize' which is 8. But new_section_h is
/not/ aligned so the resulting pointer is also not aligned.

Here is how 'new_section_h' is computed:

    new_section_h = (ElfW (Shdr) *)
        ((byte *) new_base + old_file_h->e_shoff + new_data2_incr);

GDB says the components of this sum have these values:

(gdb) print new_base
$6 = (caddr_t) 0xffff8001126aa000 "\177ELF\002\002\001"
(gdb) print old_file_h->e_shoff
$7 = 15751616
(gdb) print new_data2_incr
$8 = 16582459


'new_base' and 'old_file_h->e_shoff' are both 8 byte aligned but
'new_data2_incr' is not.

'new_data2_incr' is calculated this way:

    new_data2_incr = new_data2_size + (new_data2_offset - old_bss_offset);

It seems like 'new_data2_incr' is just an offset so it would be ok to
round it up to the nearest multiple of 8, using a function already
used in the file:

    new_data2_incr = round_up(new_data2_incr, (ElfW (Addr))8);

Adding this line to src/unexelf.c allows the build to finish normally. 

-- System Information:
Debian Release: stretch/sid
  APT prefers unreleased
  APT policy: (500, 'unreleased'), (500, 'unstable')
Architecture: sparc64

Kernel: Linux 4.3.0-gentoo (SMP w/1 CPU core)
Locale: LANG=en_SG.UTF-8, LC_CTYPE=en_SG.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash
Init: unable to detect
--- a/src/unexelf.c
+++ b/src/unexelf.c
@@ -779,6 +779,9 @@
      the end of the old .data section (and thus the offset of the .bss
      section) was unaligned.  */
   new_data2_incr = new_data2_size + (new_data2_offset - old_bss_offset);
+#ifdef __sparc_v9__
+  new_data2_incr = round_up(new_data2_incr, (ElfW (Addr))8);
+#endif
 
 #ifdef UNEXELF_DEBUG
   fprintf (stderr, "old_bss_index %td\n", old_bss_index);

Reply via email to