mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 08:25:20 +09:00
sd-json: make sure all dispatch helpers do something sensible in case of "null" JSON value
Most of our dispatch helpers already do something useful in case they
are invoked on a null JSON value: they translate this to the appropriate
niche value for the type, if there is one.
Add the same for *all* dispatchers we have, to make this fully
systematic.
For various types it's not always clear which niche value to pick. I
opted for UINT{8,16,32,64}_MAX for the various unsigned integers, which
maps our own use in most cases. I opted for -1 for the various signed
integer types. For arrays/blobs of stuff I opted for the empty
array/blob, and for booleans I opted for false.
Of course, in various cases this is not going to be the right niche
value, but that's entirely fine, after all before a json value reaches a
dispatcher function it must pass one of two type checks first:
1. Either the .type field of sd_json_dispatch_field must be
_SD_JSON_VARIANT_TYPE_INVALID to not do a type check at all
2. Or the .type field is set, but then the SD_JSON_NULLABLE flag must be
set in .flags.
This means, accidentally generating the niche values on null is not
really likely.
This commit is contained in:
@@ -31,6 +31,11 @@ int json_dispatch_unhex_iovec(const char *name, sd_json_variant *variant, sd_jso
|
||||
size_t sz;
|
||||
int r;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
iovec_done(iov);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_string(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
|
||||
|
||||
@@ -49,6 +54,11 @@ int json_dispatch_unbase64_iovec(const char *name, sd_json_variant *variant, sd_
|
||||
size_t sz;
|
||||
int r;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
iovec_done(iov);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_string(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
|
||||
|
||||
@@ -68,6 +78,11 @@ int json_dispatch_byte_array_iovec(const char *name, sd_json_variant *variant, s
|
||||
|
||||
assert(variant);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
iovec_done(iov);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_array(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
|
||||
|
||||
@@ -169,6 +184,11 @@ int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_di
|
||||
_cleanup_(iovec_done) struct iovec iov = {};
|
||||
int r;
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*address = (struct in_addr) {};
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = json_dispatch_byte_array_iovec(name, variant, flags, &iov);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -5292,6 +5292,11 @@ _public_ int sd_json_dispatch_stdbool(const char *name, sd_json_variant *variant
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*b = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_boolean(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name));
|
||||
|
||||
@@ -5305,6 +5310,11 @@ _public_ int sd_json_dispatch_intbool(const char *name, sd_json_variant *variant
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*b = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!sd_json_variant_is_boolean(variant))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name));
|
||||
|
||||
@@ -5336,6 +5346,11 @@ _public_ int sd_json_dispatch_int64(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*i = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Also accept numbers formatted as string, to increase compatibility with less capable JSON
|
||||
* implementations that cannot do 64bit integers. */
|
||||
if (sd_json_variant_is_string(variant) && safe_atoi64(sd_json_variant_string(variant), i) >= 0)
|
||||
@@ -5354,6 +5369,11 @@ _public_ int sd_json_dispatch_uint64(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*u = UINT64_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Since 64bit values (in particular unsigned ones) in JSON are problematic, let's also accept them
|
||||
* formatted as strings. If this is not desired make sure to set the .type field in
|
||||
* sd_json_dispatch_field to SD_JSON_UNSIGNED rather than _SD_JSON_VARIANT_TYPE_INVALID, so that
|
||||
@@ -5377,6 +5397,11 @@ _public_ int sd_json_dispatch_uint32(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*u = UINT32_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_uint64(name, variant, flags, &u64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -5399,6 +5424,11 @@ _public_ int sd_json_dispatch_int32(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*i = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_int64(name, variant, flags, &i64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -5421,6 +5451,11 @@ _public_ int sd_json_dispatch_int16(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*i = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_int64(name, variant, flags, &i64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -5440,6 +5475,11 @@ _public_ int sd_json_dispatch_uint16(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*u = UINT16_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_uint64(name, variant, flags, &u64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -5459,6 +5499,11 @@ _public_ int sd_json_dispatch_int8(const char *name, sd_json_variant *variant, s
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*i = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_int64(name, variant, flags, &i64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -5478,6 +5523,11 @@ _public_ int sd_json_dispatch_uint8(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*u = UINT8_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_uint64(name, variant, flags, &u64);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -5495,6 +5545,11 @@ _public_ int sd_json_dispatch_double(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*d = NAN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note, this will take care of parsing NaN, -Infinity, Infinity for us */
|
||||
if (sd_json_variant_is_string(variant) && safe_atod(sd_json_variant_string(variant), d) >= 0)
|
||||
return 0;
|
||||
@@ -5514,6 +5569,11 @@ _public_ int sd_json_dispatch_string(const char *name, sd_json_variant *variant,
|
||||
assert_return(variant, -EINVAL);
|
||||
assert_return(userdata, -EINVAL);
|
||||
|
||||
if (sd_json_variant_is_null(variant)) {
|
||||
*s = mfree(*s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_json_dispatch_const_string(name, variant, flags, &n);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
Reference in New Issue
Block a user