Bug 22156

Summary: dbus-glib returns UnknownMethod on GetAll if no properties
Product: dbus Reporter: Olivier Crête <olivier.crete>
Component: GLibAssignee: Simon McVittie <smcv>
Status: RESOLVED MOVED QA Contact: D-Bus Maintainers <dbus>
Severity: normal    
Priority: medium CC: rob.taylor, walters
Version: unspecifiedKeywords: patch
Hardware: Other   
OS: All   
URL: http://cgit.freedesktop.org/~smcv/dbus-glib/log/?h=getall-empty-22156
Whiteboard:
i915 platform: i915 features:
Attachments: [PATCH 1/2] dbus-gobject: return empty from GetAll if there are no known properties
[PATCH 2/2] Add a regression test for GetAll on objects with no properties

Description Olivier Crête 2009-06-08 08:41:39 UTC
In 0.80, there was a change in the handling of properties in dbus-glib. It claims to support the Properties interface, but when one tries to call GetAll() it returns "UnknownMethod" if there are no properties defined for this object. Older versions of dbus-glib properly returned an empty array.

It should either not declare that interface or implement it properly.
Comment 1 Colin Walters 2009-07-15 12:15:25 UTC
This commit:

commit 94d68f00d9d244de3b1d66d3cf78bb5171552311
Author: Tambet Ingo <tambet@gmail.com>
Date:   Thu Dec 18 12:09:43 2008 +0200

    Use the provided interface for org.freedesktop.DBus.Properties.GetAll call.

Did change the behavior - before we just returned all object properties, regardless, which was generally wrong.  My guess what's happening here is some other code was requesting an interface your object didn't actually claim to implement, but dbus-glib just returned the properties anyways.

Does this seem to be the case?
Comment 2 Olivier Crête 2009-07-15 12:30:41 UTC
The object implements the interface, but the interface has no properties. In that case, it should really return an empty array, not an error.
Comment 3 Colin Walters 2009-07-16 07:59:46 UTC
As far as I can tell from the code this should work; we do:

  if (getall)
    {
      object_info = lookup_object_info_by_iface (object, wincaps_propiface);
      if (object_info != NULL)
          ret = get_all_object_properties (connection, message, object_info, object);
      else
          return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
    ...

And get_all_object_properties always returns an array.  However we would do  DBUS_HANDLER_RESULT_NOT_YET_HANDLED if we can't find the interface on the object.

Is your code free software or somewhere where I can look at it?
Comment 4 Olivier Crête 2009-07-16 08:47:16 UTC
The service is in telepathy-sofiasip:
http://git.collabora.co.uk/?p=telepathy-sofiasip.git;a=blob;f=src/sip-media-stream.c
And it has no dbus properties, but it does implement the org.freedesktop.Telepathy.Media.StreamHandler interface (which now does).

And the client is libtelepathy-farsight
http://git.collabora.co.uk/?p=telepathy-farsight.git;a=blob;f=telepathy-farsight/stream.c#l578

The thing is that the interface is implemented, but it has no exported properties I believe..
Comment 5 Simon McVittie 2011-04-20 05:18:44 UTC
lookup_object_info_by_iface is mis-named (it specifically looks for properties, not for methods or signals). It returns NULL if there are no properties.

It turns out that (at least in v1 introspection) if there are no properties, no methods and no signals, then we have no record that an interface exists at all, so we can't possibly distinguish between these cases.

However, arguably GetAll("any.valid.interface.name") should return an empty array without error - the empty set of properties implemented by that interface. (Get() should still raise an error if it doesn't know the property.)

For what it's worth, telepathy-glib's TpDBusPropertiesMixin never raises an error, even if the interface name is syntatically invalid - it'll just not find any matching properties.
Comment 6 Simon McVittie 2011-04-20 07:06:35 UTC
Created attachment 45861 [details] [review]
[PATCH 1/2] dbus-gobject: return empty from GetAll if there are no  known properties
Comment 7 Simon McVittie 2011-04-20 07:06:50 UTC
Created attachment 45862 [details] [review]
[PATCH 2/2] Add a regression test for GetAll on objects with no  properties
Comment 8 Dan Williams 2012-10-23 00:32:27 UTC
I guess I'd prefer to modify the GetAll checks to still return some kind of error if the interface is not implemented at all, versus if it's implemented but has no properties (in which case, return empty set).

Isn't this as easy as removing the info->exported_properties check from lookup_object_info_by_iface_cb()?  All the code that calls lookup_object_info_by_iface() is smart enough to handle exported_properties being NULL.  A quick audit didn't turn up any cases where we'd be bypassing property access controls, but somebody would need to do a longer one than the 10 minutes I spent on it.  But I think that might get us where we need to be?

Thus lookup_object_info_by_iface() would always return the object info if the object implemented that interface, even if the interface had no properties.  The three places that call it are:

1) lookup_property_name(): if the interface has no properties, then there won't be any shadow properties, which will return the non-shadow property name, exactly the same as if object_info was NULL

2) check_property_access(): the checks for property_info_from_object_info() will fail because exported_properties is NULL and thus the while() loop in property_info_from_object_info() will simply not execute, and it'll return FALSE, leading to DBUS_ERROR_ACCESS_DENIED at the end of check_property_access().

