What does Coverity/clang static analysis actually do?

Nick Sabalausky a at a.a
Thu Oct 1 20:08:40 PDT 2009


 "Walter Bright" <newshound1 at digitalmars.com> wrote in message 
news:ha37cf$4l2$1 at digitalmars.com...
> Nick Sabalausky wrote:
>>> 3. use of uninitialized variables (no reaching definition)
>>> 3. Optimizer detects and reports it. Irrelevant for D, though, because 
>>> variables are always initialized. The =void case is rare enough to be 
>>> irrelevant.
>>>
>>
>> D variable default-initialization is absolutely no different from your 
>> scenario of a programmer blindly tossing in =0 to shut up a compiler, 
>> *except* that the programmer is never even given the opportunity to do 
>> the right thing. This is *bad*. I *want* variables that haven't meen 
>> manually inited to be statically treated as uninited. C# does this and it 
>> works great.
>
> The difference is the maintenance programmer won't be left puzzling why 
> there is an explicit assignment to the variable that is never used.

Why would there be one? If a value is assigned but never used, then a "must 
assign value before reading" rule wouldn't have tripped over it before the 
initial programmer wrote the assignment in the first place.

> The point to default initialization is consistency in the resulting 
> behavior.

Yes, I'm aware that D's default-initing came about as a better alternative 
to C's "let's introduce unreliable randomness" approach. But we're way past 
that and no one's comparing it to C. But more importantly, it does nothing 
to address my argument that compares it to a more C#-way. I'll explain with 
a scenario you may initially find very familiar:

Johnny is using a language that statically requires variables to have been 
verifiably written to before they can be read. Johnny compiles and gets the 
error "Var 'x' read without having been written to". Johnny jerks his knee 
and blindly throws in "=0". "Bad Johnny. Bad, bad Johnny." scolds Kenneth 
Compiler Writer quite justifiably. Two seconds later, Kenneth changes the 
compiler to blindly throw in "=0". Kenneth is a big hypocrite. Johnny smiles 
because his bad behavior is now automated.

Notice that story has no relevance to C's way of handling (or rather 
ignoring) uninitialized vars. It's D-style vs C#-style, not D-style vs 
C-style. So can you please address how the current D-style is supposed to be 
better than *C#-style*, rather than once again telling us it's better than 
C-style. We know it's better than C-style. That's not the issue.

> Also, the optimizer will remove nearly all of the default initializers if 
> they are dead assignments.
>
> Anyhow, I think this issue was beaten to death in the previous thread on 
> null dereference. I don't wish to divert this thread into rediscussing it, 
> but rather stick with what other kinds of bug-detecting data flow analyses 
> there are?
>
>
>>> 4. dead assignments (assignment of a value to a variable that is never 
>>> subsequently used)
>>> 4. Dead assignments are automatically detected and removed. I'm not 
>>> convinced this should be reported, as it can legitimately happen when 
>>> generating source code. Generating false positives annoy the heck out of 
>>> users.
>>>
>>
>> I'll agree with you here. But it might be nice to have an option to just 
>> simply report them anyway for when the programmer wants to see if there's 
>> any of these around that he can clean up.
>
> I congenitally dislike optional warnings, as I've pontificated at length 
> about here before <g>. The problem is it makes for a wishy-washy 
> definition of the language, and muddies what is legal versus illegal.

The way you've implemented them (as errors rather than real warnings), yes, 
it absolutely does that, as I've pontificated about at length <g>.

> D needs to advance the state of the art with clear thinking about what is 
> legal and what isn't. Warnings and false positives are failures of 
> language design.
>

If you define a failure of language design to be anything that isn't total 
perfection, then sure.

Warnings and false positives are measures that are taken to mitigate 
problems from the *inevitable* imperfections. Many of the imperfections in 
language design are like cliffs, they're potentially hazardous and you can't 
always *realistically* eliminate them. So when we can't realistically 
eliminate them, what we do is we swallow our pride and we put up a railing, 
warning and even a potential false positive.

In fact, D has *already* conceded to being imperfect and accordingly added 
false positives and...well..something warning-like (but more problematic):

- There *are* situations where an implicit narrowing cast would be perfectly 
OK. But does D warn about these false positives for the sake of the 
narrowing casts that aren't OK? Absolutely. And in these cases it forces the 
programmer to cast...but what does "cast(byte)someInt" really do if not your 
"Evil #2" below?

- No return at end of function. It should be pretty clear why a non-void 
function with no return is potentially hazardous. It's also clear that there 
are certain times it would just happen to work out just fine, for instance, 
to just assume "0" or something. But, for damn good reason, a warning got 
tossed in along with false positives. Would it have been better to just make 
it an error? Maybe. But (probably because of the false positive) we couldn't 
agree on that, so what was deemed the best solution? A warning.

And ok, maybe you do consider those things evils. But what else are you 
going to do? Let people just fall off the ledge? No. You concede that it's 
not perfect and accept the warnings and false-positives, as you've already 
done.

Or maybe there *is* a better solution to all those cases. Ok, so what do you 
do in the meantime before it's implemented? Let people fall off the ledge? 
No. You concede that it's not perfect yet and accept the warning and 
false-positives, as you've already done.

But what you *don't* do in either situation is let people trip off the ledge 
and excuse it with "well yea, but a railing would indicate it's not a 
perfect park".

Exceptions are there to help handle runtime errors. But if we didn't wrote 
programs that had error conditions, we wouldn't need exceptions. So 
exceptions must be indicative of failed program design, so let's consider 
exceptions bad and make a fuss everytime someone on our project wants a new 
one created.

Trying to minimize warnings and false positives because they are indicative 
of language design flaws is like trying to minimize safety features on a car 
because they're indicative of a potential for danger, or more iconically, 
like getting rid of all the doctors because they're indicative of illness.


I think part of the problem may be that the ideals of safety, eliminating 
false positives, and a pure "allowed/disallowed" separation have a natural 
tendency to be at odds with each other. Good language design takes 
non-problematic things and allows them, and takes problematic things and 
disallows them. But the problem is, there are very few things, in real life 
or in code, that either always result in a problem or never result in a 
problem. And, even worse, there's a lot that lives somewhere in between. So, 
with only precious few exceptions (if any even exist), every time you allow 
something, you're inherently creating a danger, and every time you disallow 
something, you're inherently creating false positive. And if you don't do 
either you get wishy-washy.

You can't win a game like that, and it's mistake to expect to. The best that 
can be done is make sure your decisions match the how you weigh those values 
(safety, convenience, uniformity). And personally, I weigh safety the 
highest since a lack of it tends to have the worst consequences.

> I generally regard as evil:
>
> 1. bugs that have erratic, random, irreproducible symptoms
>

No argument here :)

> 2. source code that doesn't have an obvious purpose (this includes code 
> inserted solely to suppress a false positive or warning)
>

I don't see what's so evil about that, other than that it's connected to 
false positives and warnings, which you seem to already regard as evil.

> I regard as undesirable:
>
> 3. wishy-washy warnings
>
> 4. overzealous compiler messages that are more akin to nagging than 
> finding actual bugs

If you accept the idea of a compiler (like DMD) having rudimentary built-in 
optional versions of normally separate tools like profiling, unittesting, 
doc generation, etc., and you accept that lint tools are perfectly fine 
tools to use (as I think you do, or am I mistaken?), then I don't see what 
would make lint tools an exception to the "built-ins are ok" attitude 
(especially since a separate one would require a lot of redundant 
parsing/analysis.)







More information about the Digitalmars-d mailing list