This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

PATCH to support __cxa_atexit



There's a long-standing bug in many C++ implementations that can be
seen with the following program:
  
  test.C
  ======
  #include <dlfcn.h>
  #include <stdio.h>

  struct S {
    ~S () { printf ("Goodbye, world.\n"); }
  };

  typedef void (*fn_t)();

  void f () { static S s; }

  int main ()
  {
    void *lib1;
    fn_t gp;

    printf ("In main\n");
    lib1 = dlopen ("/home/mitchell/tmp/test2.so", RTLD_LAZY);
    gp = (fn_t) dlsym (lib1, "g");
    (*gp) ();
    printf ("Back in main\n");
    f ();
    dlclose (lib1);
    exit (0);
  }

  test2.C
  =======
  #include <stdio.h>

  struct T {
    ~T () { printf ("Shared object going away...\n"); }
  };

  extern "C" void g ()
  {
    printf ("In shared object\n");
    static T t; 
  }

Now, suppose that `test2.C' is compiled into a shared library, and
`test.C' is used as the main program.  When run, we get a crash:

  linux1.codesourcery.com% test-g++2 -shared -o test2.so test2.C
  linux1.codesourcery.com% test-g++2 test.C -ldl
  linux1.codesourcery.com% ./a.out
  In main
  In shared object
  Back in main
  Goodbye, world.
  Segmentation fault

The reason is that when the main program exits we run the destructor
for the local static `t' in the shared object.  But, the shared object
is already gone.

The IA64 C++ ABI (also the new g++ ABI) addresses this problem by
adding two new library entry points: `__cxa_atexit' and
`__cxa_finalize'. It is implied that these new entry points will
become a part of the C library; the require integration with `atexit'
and `exit'.

These patches make G++ use these facilities, under control of a new
switch (-fuse-cxa-atexit).  I'll also submit GNU libc patches to the
appropriate list, but, in theory, these facilities could be used on
systems where the C library is not GNU libc, providing that it
supports __cxa_atexit/__cxa_finalize.

This message contains the patches to language-independent code.  I'd
particularly like an expert's opinion on the crtstuff.c patch, even
though I've checked it in already.  The next message will contain the
C++ front-end patches.

With these changes, the program does:

  linux1.codesourcery.com% ./a.out
  In main
  In shared object
  Back in main
  Shared object going away...
  Goodbye, world.

which is correct.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

1999-12-16  Mark Mitchell  <mark@codesourcery.com>

	* crtstuff.c (__dso_handle): Declare.
	(__cxa_finalize): Likewise.
	(do_global_dtors_aux): Call __cxa_finalize if __dso_handle is
	non-NULL.

	* invoke.texi: Document -fuse-cxa-atexit.
	
	* tree.h (ptr_type_node): Document.
	(const_ptr_type_node): Likewise.

Index: crtstuff.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/crtstuff.c,v
retrieving revision 1.20
diff -c -p -r1.20 crtstuff.c
*** crtstuff.c	1999/09/20 18:59:09	1.20
--- crtstuff.c	1999/12/17 06:36:26
*************** typedef void (*func_ptr) (void);
*** 129,134 ****
--- 129,147 ----
  
  #ifdef OBJECT_FORMAT_ELF
  
+ /* Declare the __dso_handle variable.  It should have a unique value
+    in every shared-object; in a main program its value is zero.  */
+ 
+ #ifdef CRTSTUFFS_O
+ void *__dso_handle = &__dso_handle;
+ #else
+ void *__dso_handle = 0;
+ #endif
+ 
+ /* The __cxa_finalize function may not be available so we use only a
+    weak declaration.  */
+ extern void __cxa_finalize (void *) TARGET_ATTRIBUTE_WEAK;
+ 
  /* Run all the global destructors on exit from the program.  */
   
  /* Some systems place the number of pointers in the first word of the
*************** __do_global_dtors_aux (void)
*** 158,163 ****
--- 171,179 ----
  
    if (completed)
      return;
+ 
+   if (__dso_handle && __cxa_finalize)
+     __cxa_finalize (__dso_handle);
  
    while (*p)
      {
Index: invoke.texi
===================================================================
RCS file: /cvs/gcc/egcs/gcc/invoke.texi,v
retrieving revision 1.163
diff -c -p -r1.163 invoke.texi
*** invoke.texi	1999/12/10 21:00:33	1.163
--- invoke.texi	1999/12/17 06:36:32
*************** in the following sections.
*** 109,115 ****
  -fhonor-std -fhuge-objects  -fno-implicit-templates  -finit-priority
  -fno-implement-inlines -fname-mangling-version-@var{n}  -fno-default-inline  
  -foperator-names  -fno-optional-diags  -fpermissive -frepo  -fstrict-prototype
! -fsquangle  -ftemplate-depth-@var{n} -fvtable-thunks
  -nostdinc++  -Wctor-dtor-privacy -Wno-deprecated -Weffc++  
  -Wno-non-template-friend 
  -Wnon-virtual-dtor  -Wold-style-cast  -Woverloaded-virtual  
--- 109,115 ----
  -fhonor-std -fhuge-objects  -fno-implicit-templates  -finit-priority
  -fno-implement-inlines -fname-mangling-version-@var{n}  -fno-default-inline  
  -foperator-names  -fno-optional-diags  -fpermissive -frepo  -fstrict-prototype
! -fsquangle  -ftemplate-depth-@var{n} -fuse-cxa-atexit -fvtable-thunks
  -nostdinc++  -Wctor-dtor-privacy -Wno-deprecated -Weffc++  
  -Wno-non-template-friend 
  -Wnon-virtual-dtor  -Wold-style-cast  -Woverloaded-virtual  
*************** Set the maximum instantiation depth for 
*** 1216,1221 ****
--- 1216,1228 ----
  A limit on the template instantiation depth is needed to detect
  endless recursions during template class instantiation. ANSI/ISO C++
  conforming programs must not rely on a maximum depth greater than 17.
+ 
+ @item -fuse-cxa-atexit
+ Register destructors for objects with static storage duration with the
+ @code{__cxa_atexit} function rather than the @code{atexit} function.
+ This option is required for fully standards-compliant handling of static
+ destructors, but will only work if your C library supports
+ @code{__cxa_atexit}.
  
  @item -fvtable-thunks
  Use @samp{thunks} to implement the virtual function dispatch table
Index: tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/tree.h,v
retrieving revision 1.108
diff -c -p -r1.108 tree.h
*** tree.h	1999/12/05 17:53:14	1.108
--- tree.h	1999/12/17 06:36:34
*************** extern tree global_trees[TI_MAX];
*** 1539,1545 ****
--- 1539,1547 ----
  #define complex_long_double_type_node	global_trees[TI_COMPLEX_LONG_DOUBLE_TYPE]
  
  #define void_type_node			global_trees[TI_VOID_TYPE]
+ /* The C type `void *'.  */
  #define ptr_type_node			global_trees[TI_PTR_TYPE]
+ /* The C type `const void *'.  */
  #define const_ptr_type_node		global_trees[TI_CONST_PTR_TYPE]
  #define ptrdiff_type_node		global_trees[TI_PTRDIFF_TYPE]
  #define va_list_type_node		global_trees[TI_VA_LIST_TYPE]


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]