[glib/th/g-ascii-strtoll-preserve-errno] glib: avoid setting wrong errno in g_ascii_strtoll() et all.



commit d550456cbf1b1ffaa92d76e1d35d2ae367b0996f
Author: Thomas Haller <thaller redhat com>
Date:   Mon May 4 22:05:58 2020 +0200

    glib: avoid setting wrong errno in g_ascii_strtoll() et all.
    
    In CI tests of NetworkManager, it happened sporadically that
    g_ascii_strtoll() for "10" would set errno to EAGAIN. The code
    in NetworkManager first initializes errno to zero and does not
    expect that g_ascii_strtoll() would set errno in case of success.
    
    Since we employed a workaround (to retry) in case of EAGAIN,
    the CI failures appear to be gone ([2]).
    
    It's not clear to me how that happened, but I can only imagine that
    it was due to newlocale(). So, do two things:
    
    - ensure that we remember and restore errno while calling newlocale().
    
    - under the assumption that newlocale might fail sporadically with
      EAGAIN, retry a few times. Since we cache the returned locale for
      all future invocations, it's rather important that we get this right.
    
    [1] https://bugzilla.redhat.com/show_bug.cgi?id=1797915
    [2] 
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/commit/d342fa267d59cd317cc3cc798824c70b1158ff61

 glib/gstrfuncs.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)
---
diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c
index f34aca29d..29aa91c21 100644
--- a/glib/gstrfuncs.c
+++ b/glib/gstrfuncs.c
@@ -328,13 +328,26 @@ const guint16 * const g_ascii_table = ascii_table_data;
 static locale_t
 get_C_locale (void)
 {
-  static gsize initialized = FALSE;
-  static locale_t C_locale = NULL;
+  static gsize initialized = 0;
+  static locale_t C_locale;
 
   if (g_once_init_enter (&initialized))
     {
-      C_locale = newlocale (LC_ALL_MASK, "C", NULL);
+      int errsv = errno;
+      int try_count = 0;
+      locale_t l;
+
+again:
+      l = newlocale (LC_ALL_MASK, "C", NULL);
+      if (   l == (locale_t) 0
+          && ++try_count < 3)
+        {
+          /* creating the C locale failed. This is unexpected. Try again... */
+          goto again;
+        }
+
       g_once_init_leave (&initialized, TRUE);
+      errno = errsv;
     }
 
   return C_locale;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]