]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Fix incorrect double-checked locking related to _res_hconf.initialized.
authorTorvald Riegel <triegel@redhat.com>
Wed, 17 Aug 2016 11:56:11 +0000 (13:56 +0200)
committerTorvald Riegel <triegel@redhat.com>
Thu, 18 Aug 2016 18:53:37 +0000 (20:53 +0200)
_res_hconf.initialized was not suitable for use in a multi-threaded
environment due to the lack of atomics and memory barriers.  Use of it was
also unnecessary because _res_hconf_init did the right thing by using
__libc_once.  This patch fixes the glibc-internal uses by just calling
_res_hconf_init unconditionally, and switches to a release MO atomic store
for _res_hconf.initialized to fix the glibc side of the synchronization
problem (which will maintain backward compatibility, but cannot fix the
lack of acquire MO on any glibc-external loads).

[BZ #20477]
* resolv/res_hconf.c (do_init): Use atomic access.
* resolv/res_hconf.h: Add comments.
* nscd/aicache.c (addhstaiX): Call _res_hconf_init unconditionally.
* nss/getXXbyYY_r.c (REENTRANT_NAME): Likewise.
* sysdeps/posix/getaddrinfo.c (gaih_inet): Likewise.

ChangeLog
nscd/aicache.c
nss/getXXbyYY_r.c
resolv/res_hconf.c
resolv/res_hconf.h
sysdeps/posix/getaddrinfo.c

index 59c68d8b9d0df31b6a7d975dca2da730a1a73a50..bc2c353c2e974a9e13561686acd65b84a5fa1f99 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2016-08-18  Torvald Riegel  <triegel@redhat.com>
+
+       [BZ #20477]
+       * resolv/res_hconf.c (do_init): Use atomic access.
+       * resolv/res_hconf.h: Add comments.
+       * nscd/aicache.c (addhstaiX): Call _res_hconf_init unconditionally.
+       * nss/getXXbyYY_r.c (REENTRANT_NAME): Likewise.
+       * sysdeps/posix/getaddrinfo.c (gaih_inet): Likewise.
+
 2016-08-18  Stefan Liebler  <stli@linux.vnet.ibm.com>
 
        * sysdeps/ieee754/dbl-64/k_rem_pio2.c (__kernel_rem_pio2):
index a2e6cf8475997896b1a5685813e0229ea2c69064..32c8f57b4111c8228d2fb06789f288d650e79379 100644 (file)
@@ -101,8 +101,7 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
   nip = hosts_database;
 
   /* Initialize configurations.  */
-  if (__glibc_unlikely (!_res_hconf.initialized))
-    _res_hconf_init ();
+  _res_hconf_init ();
   if (__res_maybe_init (&_res, 0) == -1)
     no_more = 1;
 
index 93af2538ecdee1cbd4b50b97a7c09b01c5f101ab..18d3ad68cc0560f6e7b460c049db6a4a15c483dd 100644 (file)
@@ -274,8 +274,7 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
            }
 #endif /* need _res */
 #ifdef NEED__RES_HCONF
-         if (!_res_hconf.initialized)
-           _res_hconf_init ();
+         _res_hconf_init ();
 #endif /* need _res_hconf */
 
          void *tmp_ptr = fct.l;
index 5cd128916d83c965937da7380708707f52e830a3..093c26837f718fdc1b1f1e473242f97036f87981 100644 (file)
@@ -348,7 +348,8 @@ do_init (void)
       arg_trimdomain_list (ENV_TRIM_OVERR, 1, envval);
     }
 
-  _res_hconf.initialized = 1;
+  /* See comments on the declaration of _res_hconf.  */
+  atomic_store_release (&_res_hconf.initialized, 1);
 }
 
 
index b97734df9e829b37aceb9d83b970ef8e2a637217..a3d23f3e58c3bcdd3890821d46fe8f30fb54903f 100644 (file)
 
 struct hconf
 {
+  /* We keep the INITIALIZED member only for backwards compatibility.  New
+     code should just call _res_hconf_init unconditionally.  For this field
+     to be used safely, users must ensure that either (1) a call to
+     _res_hconf_init happens-before any load from INITIALIZED, or (2) an
+     assignment of zero to INITIALIZED happens-before any load from it, and
+     these loads use acquire MO if the intent is to skip calling
+     _res_hconf_init if the load returns a nonzero value.  Such acquire MO
+     loads will then synchronize with the release MO store to INITIALIZED
+     in do_init in res_hconf.c; see pthread_once for more detail.  */
   int initialized;
   int unused1;
   int unused2[4];
index 574ce08aeab48d23d1d99e5045413610917a5116..09fbc83cf805b3fb9a60bcff3461469cda1a5729 100644 (file)
@@ -816,8 +816,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
          nip = __nss_hosts_database;
 
          /* Initialize configurations.  */
-         if (__glibc_unlikely (!_res_hconf.initialized))
-           _res_hconf_init ();
+         _res_hconf_init ();
          if (__res_maybe_init (&_res, 0) == -1)
            no_more = 1;