Merge pull request #976 from sswamy48/AIX_memleak

AIX:Fix memory leak in json_tokener_parse_ex due to duplocale
This commit is contained in:
Eric Hawicz authored and GitHub committed 2026-10-25 17:49:44 -04:00
commit cbc3d2c71d
1 file changed
+34 -27
+34 -27
View File
@@ -315,6 +315,15 @@ struct json_object *json_tokener_parse_verbose(const char *str, enum json_tokene
/* End optimization macro defs */
#ifdef HAVE_USELOCALE
/* One-time C-numeric locale, created on first call and reused forever.
* Avoids per-call duplocale() overhead and the memory leak seen on AIX
* where freelocale() does not release all locale category memory.
* Freed on library unload by json_tokener_locale_fini().
*/
static locale_t c_numeric_locale = (locale_t)0;
#endif /* HAVE_USELOCALE */
struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *str, int len)
{
struct json_object *obj = NULL;
@@ -324,7 +333,6 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
#ifdef HAVE_USELOCALE
locale_t oldlocale = uselocale(NULL);
locale_t newloc;
#elif defined(HAVE_SETLOCALE)
char *oldlocale = NULL;
#endif
@@ -346,33 +354,16 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
#ifdef HAVE_USELOCALE
{
#ifdef HAVE_DUPLOCALE
locale_t duploc = duplocale(oldlocale);
if (duploc == NULL && errno == ENOMEM)
if (c_numeric_locale == (locale_t)0)
{
tok->err = json_tokener_error_memory;
return NULL;
c_numeric_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
if (c_numeric_locale == (locale_t)0)
{
tok->err = json_tokener_error_memory;
return NULL;
}
}
newloc = newlocale(LC_NUMERIC_MASK, "C", duploc);
#else
newloc = newlocale(LC_NUMERIC_MASK, "C", oldlocale);
#endif
if (newloc == NULL)
{
tok->err = json_tokener_error_memory;
#ifdef HAVE_DUPLOCALE
freelocale(duploc);
#endif
return NULL;
}
#ifdef NEWLOCALE_NEEDS_FREELOCALE
#ifdef HAVE_DUPLOCALE
// Older versions of FreeBSD (<12.4) don't free the locale
// passed to newlocale(), so do it here
freelocale(duploc);
#endif
#endif
uselocale(newloc);
uselocale(c_numeric_locale);
}
#elif defined(HAVE_SETLOCALE)
{
@@ -1410,7 +1401,6 @@ out:
#ifdef HAVE_USELOCALE
uselocale(oldlocale);
freelocale(newloc);
#elif defined(HAVE_SETLOCALE)
setlocale(LC_NUMERIC, oldlocale);
free(oldlocale);
@@ -1477,3 +1467,20 @@ static int json_tokener_parse_double(const char *buf, int len, double *retval)
return 0; // It worked
return 1;
}
#ifdef HAVE_USELOCALE
/* Release the static C-numeric locale when the library is unloaded.
* This keeps Valgrind clean.
*/
#if defined(__GNUC__) || defined(__clang__)
__attribute__((destructor))
static void json_tokener_locale_fini(void)
{
if (c_numeric_locale != (locale_t)0)
{
freelocale(c_numeric_locale);
c_numeric_locale = (locale_t)0;
}
}
#endif /* __GNUC__ || __clang__ */
#endif /* HAVE_USELOCALE */