Bug 14149 - The _end symbol is not properly aligned
Summary: The _end symbol is not properly aligned
Status: RESOLVED INVALID
Alias: None
Product: binutils
Classification: Unclassified
Component: gold (show other bugs)
Version: 2.22
: P2 normal
Target Milestone: ---
Assignee: Ian Lance Taylor
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-05-23 21:38 UTC by jhb
Modified: 2012-08-27 15:30 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 jhb 2012-05-23 21:38:50 UTC
I have reproduced this with the gold linker from both 2.21 and 2.22.  I have reproduced this using GCC versions 4.5.3, 4.6.4, and 4.7.0 on both FreeBSD 8.2-STABLE and 9.0-STABLE.  To reproduce, compile the following test program and link with gold:

#include <stdio.h>
#include <new>

void foo()
{
        char *c = new(std::nothrow) char[10];
        delete c;
}

int
main()
{
        printf("Hello world\n");
}

Use objdump -T to obtain the offset of '_end':

a.out:     file format elf64-x86-64-freebsd

DYNAMIC SYMBOL TABLE:
0000000000401ac8 g    DO .bss   0000000000000008  Base        environ
0000000000401a80 g    DO .data  0000000000000008  Base        __progname
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4 _ZnamRKSt9nothrow_t
0000000000000000      DF *UND*  0000000000000000  GLIBCXX_3.4 _ZdlPv
0000000000000000      DF *UND*  0000000000000000  FBSD_1.0    atexit
0000000000000000      DF *UND*  0000000000000000  FBSD_1.0    exit
0000000000000000      DF *UND*  0000000000000000  FBSD_1.0    _init_tls
0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses
0000000000401ad0 g    DO .bss   0000000000000001  GLIBCXX_3.4 _ZSt7nothrow
0000000000000000      DF *UND*  0000000000000000  FBSD_1.0    puts
0000000000401ad1 g    D  *ABS*  0000000000000000  Base        _end


Note that _end has a mis-aligned address.  This causes jemalloc (the malloc in FreeBSD's libc) to corrupt it's internal RB trees as it assumes the start of the heap is aligned on at least an even address.  Using ld.bfd results in _end being aligned on an 8-byte boundary.  The linker scripts for ld.bfd for FreeBSD explicitly pad _end to an 8 byte boundary, so I assume it is a bug for the gold linker to not do this.

The bug appears to be triggered by std::nothrow pulling in a reference to a 1 byte symbol at the end of the BSS.
Comment 1 Cary Coutant 2012-05-23 21:59:08 UTC
> Note that _end has a mis-aligned address.  This causes jemalloc (the malloc in
> FreeBSD's libc) to corrupt it's internal RB trees as it assumes the start of
> the heap is aligned on at least an even address.  Using ld.bfd results in _end
> being aligned on an 8-byte boundary.  The linker scripts for ld.bfd for FreeBSD
> explicitly pad _end to an 8 byte boundary, so I assume it is a bug for the gold
> linker to not do this.

Not that I'm arguing the linker shouldn't do this, but I can't find
anything in the x86 ABI or the AMD64 ABI documents that guarantee _end
should have any specific alignment. The AMD64 ABI supplement says
nothing about _end, and the Intel386 Sys V ABI supplement says only
this:

extern _end;
   This symbol refers neither to a routine nor to a location with interesting
   contents. Instead, its address must correspond to the beginning of a
   program’s dynamic allocation area, called the heap. Typically, the heap
   begins immediately after the data segment of the program’s
   executable file.

It seems to me that your malloc implementation is relying on a
behavior of the GNU linker that is not guaranteed by the ABI. Even if
we do change gold to match the GNU ld behavior, I'd still recommend
that you change the implementation to rely only on the documented ABI.

-cary
Comment 2 jhb 2012-05-24 12:11:24 UTC
That's fair.  In fact, the man pages for end(3) and sbrk(2) on FreeBSD do not make any claims at all about alignment.  POSIX intentionally states that sbrk(2) return values do not enforce any alignment (http://pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html).

The previous malloc implementation in FreeBSD did use rounding on the return value from sbrk(0) (so it would have worked fine).  I will work on getting jemalloc fixed both in FreeBSD and upstream.  I'm fine with having this closed on my end.  Up to you if you think there might be any other software that depends on this behavior of GNU ld.
Comment 3 jhb 2012-08-27 14:15:53 UTC
FYI, jemalloc has since been fixed to handle unaligned _end addresses.  Given the link in my last comment about POSIX not requiring any specific alignment from sbrk(), I think you can probably close this as not being a bug.
Comment 4 Paul Pluzhnikov 2012-08-27 15:30:42 UTC
(Apparently) not a Gold bug.