From: Avinal Kumar Date: Tue, 5 May 2026 11:28:25 +0000 (+0530) Subject: intl: Fix memory leak in _nl_find_domain on allocation failure X-Git-Tag: glibc-2.44~233 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bb91c88af78e9f862728623b60fb68d3610a4b79;p=thirdparty%2Fglibc.git intl: Fix memory leak in _nl_find_domain on allocation failure When _nl_explode_name() returns -1 (out of memory) and the locale was resolved through an alias, _nl_find_domain() returns immediately without freeing the locale copy allocated earlier. Similarly, when _nl_make_l10nflist() returns NULL, the 'goto out' skips the alias_value free. Fix by nesting the _nl_make_l10nflist() call and its result handling inside 'if (mask != -1)' instead of returning early. Move the normalized_codeset free inside the same block. Both failure paths now fall through to the unconditional alias_value free at the end. Imported from GNU gettext commit 10eafd9e5. Original author: Bruno Haible Signed-off-by: Avinal Kumar Reviewed-by: Adhemerval Zanella --- diff --git a/intl/finddomain.c b/intl/finddomain.c index 7da0cce62f..c9153b8d8e 100644 --- a/intl/finddomain.c +++ b/intl/finddomain.c @@ -50,7 +50,6 @@ /* List of already loaded domains. */ static struct loaded_l10nfile *_nl_loaded_domains; - /* Return a data structure describing the message catalog described by the DOMAINNAME and CATEGORY parameters with respect to the currently established bindings. */ @@ -133,55 +132,52 @@ _nl_find_domain (const char *dirname, char *locale, /* Now we determine the single parts of the locale name. First look for the language. Termination symbols are `_', '.', and `@'. */ - mask = _nl_explode_name (locale, &language, &modifier, &territory, - &codeset, &normalized_codeset); - if (mask == -1) - /* This means we are out of core. */ - return NULL; - - /* We need to protect modifying the _NL_LOADED_DOMAINS data. */ - gl_rwlock_wrlock (lock); - - /* Create all possible locale entries which might be interested in - generalization. */ - retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, - strlen (dirname) + 1, mask, language, territory, - codeset, normalized_codeset, modifier, - domainname, 1); + mask = _nl_explode_name (locale, &language, &modifier, &territory, &codeset, + &normalized_codeset); + if (mask != -1) /* Not out of memory? */ + { + /* We need to protect modifying the _NL_LOADED_DOMAINS data. */ + gl_rwlock_wrlock (lock); - gl_rwlock_unlock (lock); + /* Create all possible locale entries which might be interested in + generalization. */ + retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname, + strlen (dirname) + 1, mask, language, + territory, codeset, normalized_codeset, + modifier, domainname, 1); - if (retval == NULL) - /* This means we are out of core. */ - goto out; + gl_rwlock_unlock (lock); - if (retval->decided <= 0) - _nl_load_domain (retval, domainbinding); - if (retval->data == NULL) - { - int cnt; - for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) + if (retval != NULL) /* Not out of memory? */ { - if (retval->successor[cnt]->decided <= 0) - _nl_load_domain (retval->successor[cnt], domainbinding); - if (retval->successor[cnt]->data != NULL) - break; + if (retval->decided <= 0) + _nl_load_domain (retval, domainbinding); + if (retval->data == NULL) + { + int cnt; + for (cnt = 0; retval->successor[cnt] != NULL; ++cnt) + { + if (retval->successor[cnt]->decided <= 0) + _nl_load_domain (retval->successor[cnt], domainbinding); + if (retval->successor[cnt]->data != NULL) + break; + } + } } + + /* The space for normalized_codeset is dynamically allocated. + Free it. */ + if (mask & XPG_NORM_CODESET) + free ((void *) normalized_codeset); } /* The room for an alias was dynamically allocated. Free it now. */ if (alias_value != NULL) free (locale); -out: - /* The space for normalized_codeset is dynamically allocated. Free it. */ - if (mask & XPG_NORM_CODESET) - free ((void *) normalized_codeset); - return retval; } - #ifdef _LIBC /* This is called from iconv/gconv_db.c's free_mem, as locales must be freed before freeing gconv steps arrays. */