bug-glibc
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

fix for atexit() bug in glibc 2.2.3


From: Andreas Steinmetz
Subject: fix for atexit() bug in glibc 2.2.3
Date: Sat, 19 May 2001 21:21:43 +0200 (MEST)

Unfortunately applying your patch to gcc and rebuilding gcc-2.95.3, then
glibc-2.2.3, doesn't fix the atexit() sigsegv problem for statically linked
programs. So I started digging myself. Looking at atexit() in a statically
linked test progam:

0x80485d0 <atexit>:     sub    $0xc,%esp
0x80485d3 <atexit+3>:   mov    $0x0,%edx
0x80485d8 <atexit+8>:   mov    0x10(%esp,1),%ecx
0x80485dc <atexit+12>:  xor    %eax,%eax
0x80485de <atexit+14>:  add    $0xfffffffc,%esp
0x80485e1 <atexit+17>:  test   %edx,%edx
0x80485e3 <atexit+19>:  cmovne 0x0,%eax             <========= SIGSEGV
0x80485ea <atexit+26>:  push   %eax
0x80485eb <atexit+27>:  push   $0x0
0x80485ed <atexit+29>:  push   %ecx
0x80485ee <atexit+30>:  call   0x80486e0 <__cxa_atexit>
0x80485f3 <atexit+35>:  add    $0x10,%esp
0x80485f6 <atexit+38>:  add    $0xc,%esp
0x80485f9 <atexit+41>:  ret

Registers at SIGSEGV time:

eax            0x0      0
ecx            0x8048210        134513168
edx            0x0      0
ebx            0xbffff9ac       -1073743444
esp            0xbffff910       0xbffff910
ebp            0xbffff93c       0xbffff93c
esi            0xbffff9a4       -1073743452
edi            0x1      1
eip            0x80485e3        0x80485e3
eflags         0x10346  66374
cs             0x23     35
ss             0x2b     43
ds             0x2b     43
es             0x2b     43
fs             0x0      0
gs             0x0      0
fctrl          0x37f    895
fstat          0x0      0
ftag           0xffff   65535
fiseg          0x10     16
fioff          0xc03121bf       -1070521921
foseg          0x0      0
fooff          0x0      0
fop            0x4f1    1265

