dbus_message_set/get_data usage

Brosseau, Vincent vincent.brosseau at bruker.fr
Thu Dec 12 05:18:32 PST 2013

I don't use high-level DBus library, because I use DBus in an embedded linux system (on ARM9).
I tried to compile such libraries (like GDBus), but they require other libraries, which require other libraries, and so on... And in some cases I failed to build the dependencies for my target.
That's why I use only libdbus, which requires only "expat" library (XML parser). And it's not so complicated to use it as it is. 

The ParameterSet struct is like this : (you're right, I was not very clear on this point)

#define MAX_COUNT 10
#define VALUE_MAX_SIZE 128

typedef struct
	int count;
	char value[MAX_COUNT][VALUE_MAX_ SIZE]; 
} ParameterSet;
// MAX_COUNT is the max. number of values, and VALUE_MAX_SIZE is max. string length
// ex : value[0] may contain "hello"

And as I wrote, if I use directly &param.value[index] (where param's type is ParameterSet) in dbus_message_iter_append_basic(), I get a "Segmentation fault".

You say that char[m][n] is not the same type as char*[n]. Why ? Arrays are pointers ([] = *), and addresses are pointers (& = *).

As far as I know, in my case &param.value[index] is like char** (isn't it ?), since value[index] is like char* (a string, a pointer/address to a char, an array of char), and &char* is like char** (both are memory addresses which point to "h"). 
dbus_message_iter_append_basic() knows that it's a string thanks to its second argument "DBUS_TYPE_STRING", then it knows that there's something else after the "h" (up to \0).

Then I don't understand why it crashes.

-----Message d'origine-----
De : dbus-bounces at lists.freedesktop.org [mailto:dbus-bounces at lists.freedesktop.org] De la part de Simon McVittie
Envoyé : jeudi 12 décembre 2013 12:18
À : dbus at lists.freedesktop.org
Objet : Re: dbus_message_set/get_data usage

On 12/12/13 08:07, Brosseau, Vincent wrote:
> Now I understand that I can't attach data to the message in this 
> way... But I'm not sure to understand what are 
> dbus_message_set/get_data used for, exactly (your example with Python doesn't help me, sorry)...

If you don't know why you'd need them, then you don't need them; they're for unusual situations which tend to appear when writing high-level language bindings. They're analogous to g_object_(get|set)_data(), if that's any help.

If in doubt, prefer to use a high-level D-Bus library like GDBus (C, GLib/GObject, reimplements libdbus, my preferred choice) or QtDBus (C++, Qt, wraps libdbus) rather than using libdbus directly. The libdbus documentation does say "If you use this low-level API directly, you're signing up for some pain".

> Anyway, I have another question about attaching parameters.
> When I use dbus_message_iter_init_append() and then 
> dbus_message_iter_append_basic(), the latter needs a (void *)parameter as the third argument.

Yes, or more precisely, a pointer to a type chosen to be appropriate for the second argument: for instance, DBUS_TYPE_INT32 -> (dbus_int32_t *), DBUS_TYPE_STRING -> (char **).

> 	// param contains a field with the number of string values to attach => count
> 	// and an array of string values => value[MAX_COUNT]

Please be specific: if in doubt, quote actual code. Does it look like this

    struct {
      int count;
      char *value[MAX_COUNT];   // of which 0..count-1 contain values
    } param;

    param.count = 2;
    param.value[0] = strdup ("hello");
    param.value[1] = strdup ("world");

or more like this?

    struct {
      int count;
      char value[VALUE_LEN][MAX_COUNT];
    } param;

    param.count = 2;
    strncpy (param.value[0], "hello", VALUE_LEN);
    strncpy (param.value[1], "world", VALUE_LEN);

> 	for( int a = 0; a < param.count; a++ )
> 	{
> 		dbus_message_iter_append_basic( &dbusArg, DBUS_TYPE_STRING, 
> &param.value[a] );

If the type of value is char *[n] then that should work, AFAICS:
value[a] is a char * pointing to the "h" of "hello", so &value[a] is a char ** pointing to a char * pointing to the "h" of "hello", as required.

If the type of value is char[m][n] then value[a] is a char[m] containing "hello", &value[a] points to the "h" of "hello", and your app crashes when libdbus treats it as a char **, and as a result, tries to dereference the bytes at and after the "h" as a char *.

With hindsight, either the type of the third argument should have been const DBusBasicValue * to force the use of a suitable temporary variable, or there should have been a family of type-safe functions like dbus_message_iter_append_string().

> 		const char *arg = param.value[a];
> 		dbus_message_iter_append_basic( &dbusArg, DBUS_TYPE_STRING, &arg );

If in doubt, use a temporary like this, or (preferably) use a higher-level D-Bus library. I use GDBus, when I can.


dbus mailing list
dbus at lists.freedesktop.org

More information about the dbus mailing list