LWN.net Logo

Real world experience

Real world experience

Posted May 22, 2011 10:19 UTC (Sun) by tialaramex (subscriber, #21167)
Parent article: What Every C Programmer Should Know About Undefined Behavior #3/3

On Thursday I was confronted with a pile of HTML diagnostic output from Clang (specifically checker-256 according to the metadata) for some code we GPL'd a while back.

Disappointingly so far as I can tell the output fits roughly into two categories:

1. I knew that and I don't care. e.g. Telling me that there are some trivial dead stores in code that we wrote to be transparent rather than fast. Not Clang's fault it can't read my mind, but it's still useless.

2. Confusing to the point of probably wrong. e.g. we have some code which does roughly:

for (int k = 0; k < length; ++k) { /* initialise */ }
for (int k = 0; k < length; ++k) { /* do something */ }
for (int k = 0; k < length; ++k) { /* wrap up */ }

Clang's analysis appears to claim that if the first loop exists immediately, but the second loop gets run, we access uninitialised bytes. Well, OK. But, how can one of these identical loops with constant length run, and not the others? Clang apparently thinks this part of the analysis is too obvious to bore a human with it. So we have no idea, all we know is Valgrind never sees these imaginary garbage reads in running code, which tends to make us suspect an analysis bug. It would be nice if the diagnostic was clear enough to say for sure.

Really the only semi-useful output was some code which Clang noticed is confused about whether (p == NULL) is possible, testing for it in one place and then not testing elsewhere. We fixed that, but that's one useful report compared to dozens that were a waste of time to read.

I recall reading a previous LWN article in which it was claimed that THIS is what makes static analysis hard. Figuring out what you should report in order that reading your diagnostics is a good use of the programmer's time. Right now Clang's offering isn't there. Sorry.


(Log in to post comments)

Real world experience

Posted May 22, 2011 18:43 UTC (Sun) by cbcbcb (guest, #10350) [Link]

for (int k = 0; k < length; ++k) { /* initialise */ }
for (int k = 0; k < length; ++k) { /* do something */ }
for (int k = 0; k < length; ++k) { /* wrap up */ }

Clang's analysis appears to claim that if the first loop exists immediately, but the second loop gets run, we access uninitialised bytes. Well, OK. But, how can one of these identical loops with constant length run, and not the others?
If an operation in /* initialise */ performs a store which could alias with length then (as far as the analysis is concerned) the 2nd loop may run more iterations than the first.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds