@dmckee
Well, this does not fit in the comments, but here is what:
First you write the correct static analyzer. A โfixโ in this context means that it will not remain silent if there is something dubious regarding the analyzed code, so at this point you are fun to conflate undefined and unspecified behaviors. They are bad and unacceptable in critical code, and you correctly warn them both of them.
But you only want to warn once about a possible error, and also know that your analyzer will be evaluated in tests in terms of "accuracy" and "recall" in comparison with other, possibly incorrect analyzers, so you should not warn twice about one and the same problem ... Whether it's a true or false alarm (you don't know what you never know, otherwise it would be too easy).
So you want to issue one warning for
*p = x; y = *p;
Since, as soon as p is a valid pointer in the first expression, it can be considered a valid pointer in the second expression. And without causing this, you will reduce your score in terms of accuracy metrics.
So, you will teach your analyzer to assume that p is a valid pointer, as soon as you warned about it for the first time in the above code, so you don't warn about it a second time. More generally, you will learn to ignore values โโ(and execution paths) that correspond to what you have already warned about.
Then you realize that not many people write critical code, so you do other, easy tests for the rest of them, based on the results of the initial correct analysis. Say the program slicer C.
And you say โthemโ: you do not need to check all (possibly often false) alarms emanating from the first analysis. A sliced โโprogram behaves the same as the original program, if none of them starts. Slicer produces programs that are equivalent for a cut criterion for โdefinedโ execution paths.
And users cheerfully ignore alarms and use the slicer.
And then you understand that there may be a misunderstanding. For example, most memmove implementations (you know, the one that processes overlapping blocks) actually cause unspecified behavior when called with pointers that don't point to the same block (comparing addresses that don't point to the same block). And your analyzer ignores both execution paths, since both of them are undefined, but in fact both execution paths are equivalent, and all is well.
Thus, there should not be any misunderstanding regarding the meaning of alarms, and if someone intends to ignore them, only error-free behavior undefined should be excluded.
And you are so much interested in distinguishing between undefined behavior and undefined behavior. No one can blame you for ignoring the latter. But programmers will write the first one without even thinking about it, and when you say that your slicer eliminates the "incorrect behavior" of the program, they will not feel the way they want.
And this is the end of the story, which definitely did not fit into the commentary. I apologize to those who read this far.