[ANNOUNCE] D-Bus 1.0 RC 1 (0.93) released

Kimmo Hämäläinen kimmo.hamalainen at nokia.com
Mon Sep 18 09:17:50 PDT 2006


On Mon, 2006-09-18 at 16:50, ext Havoc Pennington wrote:
> Hi,
> Kimmo Hämäläinen wrote:
>  > I'm just telling you something I have learned while developing an
>  > embedded Linux system. In such a swapless, low-RAM system we sometimes
>  > might want to deny memory allocations of an application to prevent the
>  > whole system from crashing. Technologies such as Glib (which just calls
>  > abort() on OOM) do not make this easy (actually pretty impossible).
>  > D-Bus is used also in the lowest levels, so it should allow extremely
>  > robust programs.
>  >
>  > If there is a small thing we can do to make the developer's life easier,
>  > why not do it?
> The basic issue is that it isn't a small thing at all. To do this, we 
> have to:
>   - add a DBusError to *every* function, quite possibly doubling the API
>     size with tons of _with_error variants
>   - remove the ability to shrink the library significantly, since
>     --disable-checks/--enable-checks would now be in the API contract
>   - conduct certain inefficient checks and and over and over on the same
>     data. So for example appending a string to a message could require
>     validation several times as it moves through different functions in
>     the API. _expensive_ compared to just validating untrusted data one
>     time as it enters the address space (from disk or network).
> What would happen in this case I'm very sure:
>   - people would quickly get in the habit of passing NULL for "useless"
>     and "can't happen" DBusError
>   - they would then fail to use DBusError in the cases we have now,
>     i.e. when it does in fact have a purpose in reporting a
>     compile-time-undetectable error condition such as IO errors

I'm not asking this. I think it's enough that we have some static,
boolean variable OOM_happened in the library and that could be queried
with a function. (The variable could be reset by the user, so that we
don't need to add reseting it to each public function.) This way we
would not need more DBusErrors or breaking the API.

If we have this and the validation functions (I could provide them,
directly or indirectly), then I think one has the chance to build robust
software on top of the library.

> If you really think I'm wrong, nothing says these _with_error() variants 
> have to be in libdbus itself; they could as easily be a binding. So 
> someone could offer a library that provides just what you say. If lots 
> of people were using that library then we'd have to consider whether to 
> include it in main libdbus. But I doubt a lot of people would be.

Yes, I understand that everything can be done in bindings and client
programs. However, as it requires more code, the developer is usually
too lazy to do it, unless it's really easy.

> > Yes, it's a bug, but I don't understand why D-Bus library should make it
> > more difficult to fix the bug.
> These checks are there to make it easier. The check prints out a warning 
> about exactly what is wrong, and the fix is almost always trivial.
> > Think about the time when developing the
> > client program -- the more error codes/messages the easier for the
> > developer.
> That's why return_if_fail prints an error message
> > Also, there should be a way to handle these errors in
> > run-time because some of us (with bad genes?) make mistakes that are not
> > caught in development time (asserts are not an alternative here).
> If you're going to write:
> try {
>     dbus_blah(foo);
> } catch (NullPointerException e) {
> }
> then you may as well write:
> if (foo != NULL)
>     dbus_blah(foo);
> IOW you are proposing:
> try {
>     dbus_blah(foo); // this is buggy
> } catch (BugInProgramException e) {
> }
> catching null pointer exception is definitely frowned upon in Java too; 
> catching a bug instead of fixing it is just weird. Either way you have 
> to modify the code!

What about the case of a D-Bus library wrapper. If the user of the
wrapper library gives invalid arguments, the library should return a
special error code to the user. And different error code in case of OOM.
D-Bus error messages on the console are not convenient here, because the
wrapper would want to hide the fact that D-Bus is the message bus
implementation (so that changing message bus API would only mean
changing the wrapper library).

In this case the D-Bus API contract 'return code semantics depends on
validness of arguments' does not work optimally, since the wrapper
library would always need to validate the arguments itself to make sure
that the error code can only mean OOM, and that is not desired in after
the application is 'bug free'. (Sure, this could be, too, work around
with a 'toggle validation' function in the library, but who would
remember to use it or make sure that others use it...)

> > This crashing client library is another thing I don't understand. I
> > simply don't understand why the library should 'punish' the user instead
> > of helping him to develop robust programs. If there is a crash, at least
> > the reason should be told (e.g. by returning an error code). I believe
> > this is a must for some high-level bindings as well, so that they can
> > raise an exception instead of just crashing.
> High-level bindings must validate sufficiently to be sure they don't 
> pass anything invalid to libdbus.

Yes, after we have the validation functions, this is possible, but not
the best solution, as I said above. (Will do for me, though ;))

> > The contract must tell exactly what can be returned and when.
> The contract is something like:
>   - the allowed args are xyz. if those are passed, abc happens.
>   - if you pass non-allowed args, dbus will make a best effort
>     to notice and print an explanatory warning, but has no
>     defined behavior
> Note that in C/C++, there is no robust RTTI and anything can segfault if 
> touched improperly. So the contract for non-allowed args is *at most* 
> that certain common ones are handled; it's impossible to generically 
> handle anything passed in.

Yes, arguments often cannot be validated well enough, because it's not
possible or it would be too slow. But I still would not bundle many
errors behind one error code, since it would encourage adding 'just one
more' error behind the same error code and brings trouble if the
implementation changes and new errors are possible (i.e. not scalable
and the API is supposed to be stable). However, we could work around
this the 'errno way' as I suggested above.

>   There is
> > no disclaimer 'your program must be bug-free'. What other API than the
> > D-Bus API requires this?
> In C/C++, pretty much all of them. The entire glib+gtk stack for 
> starters, but many others effectively do. Some use the "print warning 
> and enter undefined mode" approach and some just crash if given invalid 
> args. cairo has its own trick, which is that it stops drawing anything. 
> So if you pass invalid args nothing gets drawn after that and you have 
> to try and figure out which function is the problem. I prefer the 
> warning ;-)

I know already that Glib is broken (at least in OOM-sense in embedded
environment), but I would not make the same mistake in D-Bus, since it
must be usable also in the lowest levels (e.g. daemons that cannot be
restarted if they crash).

BR, Kimmo

> Havoc

More information about the dbus mailing list