bug-glibc
[Top][All Lists]
Advanced

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

Re: fix for atexit() bug in glibc 2.2.3


From: Andreas Jaeger
Subject: Re: fix for atexit() bug in glibc 2.2.3
Date: 20 May 2001 09:52:21 +0200
User-agent: Gnus/5.090004 (Oort Gnus v0.04) XEmacs/21.1 (Channel Islands)

Hi Mark and Franz, FYI: it seems that even gcc 2.95.3 on i686 miscompiles
weak symbols.

Andreas, this is a compiler bug you encounter.  Franz has some patches
to fix this and I hope he'll point you to them, otherwise search the
GCC mailing list archives.

Andreas

Andreas Steinmetz <address@hidden> writes:

> 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
> 

-- 
 Andreas Jaeger
  SuSE Labs address@hidden
   private address@hidden
    http://www.suse.de/~aj



reply via email to

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