git » libfiu » commit 8b795ac

preload/posix: Fix initialization when building without constr. priorities

author Alberto Bertogli
2009-10-15 02:21:08 UTC
committer Alberto Bertogli
2009-10-15 02:21:08 UTC
parent 0a45ab3aa3660b3d7e9116336aa164ac28f21ece

preload/posix: Fix initialization when building without constr. priorities

When building without constructor priorities, the order in which they are
called is not specified.

This caused several strange bugs (segfaults and hangs) mostly because
three issues:

 - Wrappers wanted to call the original libc version, but _fiu_init()
   hadn't performed the dlopen() yet.
 - _fiu_init() got called with _fiu_called > 0, but it resetted it back
   to 0, so the reference counter was left wrong.
 - Wrappers were called before their own constructor (i.e. from another
   constructor).

This patch fixes those things by making the wrapper constructors to call
_fiu_init() by hand if _fiu_libc == NULL, making _fiu_init() cope with
that, and fixing the wrappers to call their own constructors if they
haven't been called yet.

Thanks to Stas Oskin for the detailed bug report.

Signed-off-by: Alberto Bertogli <albertito@blitiri.com.ar>

preload/posix/codegen.c +15 -4
preload/posix/codegen.h +8 -0
preload/posix/modules/posix.custom.c +4 -0

diff --git a/preload/posix/codegen.c b/preload/posix/codegen.c
index 0f078e8..71644c5 100644
--- a/preload/posix/codegen.c
+++ b/preload/posix/codegen.c
@@ -9,7 +9,7 @@
 void *_fiu_libc;
 
 /* Recursion counter, per-thread */
-int __thread _fiu_called;
+int __thread _fiu_called = 0;
 
 /* Let the user know if there is no constructor priorities support, just in
  * case there are bugs when building/running without them */
@@ -17,17 +17,28 @@ int __thread _fiu_called;
 #warning "Building without using constructor priorities"
 #endif
 
-static void constructor_attr(200) _fiu_init(void)
+void constructor_attr(200) _fiu_init(void)
 {
-	_fiu_called = 0;
+	static int initialized = 0;
+
+	/* When built without constructor priorities, we could be called more
+	 * than once during the initialization phase: one because we're marked
+	 * as a constructor, and another when one of the other constructors
+	 * sees that it doesn't have _fiu_libc set. */
+
+	printd("_fiu_init() start (%d)\n", initialized);
+	if (initialized)
+		goto exit;
 
 	_fiu_libc = dlopen("libc.so.6", RTLD_NOW);
 	if (_fiu_libc == NULL) {
 		fprintf(stderr, "Error loading libc: %s\n", dlerror());
 		exit(1);
 	}
+	initialized = 1;
 
-	printd("done\n");
+exit:
+	printd("_fiu_init() done\n");
 }
 
 /* this runs after all function-specific constructors */
diff --git a/preload/posix/codegen.h b/preload/posix/codegen.h
index c90a951..6a3444e 100644
--- a/preload/posix/codegen.h
+++ b/preload/posix/codegen.h
@@ -8,6 +8,7 @@
 
 /* Pointer to the dynamically loaded library */
 extern void *_fiu_libc;
+void _fiu_init(void);
 
 /* Recursion counter, per-thread */
 extern int __thread _fiu_called;
@@ -75,6 +76,10 @@ extern int __thread _fiu_called;
 	static void constructor_attr(201) _fiu_init_##NAME(void) \
 	{							\
 		rec_inc();					\
+								\
+		if (_fiu_libc == NULL)				\
+			_fiu_init();				\
+								\
 		_fiu_orig_##NAME = (RTYPE (*) PARAMST)		\
 				dlsym(_fiu_libc, #NAME);	\
 		rec_dec();					\
@@ -146,6 +151,9 @@ extern int __thread _fiu_called;
 
 #define mkwrap_bottom(NAME, PARAMSN)				\
 								\
+		if (_fiu_orig_##NAME == NULL)			\
+			_fiu_init_##NAME();			\
+								\
 		r = (*_fiu_orig_##NAME) PARAMSN;		\
 								\
 	exit:							\
diff --git a/preload/posix/modules/posix.custom.c b/preload/posix/modules/posix.custom.c
index 84322a5..5caff6f 100644
--- a/preload/posix/modules/posix.custom.c
+++ b/preload/posix/modules/posix.custom.c
@@ -21,6 +21,10 @@ static int (*_fiu_orig_open) (const char *pathname, int flags, ...) = NULL;
 static void constructor_attr(201) _fiu_init_open(void)
 {
 	rec_inc();
+
+	if (_fiu_libc == NULL)
+		_fiu_init();
+
 	_fiu_orig_open = (int (*) (const char *, int, ...))
 			 dlsym(_fiu_libc, "open");
 	rec_dec();