[PATCH] locale: memory leak in newlocale (BZ #25770)
Dmitry Kovalenko
d.kovalenko@postgrespro.ru
Sat May 17 11:40:13 GMT 2025
It is a fix for memory leak in the function 'newlocale' (the real name
is __newlocale).
There is not released a memory for the local buffer 'locale_path'.
https://sourceware.org/bugzilla/show_bug.cgi?id=25770
I made the minimal changes to avoid the unnecessary
reformating/refactoring of source code.
Potentail problems:
- in 'label__cleanup_and_return_null' free(...) may change the current
errno.
- in 'label__free_cnt_data_and_exit' _nl_remove_locale and
__libc_rwlock_unlock may reset the current errno.
All these problems were not added and exist in the current code.
---
Patch was tested on Ubuntu 24.04.
My 'LOCPATH' environment variable is "/snap/code/193/usr/lib/locale".
With an original (system) libc I have the following problem:
#0 0x7d5c3aafc778 in realloc
../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:85
#1 0x7d5c394b05f2 in __argz_add_sep string/argz-addsep.c:34
#2 0x7d5c39439bdb in __newlocale locale/newlocale.c:111
#3 0x7d5c370e58fc (/lib/x86_64-linux-gnu/libp11-kit.so.0+0x1098fc)
(BuildId: 1cbcd6ac7e0ff0259eb3acc14d556d2c1ec00cdc)
#4 0x7d5c3b14571e in call_init elf/dl-init.c:74
#5 0x7d5c3b145823 in call_init elf/dl-init.c:120
#6 0x7d5c3b145823 in _dl_init elf/dl-init.c:121
#7 0x7d5c3b15f59f (/lib64/ld-linux-x86-64.so.2+0x1f59f) (BuildId:
1c8db5f83bba514f8fd5f1fb6d7be975be1bb855)
SUMMARY: AddressSanitizer: 46 byte(s) leaked in 1 allocation(s).
When I run with my corrected libc, through runtest.sh <my-application>,
all is OK.
Signed-off-by: Dmitry Kovalenko <d.kovalenko@postgrespro.ru>
-------------- next part --------------
From 70236429947b5685df66bddafdff2738daa7e960 Mon Sep 17 00:00:00 2001
From: "d.kovalenko" <d.kovalenko@postgrespro.ru>
Date: Sat, 17 May 2025 13:33:16 +0300
Subject: [PATCH] locale: memory leak in newlocale (BZ #25770)
To: libc-alpha@sourceware.org
It is a fix for memory leak in the function 'newlocale' (the real name is __newlocale).
There is not released a memory for the local buffer 'locale_path'.
https://sourceware.org/bugzilla/show_bug.cgi?id=25770
I made the minimal changes to avoid the unnecessary reformating/refactoring of source code.
Potentail problems:
- in 'label__cleanup_and_return_null' free(...) may change the current errno.
- in 'label__free_cnt_data_and_exit' _nl_remove_locale and __libc_rwlock_unlock may reset the current errno.
All these problems were not added and exist in the current code.
---
Patch was tested on Ubuntu 24.04.
My 'LOCPATH' environment variable is "/snap/code/193/usr/lib/locale".
With an original (system) libc I have the following problem:
#0 0x7d5c3aafc778 in realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:85
#1 0x7d5c394b05f2 in __argz_add_sep string/argz-addsep.c:34
#2 0x7d5c39439bdb in __newlocale locale/newlocale.c:111
#3 0x7d5c370e58fc (/lib/x86_64-linux-gnu/libp11-kit.so.0+0x1098fc) (BuildId: 1cbcd6ac7e0ff0259eb3acc14d556d2c1ec00cdc)
#4 0x7d5c3b14571e in call_init elf/dl-init.c:74
#5 0x7d5c3b145823 in call_init elf/dl-init.c:120
#6 0x7d5c3b145823 in _dl_init elf/dl-init.c:121
#7 0x7d5c3b15f59f (/lib64/ld-linux-x86-64.so.2+0x1f59f) (BuildId: 1c8db5f83bba514f8fd5f1fb6d7be975be1bb855)
SUMMARY: AddressSanitizer: 46 byte(s) leaked in 1 allocation(s).
When I run with my corrected libc, through runtest.sh <my-application>, all is OK.
Signed-off-by: Dmitry Kovalenko <d.kovalenko@postgrespro.ru>
---
locale/newlocale.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
diff --git a/locale/newlocale.c b/locale/newlocale.c
index d25a6038d3..a6990c70e9 100644
--- a/locale/newlocale.c
+++ b/locale/newlocale.c
@@ -45,8 +45,6 @@ __newlocale (int category_mask, const char *locale, locale_t base)
const char *newnames[__LC_LAST];
struct __locale_struct result;
locale_t result_ptr;
- char *locale_path;
- size_t locale_path_len;
const char *locpath_var;
int cnt;
size_t names_len;
@@ -90,16 +88,18 @@ __newlocale (int category_mask, const char *locale, locale_t base)
return NULL;
*result_ptr = result;
- goto update;
+ goto label__update;
}
+ {
/* We perhaps really have to load some data. So we determine the
path in which to look for the data now. The environment variable
`LOCPATH' must only be used when the binary has no SUID or SGID
bit set. If using the default path, we tell _nl_find_locale
by passing null and it can check the canonical locale archive. */
- locale_path = NULL;
- locale_path_len = 0;
+
+ char *locale_path = NULL;
+ size_t locale_path_len = 0;
locpath_var = getenv ("LOCPATH");
if (locpath_var != NULL && locpath_var[0] != '\0')
@@ -135,7 +135,7 @@ __newlocale (int category_mask, const char *locale, locale_t base)
if (cnt == __LC_LAST)
/* Bogus category name. */
- ERROR_RETURN;
+ goto label__cleanup_and_error_return;
/* Found the category this clause sets. */
specified_mask |= 1 << cnt;
@@ -154,7 +154,7 @@ __newlocale (int category_mask, const char *locale, locale_t base)
if (category_mask &~ specified_mask)
/* The composite name did not specify all categories we need. */
- ERROR_RETURN;
+ goto label__cleanup_and_error_return;
}
/* Protect global data. */
@@ -171,7 +171,7 @@ __newlocale (int category_mask, const char *locale, locale_t base)
cnt, &newnames[cnt]);
if (result.__locales[cnt] == NULL)
{
- free_cnt_data_and_exit:
+ label__free_cnt_data_and_exit:
while (cnt-- > 0)
if (((category_mask & 1 << cnt) != 0)
&& result.__locales[cnt]->usage_count != UNDELETABLE)
@@ -180,7 +180,7 @@ __newlocale (int category_mask, const char *locale, locale_t base)
/* Critical section left. */
__libc_rwlock_unlock (__libc_setlocale_lock);
- return NULL;
+ goto label__cleanup_and_return_null;
}
if (newnames[cnt] != _nl_C_name)
@@ -200,7 +200,7 @@ __newlocale (int category_mask, const char *locale, locale_t base)
if (result_ptr == NULL)
{
cnt = __LC_LAST;
- goto free_cnt_data_and_exit;
+ goto label__free_cnt_data_and_exit;
}
if (base == NULL)
@@ -258,11 +258,23 @@ __newlocale (int category_mask, const char *locale, locale_t base)
free (base);
}
+ free(locale_path);
+
/* Critical section left. */
__libc_rwlock_unlock (__libc_setlocale_lock);
+ goto label__update;
+
+ label__cleanup_and_error_return:
+ free(locale_path);
+ ERROR_RETURN;
+
+ label__cleanup_and_return_null:
+ free(locale_path);
+ return NULL;
+ }
/* Update the special members. */
- update:
+ label__update:
{
union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
result_ptr->__ctype_b = (const unsigned short int *)
--
2.46.0.dirty
More information about the Libc-alpha
mailing list