Commit Graph
2 Commits
Author SHA1 Message Date
Sangamesh Mallayya fd92d58f2d Fix memory leak in json_tokener_parse_ex due to duplocale
json-c uses duplocale+newlocale+uselocale() to temporarily switch LC_NUMERIC
to "C" during JSON number parsing.

On AIX, every call to json_tokener_parse_ex permanently leaks memory.
This was confirmed with dbx malloc allocation.

0x20008af8           24    0     YORKTOWN
0x20008e18         5128    0     YORKTOWN
0x2000a458          776    0     YORKTOWN
0x2000a768          776    0     YORKTOWN
0x2000aa78          776    0     YORKTOWN
0x2000ad88          776    0     YORKTOWN
0x2000b098          776    0     YORKTOWN
0x2000b6b8          776    0     YORKTOWN

dbx malloc allocation showing new allocations surviving after each parse call with ~776
bytes left after invocations.

The root cause is that on AIX, locale category objects allocated by duplocale() are not
released back to the process heap, even when freelocale() is called correctly.
This causes unbounded heap growth in any long-running process that parses JSON repeatedly.

The fix it to replace the per-call duplocale+newlocale+reelocale() with a single
file-scope static locale_t created once on first call using
newlocale(LC_NUMERIC_MASK, "C", (locale_t)0) and reused for the lifetime of the library.
This reduces newlocale calls on all platforms.

__attribute__((destructor)) function json_tokener_locale_fini() frees the static locale
when the library is unloaded via dlclose() or process exit.
2026-10-08 01:37:47 -05:00
Sangamesh Mallayya 52f57ec18a AIX: Fix test_json_patch NULL pointer passed to printf
Some test_json_patch test cases have neither a comment field and
nor a error field, so the expression
"comment ? comment : error_s"  evaluates to NULL.

The printf statement

printf("Testing '%s', ...", comment ? comment : error_s, ...);

passes NULL as a %s argument. GNU libc handles this gracefully and prints (null).
On AIX, passing NULL for %s prints an empty string, causing the test output
to differ from the expected file.

The fix adds a simple macro:

define STR_OR_NULL(s) ((s) ? (s) : "(null)")

that retruns "(null)" when s is NULL.
2026-09-21 01:03:16 -05:00