[libvirt] [PATCH] remote_internal.c: don't dereference a NULL "conn"

Jim Meyering jim at meyering.net
Thu Sep 3 09:00:38 UTC 2009


Jim Paris wrote:
> Daniel P. Berrange wrote:
>> On Wed, Sep 02, 2009 at 12:26:43PM +0200, Jim Meyering wrote:
>> > Daniel Veillard wrote:
>> > > On Wed, Sep 02, 2009 at 11:58:07AM +0200, Jim Meyering wrote:
>> > >> Here's the test just before the else-if in the patch below:
>> > >>
>> > >>     if (conn &&
>> > >>         conn->driver &&
>> > >>         STREQ (conn->driver->name, "remote")) {
>> > >>
>> > >> So, in the else-branch, "conn" is guaranteed to be NULL.
>> > >> And dereferenced.
>> > >>
>> > >> This may be only a theoretical risk, but if so,
>> > >> the test of "conn" above should be changed to an assertion,
>> > >> and/or the parameter should get the nonnull attribute.
>> > >
>> > >   I'm fine with your patch, so that even if code around changes
>> > > having a gard is IMHO a good thing
>> >
>> > Thanks for the quick review.
>> > Daniel Berrange said he'd prefer the nonnull approach I mentioned above,
>> > so I've just adjusted (caveat, still not tested or even compiled)
>>
>> Yeah, for functions where it is expected that the passed in param
>> be non-NULL, then annotations are definitely the way togo. This
>> lets the compiler/checkers validate the callers instead, avoiding
>> the need to clutter the methods with irrelevant NULL checks.
>
> Does __attribute__((__nonnull__())) really cover the case we're
> concerned about here?  As I understand it, it tells the compiler
>
>   1) if the caller obviously passes NULL, emit a warning
>   2) assume that the arguments are non-NULL and optimize away
>
> In other words it will do nothing to prevent a null dereference and

That's true, in a way.

> will even make it more likely since non-NULL checks will be skipped.

Once a parameter is marked nonnull, tools can do a better job
of spotting *callers* that might mistakenly pass a corresponding NULL
argument.  Without nonnull, the compiler could only detect a problem
*inside* the function, in the case that we lack adequate protection
on a dereferencing expression.

For external functions, it's a policy decision.  If you say the
function is defined only for non-NULL pointers, then you may as well
add an assert(ptr != NULL) and __attribute__((nonnull...)).  Otherwise,
we must perform the test at run-time.  Note that memcpy, strcpy, unlink,
stat, etc. have parameters that can be marked with the nonnull attribute.
That's a plus, because compiler/analyzer tools can then warn callers
about misuse, and they needn't be burdened with detecting and diagnosing
NULL pointers.

Using attribute-nonnull is not an excuse for skipping a "ptr == NULL"
test.  Rather, it is a way to tell the compiler that we require
every caller to ensure that a "ptr" parameter is non-NULL.

This has been true of most internal "conn" parameters for some time.
There were even quite a few places in the code where "conn" would be
dereferenced without first ensuring it is non-NULL, but there was no
way to trigger the NULL-deref in those seemingly-erroneous bits of code,
because upstream tests ensured non-NULL conn.

I spent time adding guards, as I would find those disturbing bits
of code.  I now think that I should have been adding assertions and/or
attribute-nonnull directives, instead.

Adding an "assert (ptr != NULL);" is tempting, because then we'd get
a pretty diagnostic with filename:lineno rather than just a segfault,
whenever this assumption is violated.  However, adding a raw "assert"
use in library grade code is frowned upon, to say the least.




More information about the libvir-list mailing list