Well, I don't have an assembler manual around so I can't tell if the
access to the source by cmovne is defined as standard or if it is just an
unexpected speculative access (I'm running an Athlon TB900). One would expect,
however, that a conditional move data access would only happen if the condition
is met which it is not (edx=0).

The same in the source (stdlib/atexit.c):

/* This is defined by newer gcc version unique for each module.  */
extern void *__dso_handle __attribute__ ((__weak__));
 
 
/* Register FUNC to be executed by `exit'.  */
int
atexit (void (*func) (void))
{
  return __cxa_atexit ((void (*) (void *)) func, NULL,
                       &__dso_handle == NULL ? NULL : __dso_handle);
}                            ^^
                             ||
                   This being the problem


As it turns out a workaround is simple (de-optimization, patch below):

=======snip=======
--- stdlib/atexit.c-2.2.3       Sat May 19 20:13:37 2001
+++ stdlib/atexit.c     Sat May 19 20:48:51 2001
@@ -28,8 +28,9 @@
 int
 atexit (void (*func) (void))
 {
-  return __cxa_atexit ((void (*) (void *)) func, NULL,
-                      &__dso_handle == NULL ? NULL : __dso_handle);
+  if(&__dso_handle)return __cxa_atexit ((void (*) (void *)) func,
+       NULL,__dso_handle);
+  else return __cxa_atexit ((void (*) (void *)) func, NULL,NULL);
 }
 
 /* Hide the symbol so that no definition but the one locally in the
======snip========

This results in the following assembler which is 'bug free':

0x80485d0 <atexit>:     sub    $0xc,%esp
0x80485d3 <atexit+3>:   mov    $0x0,%eax
0x80485d8 <atexit+8>:   mov    0x10(%esp,1),%edx
0x80485dc <atexit+12>:  test   %eax,%eax
0x80485de <atexit+14>:  je     0x80485ec <atexit+28>
0x80485e0 <atexit+16>:  add    $0xfffffffc,%esp
0x80485e3 <atexit+19>:  mov    0x0,%eax
0x80485e8 <atexit+24>:  push   %eax
0x80485e9 <atexit+25>:  jmp    0x80485f1 <atexit+33>
0x80485eb <atexit+27>:  nop
0x80485ec <atexit+28>:  add    $0xfffffffc,%esp
0x80485ef <atexit+31>:  push   $0x0
0x80485f1 <atexit+33>:  push   $0x0
0x80485f3 <atexit+35>:  push   %edx
0x80485f4 <atexit+36>:  call   0x80486e0 <__cxa_atexit>
0x80485f9 <atexit+41>:  add    $0x10,%esp
0x80485fc <atexit+44>:  add    $0xc,%esp
0x80485ff <atexit+47>:  ret

I don't really know if the actual bug is caused by glibc-2.2.3 or gcc-2.95.3.
This problem should be solved, however, by the appropriate party (please forward
this mail to the proper developers, if necessary). Furthermore '__dso_handle'
is used in more places, especially 'malloc/mtrace.c'. So further fixes may be
required.

To better check for the problem here's the configure statement (oh, configure
needs to be modified to be able to not build against libgd even when it is
around, I patched that the hard way...) and the compiler flags:

../configure  --prefix=/usr --enable-add-ons --disable-profile
--enable-kernel=2.2.18 --with-headers=/usr/src/linux/include --without-gmp
--without-gd --without-gd-include --without-gd-lib --without-cvs --with-elf
--enable-shared

CFLAGS=-O3 -fomit-frame-pointer -funroll-loops -fexpensive-optimizations
-fschedule-insns2 -mwide-multiply -march=pentiumpro -mcpu=pentiumpro
-malign-loops=2 -malign-jumps=2 -malign-functions=4

CXXFLAGS=-O3 -fomit-frame-pointer -funroll-loops -fexpensive-optimizations
-fschedule-insns2 -mwide-multiply -march=pentiumpro -mcpu=pentiumpro
-malign-loops=2 -malign-jumps=2 -malign-functions=4

When I'm at it: 'make check' uses somewhere a hardcoded '/bin/cat' which is not
nice if cat is not in /bin. 'make install' doesn't honor a softlink for
'/etc/ld.so.cache' but replaces the softlink with a new cache file.

On 16-May-2001 Andreas Jaeger wrote:
> Andreas Steinmetz <address@hidden> writes:
> 
>> Hi,
>> when building static (-static) versions of fileutils-4.1 with gcc 2.95.3 the
>> resulting binaries segfault in atexit(). Temporary fix for me is an atexit()
>> shim diverting the call to on_exit().
> 
> Did you apply the appended patch to GCC 2.95.3 as mentioned in the
> release notes?
> 
>> After the upgrade from 2.2.2 to 2.2.3 the following packages stopped working
>> and had to be rebuilt against the new library:
>> 
>> ypserv-1.3.12
>> nfs-utils-0.3.1 (rpc.kstatd)
> 
> Really? 
>> Installing glibc-2.2.3 did cause problems too:
>> 
>> [snip]
>> 
>> make  -C linuxthreads subdir_install
>> make[2]: Entering directory `/usr/src/glibc-2.2.3/linuxthreads'
>> /bin/install -c -m 644 ../linuxthreads/sysdeps/pthread/pthread.h
>> /usr/include/pt/bin/install -c -m 644 semaphore.h /usr/include/semaphore.h
>> /bin/install -c /usr/src/glibc-2.2.3/build/linuxthreads/libpthread.so
>> /lib/libpthread-0.9.so.new
>> mv -f /lib/libpthread-0.9.so.new /lib/libpthread-0.9.so
>> echo libpthread-0.9.so /lib/libpthread.so.0 >>
>> /usr/src/glibc-2.2.3/build/elf/symlink.list
>> rm -f /usr/lib/libpthread.so.new
>> /bin/sh ../scripts/rellns-sh /lib/libpthread.so.0 /usr/lib/libpthread.so.new
>> mv -f /usr/lib/libpthread.so.new /usr/lib/libpthread.so
>> /bin/install -c -m 644 /usr/src/glibc-2.2.3/build/linuxthreads/libpthread.a
>> /usr/lib/libpthread.a
>> : /usr/lib/libpthread.a
>> make[2]: Leaving directory `/usr/src/glibc-2.2.3/linuxthreads'
>> make  -C resolv subdir_install
>> make: /lib/libc.so.6: version `GLIBC_2.2.3' not found (required by
>> /lib/libpthread.so.0)
>> make[1]: *** [resolv/subdir_install] Error 1
>> make[1]: Leaving directory `/usr/src/glibc-2.2.3'
>> make: *** [install] Error 2
>> 
>> This happens as (at least my) make (make-3.79.1) is linked against
>> libpthread.so.0 which is installed before the symbolic link /lib/libc.so.6
>> is
>> set up to point to the new glibc. Workaround is to use a statically linked
>> make
>> during installation (if you have one available).
> 
> I'll forward this,
> Andreas
> 
> 
> P.S. see http://gcc.gnu.org/ml/gcc-patches/2001-03/msg01187.html
> 
> 2001-03-16  Jakub Jelinek  <address@hidden>
> 
>         * crtstuff.c (init_dummy): Use CRT_END_INIT_DUMMY if defined.
>         Remove ia32 linux PIC kludge and move it...
>         * config/i386/linux.h (CRT_END_INIT_DUMMY): ...here.
> 
> --- gcc/config/i386/linux.h.jj  Mon Mar 12 11:45:15 2001
> +++ gcc/config/i386/linux.h     Fri Mar 16 18:52:31 2001
> @@ -170,3 +170,21 @@ Boston, MA 02111-1307, USA.  */
>      }                                                                  \
>    } while (0)
>  #endif
> +
> +#if defined(__PIC__) && defined (USE_GNULIBC_1)
> +/* This is a kludge. The i386 GNU/Linux dynamic linker needs ___brk_addr,
> +   __environ and atexit (). We have to make sure they are in the .dynsym
> +   section. We accomplish it by making a dummy call here. This
> +   code is never reached.  */
> +
> +#define CRT_END_INIT_DUMMY             \
> +  do                                   \
> +    {                                  \
> +      extern void *___brk_addr;                \
> +      extern char **__environ;         \
> +                                       \
> +      ___brk_addr = __environ;         \
> +      atexit (0);                      \
> +    }                                  \
> +  while (0)
> +#endif
> ============================================================
> Index: gcc/crtstuff.c
> --- gcc/crtstuff.c    1999/03/23 00:43:51     1.18
> +++ gcc/crtstuff.c    2001/03/19 10:21:44
> @@ -379,20 +379,8 @@
>    FORCE_INIT_SECTION_ALIGN;
>  #endif
>    asm (TEXT_SECTION_ASM_OP);
> -
> -/* This is a kludge. The i386 GNU/Linux dynamic linker needs ___brk_addr,
> -   __environ and atexit (). We have to make sure they are in the .dynsym
> -   section. We accomplish it by making a dummy call here. This
> -   code is never reached.  */
> - 
> -#if defined(__linux__) && defined(__PIC__) && defined(__i386__)
> -  {
> -    extern void *___brk_addr;
> -    extern char **__environ;
> -
> -    ___brk_addr = __environ;
> -    atexit ();
> -  }
> +#ifdef CRT_END_INIT_DUMMY
> +  CRT_END_INIT_DUMMY;
>  #endif
>  }
>  
> 
> 
> -- 
>  Andreas Jaeger
>   SuSE Labs address@hidden
>    private address@hidden
>     http://www.suse.de/~aj
> 

Andreas Steinmetz
D.O.M. Datenverarbeitung GmbH


reply via email to

[Prev in Thread] Current Thread [Next in Thread]