diff options
| author | Hauke Mehrtens | 2026-04-16 20:16:42 +0000 |
|---|---|---|
| committer | Hauke Mehrtens | 2026-06-18 22:06:53 +0000 |
| commit | 3bbf83c3a3eb0ec79c5dffe5b9106e46e3180af1 (patch) | |
| tree | 5b91be017c0a7faefd686ef2d153aafe7a63308c | |
| parent | 52868080dc8852b71077d24178957006d125b9f5 (diff) | |
| download | libubox-3bbf83c3a3eb0ec79c5dffe5b9106e46e3180af1.tar.gz | |
blobmsg_json: fix double format string to avoid truncation and data loss
Using %lf (= %f) with the default precision of 6 fractional decimal
digits requires up to 317 characters for negative values close to
-DBL_MAX (1 sign + 309 integer digits + 1 decimal point + 6 fraction
digits + NUL), but buf[] only holds 317 bytes, leaving no room for the
NUL terminator — snprintf truncates the last digit silently.
Additionally, 6 fractional digits do not give round-trip accuracy for
IEEE 754 doubles; 17 significant digits (%.17g) are required.
Switch to %.17g which uses scientific notation for very large or small
values, keeping the output well within the buffer, and guarantees
round-trip accuracy for all finite doubles.
Update the cram fixtures test_blobmsg.t and test_blobmsg_types.t to
match the new output. The previous fixtures encoded the buggy
behaviour: DBL_MIN serialised as "0.000000" and was silently flattened
to zero on the JSON round-trip, while DBL_MAX produced a 309-digit
decimal string.
Link: https://github.com/openwrt/libubox/pull/42
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
(cherry picked from commit 23c6618a5b9088644bb6b509c83f4f88ee8998d3)
| -rw-r--r-- | blobmsg_json.c | 2 | ||||
| -rw-r--r-- | tests/cram/test_blobmsg.t | 8 | ||||
| -rw-r--r-- | tests/cram/test_blobmsg_types.t | 8 |
3 files changed, 9 insertions, 9 deletions
diff --git a/blobmsg_json.c b/blobmsg_json.c index 49eea61..04bb9a1 100644 --- a/blobmsg_json.c +++ b/blobmsg_json.c @@ -272,7 +272,7 @@ static void blobmsg_format_element(struct strbuf *s, struct blob_attr *attr, boo snprintf(buf, sizeof(buf), "%" PRId64, (int64_t) be64_to_cpu(*(uint64_t *)data)); break; case BLOBMSG_TYPE_DOUBLE: - snprintf(buf, sizeof(buf), "%lf", blobmsg_get_double(attr)); + snprintf(buf, sizeof(buf), "%.17g", blobmsg_get_double(attr)); break; case BLOBMSG_TYPE_STRING: blobmsg_format_string(s, data); diff --git a/tests/cram/test_blobmsg.t b/tests/cram/test_blobmsg.t index 0c192c5..67a9d80 100644 --- a/tests/cram/test_blobmsg.t +++ b/tests/cram/test_blobmsg.t @@ -35,7 +35,7 @@ check that blobmsg is producing expected results: \tworld : 2 (str) (esc) } - [*] blobmsg to json: {"message":"Hello, world!","testdata":{"dbl-min":0.000000,"dbl-max":179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000,"foo":false,"poo":true,"moo-min":true,"moo-max":true,"bar-min":-32768,"bar-max":32767,"baz-min":-2147483648,"baz-max":2147483647,"taz-min":-9223372036854775808,"taz-max":9223372036854775807,"world":"2"},"list":[false,true,true,true,-32768,32767,-2147483648,2147483647,-9223372036854775808,9223372036854775807,0.000000,179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000]} + [*] blobmsg to json: {"message":"Hello, world!","testdata":{"dbl-min":2.2250738585072014e-308,"dbl-max":1.7976931348623157e+308,"foo":false,"poo":true,"moo-min":true,"moo-max":true,"bar-min":-32768,"bar-max":32767,"baz-min":-2147483648,"baz-max":2147483647,"taz-min":-9223372036854775808,"taz-max":9223372036854775807,"world":"2"},"list":[false,true,true,true,-32768,32767,-2147483648,2147483647,-9223372036854775808,9223372036854775807,2.2250738585072014e-308,1.7976931348623157e+308]} [*] blobmsg from json: Message: Hello, world! @@ -102,7 +102,7 @@ check that blobmsg is producing expected results: \tworld : 2 (str) (esc) } - [*] blobmsg to json: {"message":"Hello, world!","testdata":{"dbl-min":0.000000,"dbl-max":179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000,"foo":false,"poo":true,"moo-min":true,"moo-max":true,"bar-min":-32768,"bar-max":32767,"baz-min":-2147483648,"baz-max":2147483647,"taz-min":-9223372036854775808,"taz-max":9223372036854775807,"world":"2"},"list":[false,true,true,true,-32768,32767,-2147483648,2147483647,-9223372036854775808,9223372036854775807,0.000000,179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000]} + [*] blobmsg to json: {"message":"Hello, world!","testdata":{"dbl-min":2.2250738585072014e-308,"dbl-max":1.7976931348623157e+308,"foo":false,"poo":true,"moo-min":true,"moo-max":true,"bar-min":-32768,"bar-max":32767,"baz-min":-2147483648,"baz-max":2147483647,"taz-min":-9223372036854775808,"taz-max":9223372036854775807,"world":"2"},"list":[false,true,true,true,-32768,32767,-2147483648,2147483647,-9223372036854775808,9223372036854775807,2.2250738585072014e-308,1.7976931348623157e+308]} [*] blobmsg from json: Message: Hello, world! @@ -169,7 +169,7 @@ check that blobmsg is producing expected results: \tworld : 2 (str) (esc) } - [*] blobmsg to json: {"message":"Hello, world!","testdata":{"dbl-min":0.000000,"dbl-max":179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000,"foo":false,"poo":true,"moo-min":true,"moo-max":true,"bar-min":-32768,"bar-max":32767,"baz-min":-2147483648,"baz-max":2147483647,"taz-min":-9223372036854775808,"taz-max":9223372036854775807,"world":"2"},"list":[false,true,true,true,-32768,32767,-2147483648,2147483647,-9223372036854775808,9223372036854775807,0.000000,179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000]} + [*] blobmsg to json: {"message":"Hello, world!","testdata":{"dbl-min":2.2250738585072014e-308,"dbl-max":1.7976931348623157e+308,"foo":false,"poo":true,"moo-min":true,"moo-max":true,"bar-min":-32768,"bar-max":32767,"baz-min":-2147483648,"baz-max":2147483647,"taz-min":-9223372036854775808,"taz-max":9223372036854775807,"world":"2"},"list":[false,true,true,true,-32768,32767,-2147483648,2147483647,-9223372036854775808,9223372036854775807,2.2250738585072014e-308,1.7976931348623157e+308]} [*] blobmsg from json: Message: Hello, world! @@ -236,7 +236,7 @@ check that blobmsg is producing expected results: \tworld : 2 (str) (esc) } - [*] blobmsg to json: {"message":"Hello, world!","testdata":{"dbl-min":0.000000,"dbl-max":179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000,"foo":false,"poo":true,"moo-min":true,"moo-max":true,"bar-min":-32768,"bar-max":32767,"baz-min":-2147483648,"baz-max":2147483647,"taz-min":-9223372036854775808,"taz-max":9223372036854775807,"world":"2"},"list":[false,true,true,true,-32768,32767,-2147483648,2147483647,-9223372036854775808,9223372036854775807,0.000000,179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000]} + [*] blobmsg to json: {"message":"Hello, world!","testdata":{"dbl-min":2.2250738585072014e-308,"dbl-max":1.7976931348623157e+308,"foo":false,"poo":true,"moo-min":true,"moo-max":true,"bar-min":-32768,"bar-max":32767,"baz-min":-2147483648,"baz-max":2147483647,"taz-min":-9223372036854775808,"taz-max":9223372036854775807,"world":"2"},"list":[false,true,true,true,-32768,32767,-2147483648,2147483647,-9223372036854775808,9223372036854775807,2.2250738585072014e-308,1.7976931348623157e+308]} [*] blobmsg from json: Message: Hello, world! diff --git a/tests/cram/test_blobmsg_types.t b/tests/cram/test_blobmsg_types.t index 190e1f2..4def0e6 100644 --- a/tests/cram/test_blobmsg_types.t +++ b/tests/cram/test_blobmsg_types.t @@ -40,7 +40,7 @@ check that blobmsg is producing expected results: double_max: 1.797693e+308 double_min: 2.225074e-308 - [*] blobmsg to json: {"string":"Hello, world!","int64_max":9223372036854775807,"int64_min":-9223372036854775808,"int32_max":2147483647,"int32_min":-2147483648,"int16_max":32767,"int16_min":-32768,"int8_max":true,"int8_min":true,"double_max":179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000,"double_min":0.000000} + [*] blobmsg to json: {"string":"Hello, world!","int64_max":9223372036854775807,"int64_min":-9223372036854775808,"int32_max":2147483647,"int32_min":-2147483648,"int16_max":32767,"int16_min":-32768,"int8_max":true,"int8_min":true,"double_max":1.7976931348623157e+308,"double_min":2.2250738585072014e-308} [*] blobmsg from json: string: Hello, world! @@ -53,7 +53,7 @@ check that blobmsg is producing expected results: int8_max: 1 int8_min: 1 double_max: 1.797693e+308 - double_min: 0.000000e+00 + double_min: 2.225074e-308 [*] blobmsg from json/cast_u64: string: Hello, world! @@ -66,7 +66,7 @@ check that blobmsg is producing expected results: int8_max: 1 int8_min: 1 double_max: 1.797693e+308 - double_min: 0.000000e+00 + double_min: 2.225074e-308 [*] blobmsg from json/cast_s64: string: Hello, world! @@ -79,4 +79,4 @@ check that blobmsg is producing expected results: int8_max: 1 int8_min: 1 double_max: 1.797693e+308 - double_min: 0.000000e+00 + double_min: 2.225074e-308 |