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.
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.