Bypass npth_unprotect/protect when npth has not yet been initialized.
authorWerner Koch <wk@gnupg.org>
Mon, 21 Nov 2016 08:35:26 +0000 (09:35 +0100)
committerWerner Koch <wk@gnupg.org>
Mon, 21 Nov 2016 08:35:26 +0000 (09:35 +0100)
* src/npth.c (initialized_or_any_threads): New variable.
(npth_init): Set var.
(npth_create): Set var.
(npth_unprotect, npth_protect): Shortcut if not initialized.

* w32/npth.c (initialized_or_any_threads): New variable.
(npth_init): Set var.
(npth_unprotect, npth_protect): Shortcut if not initialized.

Signed-off-by: Werner Koch <wk@gnupg.org>
src/npth.c
w32/npth.c

index c332338..bfcf0e9 100644 (file)
@@ -93,6 +93,14 @@ static sem_t *sceptre = &sceptre_buffer;
    variable.  */
 static volatile pthread_t main_thread;
 
+/* This flag is set as soon as npth_init has been called or if any
+ * thread has been created.  It will never be cleared again.  The only
+ * purpose is to make npth_protect and npth_unprotect more robust in
+ * that they can be shortcut when npth_init has not yet been called.
+ * This is important for libraries which want to support nPth by using
+ * those two functions but may have be initialized before pPth. */
+static int initialized_or_any_threads;
+
 /* Systems that don't have pthread_mutex_timedlock get a busy wait
    implementation that probes the lock every BUSY_WAIT_INTERVAL
    milliseconds.  */
@@ -203,6 +211,9 @@ npth_init (void)
 
   main_thread = pthread_self();
 
+  /* Track that we have been initialized.  */
+  initialized_or_any_threads |= 1;
+
   /* Better reset ERRNO so that we know that it has been set by
      sem_init.  */
   errno = 0;
@@ -315,6 +326,8 @@ npth_create (npth_t *thread, const npth_attr_t *attr,
   if (!startup)
     return errno;
 
+  initialized_or_any_threads |= 2;
+
   startup->start_routine = start_routine;
   startup->arg = arg;
   err = pthread_create (thread, attr, thread_start, startup);
@@ -716,14 +729,23 @@ npth_sendmsg (int fd, const struct msghdr *msg, int flags)
 void
 npth_unprotect (void)
 {
-  ENTER();
+  /* If we are not initialized we may not access the semaphore and
+   * thus we shortcut it. Note that in this case the unprotect/protect
+   * is not needed.  For failsafe reasons if an nPth thread has ever
+   * been created but nPth has accidentally not initialized we do not
+   * shortcut so that a stack backtrace (due to the access of the
+   * uninitialized semaphore) is more expressive.  */
+  if (initialized_or_any_threads)
+    ENTER();
 }
 
 
 void
 npth_protect (void)
 {
-  LEAVE();
+  /* See npth_unprotect for commentary.  */
+  if (initialized_or_any_threads)
+    LEAVE();
 }
 
 
index ddd2b40..67752dc 100644 (file)
    global data such as the thread_table.  */
 static CRITICAL_SECTION sceptre;
 
+/* This flag is set as soon as npth_init has been called or if any
+ * thread has been created.  It will never be cleared again.  The only
+ * purpose is to make npth_protect and npth_unprotect more robust in
+ * that they can be shortcut when npth_init has not yet been called.
+ * This is important for libraries which want to support nPth by using
+ * those two functions but may have be initialized before pPth. */
+static int initialized_or_any_threads;
+
+
 typedef struct npth_impl_s *npth_impl_t;
 #define MAX_THREADS 1024
 #define INVALID_THREAD_ID 0
@@ -321,6 +330,9 @@ npth_init (void)
 
   InitializeCriticalSection (&sceptre);
 
+  /* Track that we have been initialized.  */
+  initialized_or_any_threads = 1;
+
   /* Fake a thread table item for the main thread.  */
   tls_index = TlsAlloc();
   if (tls_index == TLS_OUT_OF_INDEXES)
@@ -1746,14 +1758,23 @@ npth_sendmsg (int fd, const struct msghdr *msg, int flags)
 void
 npth_unprotect (void)
 {
-  ENTER();
+  /* If we are not initialized we may not access the semaphore and
+   * thus we shortcut it. Note that in this case the unprotect/protect
+   * is not needed.  For failsafe reasons if an nPth thread has ever
+   * been created but nPth has accidentally not initialized we do not
+   * shortcut so that a stack backtrace (due to the access of the
+   * uninitialized semaphore) is more expressive.  */
+  if (initialized_or_any_threads)
+    ENTER();
 }
 
 
 void
 npth_protect (void)
 {
-  LEAVE();
+  /* See npth_unprotect for commentary.  */
+  if (initialized_or_any_threads)
+    LEAVE();
 }
 
 \f