]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-varlink: ensure that "any" actually means "any but null"
authorLennart Poettering <lennart@poettering.net>
Mon, 19 Jan 2026 19:06:00 +0000 (20:06 +0100)
committerMike Yuan <me@yhndnzj.com>
Mon, 19 Jan 2026 20:29:38 +0000 (21:29 +0100)
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

src/libsystemd/sd-varlink/sd-varlink-idl.c
src/test/test-varlink-idl.c

index eb4d737d2faf1124e12072ac29a2f77c20af2f69..a70cbe529ce29a8ce511025e46712a6f7c6c7bb0 100644 (file)
@@ -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:
index f77fa7ee774ce53afb5c874a9a6d868520d70ed9..714189bbd12e77bcc1ea218a116692081dbc6702 100644 (file)
@@ -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);