Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 15 Apr 2019 13:03:10 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r346225 - in head: lib/libc/stdlib libexec/rtld-elf
Message-ID:  <201904151303.x3FD3As2031072@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Apr 15 13:03:09 2019
New Revision: 346225
URL: https://svnweb.freebsd.org/changeset/base/346225

Log:
  Fix order of destructors between main binary and libraries.
  
  Since inits for the main binary are run from rtld (for some time), the
  rtld_exit atexit(3) handler, which is passed from rtld to the program
  entry and installed by csu, is installed after any atexit(3) handlers
  installed by main binary constructors.  This means that rtld_exit() is
  fired before main binary handlers.
  
  Typical C++ static constructors are executed from init (either binary
  or libs) but use atexit(3) to ensure that destructors are called in
  the right order, independent of the linking order.  Also, C++
  libraries finalizers call __cxa_finalize(3) to flush library'
  atexit(3) entries.  Since atexit(3) entry is cleared after being run,
  this would be mostly innocent, except that, atexit(rtld_exit) done
  after main binary constructors, makes destructors from libraries
  executed before destructors for main.
  
  Fix by reordering atexit(rtld_exit) before inits for main binary, same
  as it happened when inits were called by csu.  Do it using new private
  libc symbol with pre-defined ABI.
  
  Reported. tested, and reviewed by:	kan
  Sponsored by:	The FreeBSD Foundation
  MFC after:	1 week

Modified:
  head/lib/libc/stdlib/Symbol.map
  head/lib/libc/stdlib/atexit.c
  head/libexec/rtld-elf/rtld.c

Modified: head/lib/libc/stdlib/Symbol.map
==============================================================================
--- head/lib/libc/stdlib/Symbol.map	Mon Apr 15 12:24:19 2019	(r346224)
+++ head/lib/libc/stdlib/Symbol.map	Mon Apr 15 13:03:09 2019	(r346225)
@@ -129,4 +129,5 @@ FBSDprivate_1.0 {
 	_system;
 	__libc_system;
 	__cxa_thread_call_dtors;
+	__libc_atexit;
 };

Modified: head/lib/libc/stdlib/atexit.c
==============================================================================
--- head/lib/libc/stdlib/atexit.c	Mon Apr 15 12:24:19 2019	(r346224)
+++ head/lib/libc/stdlib/atexit.c	Mon Apr 15 13:03:09 2019	(r346225)
@@ -142,6 +142,7 @@ atexit(void (*func)(void))
 	error = atexit_register(&fn);
 	return (error);
 }
+__weak_reference(atexit, __libc_atexit);
 
 /**
  * Register a block to be performed at exit.

Modified: head/libexec/rtld-elf/rtld.c
==============================================================================
--- head/libexec/rtld-elf/rtld.c	Mon Apr 15 12:24:19 2019	(r346224)
+++ head/libexec/rtld-elf/rtld.c	Mon Apr 15 13:03:09 2019	(r346225)
@@ -151,6 +151,7 @@ static int rtld_dirname(const char *, char *);
 static int rtld_dirname_abs(const char *, char *);
 static void *rtld_dlopen(const char *name, int fd, int mode);
 static void rtld_exit(void);
+static void rtld_nop_exit(void);
 static char *search_library_path(const char *, const char *, const char *,
     int *);
 static char *search_library_pathfds(const char *, const char *, int *);
@@ -295,6 +296,8 @@ const char *ld_path_rtld = _PATH_RTLD;
 const char *ld_standard_library_path = STANDARD_LIBRARY_PATH;
 const char *ld_env_prefix = LD_;
 
+static void (*rtld_exit_ptr)(void);
+
 /*
  * Fill in a DoneList with an allocation large enough to hold all of
  * the currently-loaded objects.  Keep this as a macro since it calls
@@ -756,6 +759,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entr
       *ld_bind_now != '\0', SYMLOOK_EARLY, &lockstate) == -1)
 	rtld_die();
 
+    rtld_exit_ptr = rtld_exit;
     if (obj_main->crt_no_init)
 	preinit_main();
     objlist_call_init(&initlist, &lockstate);
@@ -778,7 +782,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entr
     dbg("transferring control to program entry point = %p", obj_main->entry);
 
     /* Return the exit procedure and the program entry point. */
-    *exit_proc = rtld_exit;
+    *exit_proc = rtld_exit_ptr;
     *objp = obj_main;
     return (func_ptr_type) obj_main->entry;
 }
@@ -2662,6 +2666,7 @@ objlist_call_init(Objlist *list, RtldLockState *lockst
     Obj_Entry *obj;
     char *saved_msg;
     Elf_Addr *init_addr;
+    void (*reg)(void (*)(void));
     int index;
 
     /*
@@ -2690,7 +2695,16 @@ objlist_call_init(Objlist *list, RtldLockState *lockst
 	 */
 	elm->obj->init_done = true;
 	hold_object(elm->obj);
+	reg = NULL;
+	if (elm->obj == obj_main && obj_main->crt_no_init) {
+		reg = (void (*)(void (*)(void)))get_program_var_addr(
+		    "__libc_atexit", lockstate);
+	}
 	lock_release(rtld_bind_lock, lockstate);
+	if (reg != NULL) {
+		reg(rtld_exit);
+		rtld_exit_ptr = rtld_nop_exit;
+	}
 
         /*
          * It is legal to have both DT_INIT and DT_INIT_ARRAY defined.
@@ -3002,6 +3016,11 @@ rtld_exit(void)
     if (!libmap_disable)
         lm_fini();
     lock_release(rtld_bind_lock, &lockstate);
+}
+
+static void
+rtld_nop_exit(void)
+{
 }
 
 /*



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904151303.x3FD3As2031072>