[libvirt] [PATCH] uml_conf.c: don't return an uninitialized pointer
Jim Meyering
jim at meyering.net
Fri Sep 4 14:40:43 UTC 2009
Daniel Veillard wrote:
> On Thu, Sep 03, 2009 at 01:39:25PM +0200, Jim Meyering wrote:
>> Jim Meyering wrote:
>> > Daniel P. Berrange wrote:
>> > ...
>> >>> Actually I did that first, but then un-did it in favor
>> >>> of the change above. Why? because that initialization could
>> >>> mask a failure to initialize in a new case.
>> >>>
>> >>> With per-case initialization, we'd detect the bug at
>> >>> compile/static-analysis time. With the up-front unconditional
>> >>> initialization, we cannot, and would have to rely on testing to find it.
>> >>
>> >> It is a tradeoff, but I still prefer the initialization at time of
>> >> declaration as a safety net, and we do use this pattern pretty much
>> >> everywhere
>> >
>> > Ok. adjusted
>>
>> Actually, I will now try to convince you that we should
>> do it the other way. Not only is it better to have the compiler
>> tell us about this problem, but if ever someone were to add the
>> definition that seems to be missing in the default case, clang
>> would report the preceding initialization (the one you prefer)
>> as a "dead store" error.
>>
> [...]
>>
>> And in every "case" of that switch, there is an assignment to "group".
>> That renders the preceding assignment useless, and hence clang calls it
>> a dead initialization.
>>
>> Just to show you that they're not all so ambiguous, node_device_conf.c:116
>> has a "dead initialization" that is obviously worth fixing:
>>
>> virNodeDevCapsDefPtr caps = def->caps;
>> ...
>> for (caps = def->caps; caps; caps = caps->next) {
>>
>> Posting that separately.
>
> I must admit I don't see a NULL initialization of a pointer for safety
> when entering a routine as a bad thing, actually this could be
> considered a standard feature in any highlevel language.
Then perhaps I didn't explain well.
Here's a small example:
int
foo (void)
{
int ret = 0;
switch (f())
{
case 0:
do_something ();
ret = -1;
break;
case 1:
do_something_else ();
ret = -1;
break;
default:
ret = -2;
break;
}
return ret;
}
In that function, the initialization of "ret" is officially unnecessary.
Or, make it more like the code in question, initializing to
the value used in the "default" case:
int
foo (void)
{
int ret = -2;
switch (f())
{
case 0:
do_something ();
ret = -1;
break;
case 1:
do_something_else ();
ret = -1;
break;
default:
break;
}
return ret;
}
However, Dan argued that he wants to be sure "ret" is defined, in case
someone else (one of the case stmts) forgets. However, that's precisely
the case in which you do *not* want there to be an overarching
definition, because with that "extra", initial assignment, the compiler
cannot warn you if you add a case like this:
case 2:
// ...do things, but forget to set "ret"
break;
However, if you merely declare "ret", with no initial value,
adding that erroneous "case 2" would provoke a warning
about "ret" being used (via the return) undefined.
I prefer to use the compiler as a safety net, whenever possible.
I.e., imho, it is clear that this toy function should be written
like this, with no initial assignment to "ret":
int
foo (void)
{
int ret;
switch (f())
{
case 0:
do_something ();
ret = -1;
break;
case 1:
do_something_else ();
ret = -1;
break;
default:
ret = -2;
break;
}
return ret;
}
More information about the libvir-list
mailing list