From 0f8fe5dd5382734d7668ab887873b2c3d7b2756f Mon Sep 17 00:00:00 2001 From: zhouyunding Date: Wed, 4 Nov 2026 20:01:17 +0800 Subject: [PATCH] json_object: fix double format use-after-free on strdup failure json_c_set_serialization_double_format() freed the current format string before strdup() of its replacement. In the GLOBAL branch the freed pointer was not reset on the strdup() failure path, leaving it dangling: a later serialization read through the dangling pointer, and a subsequent set(NULL) call freed it a second time. The THREAD branch reset its pointer to NULL right after the free, so it had no dangling pointer; its only defect was that a strdup() failure silently dropped the configured thread-local format and fell back to the global format. strdup() the new format first and replace the old one only once it succeeds, so a failure leaves both the global and thread-local format exactly as they were before the call. Fixes #997. --- json_object.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/json_object.c b/json_object.c index a36bf52..d65b1c8 100644 --- a/json_object.c +++ b/json_object.c @@ -1195,6 +1195,23 @@ int json_c_set_serialization_double_format(const char *double_format, int global { if (global_or_thread == JSON_C_OPTION_GLOBAL) { + if (double_format) + { + char *p = strdup(double_format); + if (p == NULL) + { + _json_c_set_last_err("json_c_set_serialization_double_format: " + "out of memory\n"); + return -1; + } + free(global_serialization_float_format); + global_serialization_float_format = p; + } + else + { + free(global_serialization_float_format); + global_serialization_float_format = NULL; + } #if defined(HAVE___THREAD) if (tls_serialization_float_format) { @@ -1202,32 +1219,10 @@ int json_c_set_serialization_double_format(const char *double_format, int global tls_serialization_float_format = NULL; } #endif - if (global_serialization_float_format) - free(global_serialization_float_format); - if (double_format) - { - char *p = strdup(double_format); - if (p == NULL) - { - _json_c_set_last_err("json_c_set_serialization_double_format: " - "out of memory\n"); - return -1; - } - global_serialization_float_format = p; - } - else - { - global_serialization_float_format = NULL; - } } else if (global_or_thread == JSON_C_OPTION_THREAD) { #if defined(HAVE___THREAD) - if (tls_serialization_float_format) - { - free(tls_serialization_float_format); - tls_serialization_float_format = NULL; - } if (double_format) { char *p = strdup(double_format); @@ -1237,10 +1232,12 @@ int json_c_set_serialization_double_format(const char *double_format, int global "out of memory\n"); return -1; } + free(tls_serialization_float_format); tls_serialization_float_format = p; } else { + free(tls_serialization_float_format); tls_serialization_float_format = NULL; } #else