sparc64/119289: C++ throw/catch segfaults

Marius Strobl marius at alchemy.franken.de
Thu Jan 3 11:00:10 PST 2008


The following reply was made to PR sparc64/119289; it has been noted by GNATS.

From: Marius Strobl <marius at alchemy.franken.de>
To: bug-followup at FreeBSD.org, Stephen Hurd <shurd at sasktel.net>,
        kan at FreeBSD.org, obrien at FreeBSD.org
Cc: re at FreeBSD.org
Subject: Re: sparc64/119289: C++ throw/catch segfaults
Date: Thu, 3 Jan 2008 19:39:30 +0100

 On Thu, Jan 03, 2008 at 03:29:48AM +0000, Stephen Hurd wrote:
 > 
 > Even the most simple trow/catch programs appear to crash in the __cxa_* functions.  this appears to be at least part of the problem with OpenEXR.
 > >How-To-Repeat:
 > The following simple program crashes with the following backtrace:
 > 
 > (gdb) r
 > Starting program: /home/admin/a.out 
 > start
 > Inside try block
 > Caught an exception -- value is: 99
 > 
 > Program received signal SIGSEGV, Segmentation fault.
 > 0x0000000040396aac in __cxa_end_catch () from /usr/lib/libstdc++.so.6
 > (gdb) bt
 > #0  0x0000000040396aac in __cxa_end_catch () from /usr/lib/libstdc++.so.6
 > #1  0x0000000000100f38 in main () at test.cpp:13
 > 
 > 
 > // A simple exception handling example.
 > #include <iostream>
 > int main()
 > {
 >   std::cout << "start\n";
 > try
 > {   // start a try block
 >     std::cout << "Inside try block\n";
 >     throw 99; // throw an error
 >     std::cout << "This will not execute";
 >   }
 > 
 > catch (int i)
 >  {   // catch an error
 >     std::cout << "Caught an exception -- value is: ";
 >     std::cout << i << "\n";
 >   }
 > 
 >   std::cout << "end";
 > 
 >   return 0;
 > }
 > 
 
 The underlying problem (from a libstdc++ perspective) is that with
 GCC 4.2 __gthread_active_p() always returns 1, regardless of whether
 the program was compiled with -pthread or not. This is even a MI
 problem:
 
 marius at alchemy:/home/marius > uname -a
 FreeBSD alchemy.franken.de 8.0-CURRENT FreeBSD 8.0-CURRENT #0: Thu Dec  6 15:47:30 CET 2007     root at alchemy.franken.de:/tmp/obj/usr/src/sys/alchemy  i386
 marius at alchemy:/home/marius > cat test.cc
 #include <iostream>
 
 int main()
 {
 
 	std::cout << "__gthread_active_p=" << __gthread_active_p() << "\n";
 	return (0);
 }
 marius at alchemy:/home/marius > g++ -o test test.cc
 marius at alchemy:/home/marius > ./test
 __gthread_active_p=1
 marius at alchemy:/home/marius > g++ -o test -pthread test.cc
 marius at alchemy:/home/marius > ./test
 __gthread_active_p=1
 
 
 For reference, with GCC 3.4.6 on a FreeBSD 6.2-STABLE:
 
 marius at vnv:/home/marius > uname -a
 FreeBSD vnv.invalid 6.2-STABLE FreeBSD 6.2-STABLE #6: Wed Jun 13 09:21:13 CEST 2007     root at vnv.invalid:/usr/obj/usr/src/sys/vnv  i386
 marius at vnv:/home/marius > cat test.cc
 #include <iostream>
 
 int main()
 {
 
 	std::cout << "__gthread_active_p=" << __gthread_active_p() << "\n";
 	return (0);
 }
 marius at vnv:/home/marius > g++ -o test test.cc
 marius at vnv:/home/marius > ./test
 __gthread_active_p=0
 marius at vnv:/home/marius > g++ -o test -pthread test.cc
 marius at vnv:/home/marius > ./test
 __gthread_active_p=1
 
 
 With GCC 4.2 __gthread_active_p() always returning 1 breaks the
 exception handling of libstdc++ for non-threaded programs on
 platforms without TLS support due to the way it implements EH
 there, i.e. on FreeBSD/arm and FreeBSD/sparc64 due to the lack
 of TLS support for these archs in the ancient base binutils.
 However, given that __gthread_active_p() is also used in a couple
 of other places besides EH, this bug has great potential to also
 cause problems in other areas and on all archs.
 
 The reason for this false positive is that gthr-posix.h checks
 for the existence of pthread_cancel() and FreeBSD 7 supplies
 a stub for it in libc since lib/libc/gen/_pthread_stubs.c rev.
 1.13. A solution for this is to use the __gthread_active_p()
 version that libstdc++ uses for Solaris and which actively
 checks for a working POSIX threads implementation (if such
 functions exist) instead of checking for the mere existence
 of corresponding functions. The patch below changes gthr-posix.h
 accordingly (in order to use it it's probably best to go through
 buildworld and installworld in order to ensure all base consumers
 of gthr-posix.h are rebuilt and all copies of gthr-posix.h are
 also updated).
 Does anyone object to me committing that patch to the vendor
 branch?
 
 Marius
 
 Index: gthr-posix.h
 ===================================================================
 RCS file: /usr/data/bsd/cvs/fbsd/src/contrib/gcc/gthr-posix.h,v
 retrieving revision 1.1.1.8
 diff -u -r1.1.1.8 gthr-posix.h
 --- gthr-posix.h	14 Aug 2007 02:37:31 -0000	1.1.1.8
 +++ gthr-posix.h	3 Jan 2008 14:54:51 -0000
 @@ -152,9 +152,13 @@
     it is passed so we cannot pretend that the interface is active if -pthreads
     is not specified.  On Solaris 2.5.1, the interface is not exposed at all so
     we need to play the usual game with weak symbols.  On Solaris 10 and up, a
 -   working interface is always exposed.  */
 +   working interface is always exposed.
 +   On FreeBSD 6 and 7 the libc also exposes a dummy POSIX threads interface,
 +   similar to what Solaris 2.6 up to 9 does.  FreeBSD >= 700014 even provides
 +   a pthread_cancel stub in libc, which means the alternate __gthread_active_p
 +   below can't be used there.  */
  
 -#if defined(__sun) && defined(__svr4__)
 +#if defined(__FreeBSD__) || (defined(__sun) && defined(__svr4__))
  
  static volatile int __gthread_active = -1;
  
 @@ -197,7 +201,7 @@
    return __gthread_active_latest_value != 0;
  }
  
 -#else /* not Solaris */
 +#else /* neither FreeBSD nor Solaris */
  
  static inline int
  __gthread_active_p (void)
 @@ -207,7 +211,7 @@
    return __gthread_active_ptr != 0;
  }
  
 -#endif /* Solaris */
 +#endif /* FreeBSD or Solaris */
  
  #else /* not SUPPORTS_WEAK */
  
 


More information about the freebsd-sparc64 mailing list