diff --git a/src/libsystemd/sd-bus/bus-dump-json.c b/src/libsystemd/sd-bus/bus-dump-json.c index 8238ac587e..ae3e806194 100644 --- a/src/libsystemd/sd-bus/bus-dump-json.c +++ b/src/libsystemd/sd-bus/bus-dump-json.c @@ -72,6 +72,7 @@ static int json_transform_dict_array(sd_bus_message *m, sd_json_variant **ret) { CLEANUP_ARRAY(elements, n_elements, sd_json_variant_unref_many); for (;;) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *key = NULL; const char *contents; char type; @@ -94,11 +95,35 @@ static int json_transform_dict_array(sd_bus_message *m, sd_json_variant **ret) { if (r < 0) return r; - r = json_transform_one(m, elements + n_elements); + r = json_transform_one(m, &key); if (r < 0) return r; - n_elements++; + /* JSON only supports string keys in objects, but D-Bus specification is a bit more lenient + * and allows dict entries to have any basic type as key. Let's stringify allowed non-string + * keys so that we can represent them as JSON objects. */ + if (!sd_json_variant_is_string(key)) { + _cleanup_free_ char *s = NULL; + + if (!IN_SET(sd_json_variant_type(key), + SD_JSON_VARIANT_BOOLEAN, + SD_JSON_VARIANT_INTEGER, + SD_JSON_VARIANT_REAL, + SD_JSON_VARIANT_UNSIGNED)) + return -EINVAL; + + r = sd_json_variant_format(key, /* flags= */ 0, &s); + if (r < 0) + return r; + + key = sd_json_variant_unref(key); + + r = sd_json_variant_new_string(&key, s); + if (r < 0) + return r; + } + + elements[n_elements++] = TAKE_PTR(key); r = json_transform_one(m, elements + n_elements); if (r < 0) diff --git a/test/units/TEST-74-AUX-UTILS.busctl.sh b/test/units/TEST-74-AUX-UTILS.busctl.sh index 875f353b00..54170cf5b5 100755 --- a/test/units/TEST-74-AUX-UTILS.busctl.sh +++ b/test/units/TEST-74-AUX-UTILS.busctl.sh @@ -43,6 +43,12 @@ busctl call --json=short \ busctl call -j \ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.DBus.Properties \ GetAll s "org.freedesktop.systemd1.Manager" | jq -c +# Do the same with D-Bus' org.freedesktop.DBus.Debug.Stats interface which also provides some +# complex signatures that caused issues during the JSON conversion in the past +# See: https://github.com/systemd/systemd/issues/32904 +busctl call --json=pretty \ + org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.Debug.Stats \ + GetStats | jq -c busctl call --verbose --timeout=60 --expect-reply=yes \ org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager \ ListUnitsByPatterns asas 1 "active" 2 "systemd-*.socket" "*.mount"