19

I would like to see a small but complete snippet of code that will cause Clang's static analyser to complain. My motivation is mostly that I'm trying to get it to work on my PIC32 code, and I need a way to distinguish between "all the code is fine" and "it's not actually doing anything". It's also partly curiosity, since I can't seem to come up with a simple example myself.

C89/ANSI or C99 is fine, and ideally I'd like to see it pick up a simple memory leak. My usage is

clang --analyze test.c
detly
  • 29,332
  • 18
  • 93
  • 152

1 Answers1

15

I found a "bug" in my code (the only one ;-) that triggers by that, and that is not detected by -Wall. I cooked it down to the following

struct elem {
  struct elem *prev;
  struct elem *next;
};

#define ELEM_INITIALIZER(NAME) { .prev = &(NAME), .next = &(NAME), }

struct head {
  struct elem header;
};

#define HEAD_INITIALIZER(NAME) { .header = ELEM_INITIALIZER(NAME.header) }

int main(int argc, char ** argv) {
  struct head myhead = HEAD_INITIALIZER(myhead);
}

This is a relatively straight forward implementation of a linked list, but this is not important here. The variable myhead is unused in a common sense application of the term, but for the compiler it is used since inside the initializer the address of a field is taken.

clang correctly analyzes this as

/tmp 11:58 <722>% clang --analyze test-clang.c
test-clang.c:25:15: warning: Value stored to 'myhead' during its initialization is never read
  struct head myhead = HEAD_INITIALIZER(myhead);
              ^        ~~~~~~~~~~~~~~~~~~~~~~~~
1 diagnostic generated.

Edit: I found another one that also detects stack memory proliferation

char const* myBuggyFunction(void) {
  return (char[len + 1]){ 0 };
}

This is not detected by gcc, open64 or clang with -Wall, but by clang with --analyze.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
  • Does the job, thanks :) I must say, I came up with the most obvious and the most creative bloody memory leaks I could dream up, and it let all of them pass. Clearly it knows enough to know I was testing it. – detly Aug 17 '10 at 06:29
  • @detly: has been fun, learned clang by it :) for my curiosity what are leaks in a context of static analysis? – Jens Gustedt Aug 17 '10 at 07:01
  • Well I'm not 100% sure, but I was under the impression that many static analysis tools, including clang, can detect potential runtime memory problems (such as `p = malloc(...); p = q;`). I could be wrong about that. – detly Aug 17 '10 at 07:34
  • Hm, it could, if they somehow hardcode that `malloc` does an allocation. Shouldn't this be documented somewhere? At least it should give you an "initialization not used" warning in this trivial case :) But for dynamic memory problems there is `valgrind` which does an excellent job, so perhaps the concentrate their efforts to other potential bugs. – Jens Gustedt Aug 17 '10 at 08:14
  • 1
    That seems reasonable. Usually I don't use dynamic memory, so it's not an issue, I was just curious whether it would pick it up. Also, I can't use valgrind anyway, since it's code for the PIC32MX (ie. embedded). – detly Aug 17 '10 at 08:47
  • In that added example: are you sure it shouldn't return a `const char *`? – detly Nov 08 '10 at 03:24
  • @detly: A `T*` is implicitly converted to `T const*`. I had it in here like that, since this was what happened in real life: I had a compound literal that was passed to another function for initialization and then returned by the function itself. `const` or not `const` might have an impact on the severity of the problem, since if it is `const`, the compiler is allowed not to place it on the stack but statically in the "text" segment. So the error might be even hidden even longer, until you compile with a compiler that does put it on the stack. gcc and opencc are e.g different in that. – Jens Gustedt Nov 08 '10 at 07:43