From: Lennart Poettering Date: Mon, 19 Jan 2026 19:06:00 +0000 (+0100) Subject: sd-varlink: ensure that "any" actually means "any but null" X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=799392286ec0797c0a2a1260c444360b47ef36fc;p=thirdparty%2Fsystemd.git sd-varlink: ensure that "any" actually means "any but null" The new "any" type was implemented by accident that it actually meant "any but null" – unless marked as "any?" in which case it actually meant truly any, including null. The spec change in https://github.com/varlink/varlink.github.io/pull/43 otoh suggested that "any" really means anything, and "any?" apparently too. I think the implementation in code makes more sense than the spec change however, hence let's add some checks/tests to ensure the behaviour of the code is made explicitly and cared for. I will prep a spec change to make the spec follow the code on this too. Follow-up for: #39918 --- diff --git a/src/libsystemd/sd-varlink/sd-varlink-idl.c b/src/libsystemd/sd-varlink/sd-varlink-idl.c index eb4d737d2fa..a70cbe529ce 100644 --- a/src/libsystemd/sd-varlink/sd-varlink-idl.c +++ b/src/libsystemd/sd-varlink/sd-varlink-idl.c @@ -1704,6 +1704,8 @@ static int varlink_idl_validate_symbol(const sd_varlink_symbol *symbol, sd_json_ static int varlink_idl_validate_field_element_type(const sd_varlink_field *field, sd_json_variant *v) { assert(field); + assert(v); + assert(!sd_json_variant_is_null(v)); switch (field->field_type) { @@ -1764,7 +1766,8 @@ static int varlink_idl_validate_field_element_type(const sd_varlink_field *field break; case SD_VARLINK_ANY: - /* The any type accepts any JSON value, no validation needed */ + /* The any type accepts any non-null JSON value, no validation needed. (Note that null is + * already handled by the caller.) */ break; case _SD_VARLINK_FIELD_COMMENT: diff --git a/src/test/test-varlink-idl.c b/src/test/test-varlink-idl.c index f77fa7ee774..714189bbd12 100644 --- a/src/test/test-varlink-idl.c +++ b/src/test/test-varlink-idl.c @@ -537,4 +537,38 @@ TEST(enums_idl) { TEST_IDL_ENUM(ResolveSupport, resolve_support, vl_type_ResolveSupport); } +static SD_VARLINK_DEFINE_METHOD( + AnyTestStrict, + SD_VARLINK_DEFINE_INPUT(foo, SD_VARLINK_ANY, 0), + SD_VARLINK_DEFINE_INPUT(foo2, SD_VARLINK_ANY, 0), + SD_VARLINK_DEFINE_INPUT(foo3, SD_VARLINK_ANY, 0), + SD_VARLINK_DEFINE_INPUT(foo4, SD_VARLINK_ANY, 0)); + +static SD_VARLINK_DEFINE_METHOD( + AnyTestNullable, + SD_VARLINK_DEFINE_INPUT(foo, SD_VARLINK_ANY, SD_VARLINK_NULLABLE), + SD_VARLINK_DEFINE_INPUT(foo2, SD_VARLINK_ANY, SD_VARLINK_NULLABLE), + SD_VARLINK_DEFINE_INPUT(foo3, SD_VARLINK_ANY, SD_VARLINK_NULLABLE), + SD_VARLINK_DEFINE_INPUT(foo4, SD_VARLINK_ANY, SD_VARLINK_NULLABLE)); + +TEST(any) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + + ASSERT_OK(sd_json_buildo(&v, + SD_JSON_BUILD_PAIR_STRING("foo", "bar"), + SD_JSON_BUILD_PAIR_INTEGER("foo2", 47), + SD_JSON_BUILD_PAIR_NULL("foo3"), + SD_JSON_BUILD_PAIR_BOOLEAN("foo4", true))); + + /* "any" shall mean any type – but null */ + const char *bad_field = NULL; + ASSERT_ERROR(varlink_idl_validate_method_call(&vl_method_AnyTestStrict, v, /* flags= */ 0, &bad_field), ENOANO); + ASSERT_STREQ(bad_field, "foo3"); + + /* "any?" shall many truly any type */ + bad_field = NULL; + ASSERT_OK(varlink_idl_validate_method_call(&vl_method_AnyTestNullable, v, /* flags= */ 0, &bad_field)); + ASSERT_NULL(bad_field); +} + DEFINE_TEST_MAIN(LOG_DEBUG);