3) object_registration_message() for GetAll: calls get_all_object_properties() which will open the returned properties container, never execute the while() loop due to exported_properties being NULL, close the container, and return.

That approach, which basically is:

--- a/dbus/dbus-gobject.c
+++ b/dbus/dbus-gobject.c
@@ -599,7 +599,7 @@ lookup_object_info_by_iface_cb (const DBusGObjectInfo *info,
       lookup_data->info = info;
       lookup_data->iface_type = gtype;
     }
-  else if (info->exported_properties && !strcmp (info->exported_properties, lookup_data->iface))
+  else if (!strcmp (info->exported_properties, lookup_data->iface))
     {
       lookup_data->info = info;
       lookup_data->iface_type = gtype;

passes your 2/2 testcase here too.  Though we'd want another testcase to ensure we get an error if the interface actually doesn't exist.
Comment 9 Dan Williams 2012-10-23 00:32:57 UTC
Comment on attachment 45862 [details] [review]
[PATCH 2/2] Add a regression test for GetAll on objects with no  properties

Review of attachment 45862 [details] [review]:
-----------------------------------------------------------------

You need this hunk too:

--- a/test/core/Makefile.am
+++ b/test/core/Makefile.am
@@ -123,7 +123,7 @@ test_variant_recursion_SOURCES=test-variant-recursion.c
 
 test_variant_recursion_LDADD= $(tool_ldadd)
 
-BUILT_SOURCES = test-service-glib-glue.h test-service-glib-subclass-glue.h test-service-glib-bindings.h my-object-marshal.c my-object-marshal.h 
+BUILT_SOURCES = test-service-glib-glue.h test-service-glib-subclass-glue.h test-service-glib-bindings.h my-object-marshal.c my-object-marshal.h boring-ifa
 
 test_service_glib_SOURCES=                             \
        my-object.c                             \
Comment 10 Dan Williams 2012-10-23 00:34:15 UTC
(In reply to comment #9)
> Comment on attachment 45862 [details] [review] [review]
> [PATCH 2/2] Add a regression test for GetAll on objects with no  properties
> 
> Review of attachment 45862 [details] [review] [review]:
> -----------------------------------------------------------------
> 
> You need this hunk too:
> 
> --- a/test/core/Makefile.am
> +++ b/test/core/Makefile.am
> @@ -123,7 +123,7 @@ test_variant_recursion_SOURCES=test-variant-recursion.c
>  
>  test_variant_recursion_LDADD= $(tool_ldadd)
>  
> -BUILT_SOURCES = test-service-glib-glue.h test-service-glib-subclass-glue.h
> test-service-glib-bindings.h my-object-marshal.c my-object-marshal.h 
> +BUILT_SOURCES = test-service-glib-glue.h test-service-glib-subclass-glue.h
> test-service-glib-bindings.h my-object-marshal.c my-object-marshal.h
> boring-ifa
>  
>  test_service_glib_SOURCES=                             \
>         my-object.c                             \

Ugh, my cut/paste from the terminal failed because it's not wrapping long lines.  Basically, make sure you add boring-iface-glue.h to BUILT_SOURCES.
Comment 11 Dan Williams 2012-10-23 00:50:40 UTC
Comment on attachment 45862 [details] [review]
[PATCH 2/2] Add a regression test for GetAll on objects with no  properties

Review of attachment 45862 [details] [review]:
-----------------------------------------------------------------

Grr, also dont' forget to add the test to test/core/run-test.sh otherwise it won't get run for 'make check'.  Now that the test is actually run, my proposed change does *not* pass this test, because of the changed semantics for the case where an interface has no properties, methods, or signals (and thus no object info).
Comment 12 Dan Williams 2012-10-23 00:53:04 UTC
IMHO if the interface is implemented but has no properties, methods, or signals, then we should still return an error.  What would the point of that interface be?  Really, we just want to catch the case where the interface has no properties, but *does* have signals or methods, which is much much more useful.

No properties, Has signals | Has methods = return empty set

No properties, No signals, No methods = return error
Comment 13 GitLab Migration User 2018-08-22 22:03:18 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/dbus/dbus-glib/issues/8.

Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.