Skip to content
  • Simon McVittie's avatar
    strfuncs: Don't let get_C_locale() clobber errno · e807966b
    Simon McVittie authored
    Some callers of `g_ascii_strtoull()` and similar functions assume that
    they can use this pattern, similar to what they might do for
    Standard C `strtoull()`:
    
        errno = 0;
        result = g_ascii_strtoull (nptr, endptr, base);
        saved_errno = errno;
    
        if (saved_errno != 0)
          g_printerr ("error parsing %s\n", nptr);
    
    This is based on the fact that it is non-trivial to tell whether
    `strtoull()` and related functions succeeded (in which case the value
    of `errno` is unspecified) or failed (in which case `errno` is valid).
    For example, POSIX `strtoul(3)` suggests this pattern:
    
    > Since 0, `ULONG_MAX`, and `ULLONG_MAX` are returned on error and are
    > also valid returns on success, an application wishing to check for
    > error situations should set `errno` to 0, then call `strtoul()` or
    > `strtoull()`, then check `errno`.
    
    However, `g_ascii_strtoull()` does not *only* call a function resembling
    `strtoull()` (`strtoull_l()` or its reimplementation
    `g_parse_long_long()`): it also calls `get_C_locale()`, which wraps
    `newlocale()`. Even if `newlocale()` succeeds (which in practice we
    expect and assume that it will), it is valid for it to clobber `errno`.
    For example, it might attempt to open a file that only conditionally
    exists, which would leave `errno` set to `ENOENT`.
    
    This is difficult to reproduce in practice: I encountered what I
    believe to be this bug when compiling GLib-based software for i386 in a
    Debian 12 derivative via an Open Build Service instance, but I could
    not reproduce the bug in a similar chroot environment locally, and I
    also could not reproduce the bug when compiling for x86_64 or for a
    Debian 10, 11 or 13 derivative on the same Open Build Service instance.
    It also cannot be reproduced via the GTest framework, because
    `g_test_init()` indirectly calls `g_ascii_strtoull()`, resulting in
    the call to `newlocale()` already having happened by the time we enter
    test code.
    
    Resolves: GNOME/glib#3418
    
    
    Signed-off-by: default avatarSimon McVittie <smcv@collabora.com>
    e807966b