git » libfiu » commit a959d62

preload/posix: Enforce initialization of ferror hash table

author Alberto Bertogli
2018-12-13 13:43:29 UTC
committer Alberto Bertogli
2018-12-13 14:01:40 UTC
parent 1cc90cc7516335092908670d64d96ff9b9333283

preload/posix: Enforce initialization of ferror hash table

The hash table we use to keep track of ferrors is currently initialized
via a constructor.

If for some reason the functions using the table are run before the
constructor has had a chance to run (for example, early init of other
libraries), then the library crashes because it tries to operate on a
NULL hash table.

This patch fixes this by always checking that the table has been
initialized before using it, and it does so in a lazy way (purely for
convenience).

Thanks to Pietro Oliva for finding this issue, and the detailed bug
report!

preload/posix/modules/posix.custom.c +11 -1

diff --git a/preload/posix/modules/posix.custom.c b/preload/posix/modules/posix.custom.c
index e6eea8f..c4bcfd9 100644
--- a/preload/posix/modules/posix.custom.c
+++ b/preload/posix/modules/posix.custom.c
@@ -198,8 +198,9 @@ mkwrap_bottom(open64, (pathname, flags, mode))
  */
 static hash_t *ferror_hash_table;
 static pthread_mutex_t ferror_hash_table_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t ferror_hash_table_is_initialized = PTHREAD_ONCE_INIT;
 
-static void constructor_attr(200) _fiu_init_ferror_hash_table(void)
+static void _fiu_init_ferror_hash_table(void)
 {
 	rec_inc();
 	pthread_mutex_lock(&ferror_hash_table_mutex);
@@ -227,6 +228,9 @@ void set_ferror(void * stream)
 	char key[STREAM_KEY_SIZE];
 	stream_to_key(stream, key);
 
+	pthread_once(&ferror_hash_table_is_initialized,
+			_fiu_init_ferror_hash_table);
+
 	pthread_mutex_lock(&ferror_hash_table_mutex);
 
 	// Use a dummy the value; we don't care about it, we only need to be able to
@@ -241,6 +245,9 @@ static int get_ferror(void * stream)
 	char key[STREAM_KEY_SIZE];
 	stream_to_key(stream, key);
 
+	pthread_once(&ferror_hash_table_is_initialized,
+			_fiu_init_ferror_hash_table);
+
 	pthread_mutex_lock(&ferror_hash_table_mutex);
 
 	void *value = hash_get(ferror_hash_table, key);
@@ -255,6 +262,9 @@ static void clear_ferror(void * stream)
 	char key[STREAM_KEY_SIZE];
 	stream_to_key(stream, key);
 
+	pthread_once(&ferror_hash_table_is_initialized,
+			_fiu_init_ferror_hash_table);
+
 	pthread_mutex_lock(&ferror_hash_table_mutex);
 
 	hash_del(ferror_hash_table, key);