Geoffrey1014 / SA_Bugs

record bugs of static analyzers
2 stars 1 forks source link

GCC --Wanalyzer-null-dereference false negative with `*f = 1` #13

Open 0-0x41 opened 1 year ago

0-0x41 commented 1 year ago

date: 2022-11-22 commit: 8c8ca873216387bc26046615c806b96f0345ff9d args: -O0 -fanalyzer test:

#include <stdio.h>
int main() {   
  int e = 1;
  int *f;

  for (int i = 0; i < 1; i++) {
    e = 0;
    __analyzer_eval(0 == e);
  }

  __analyzer_eval(0 == e);
  f = e;

  __analyzer_eval(0 == f);
  *f = 1;

  return 0;
}

report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108428 fix: original:

0-0x41 commented 1 year ago

I got a false negative error when compiling the following program with gcc(trunk) -fanalyzer -O0 in https://godbolt.org/z/65bzcYr19. After changing int e = 1 to int e = 0, the NPD appears.

By adding the __analyzer_eval() at the appropriate place in the code, I found that after iterating through the for loop once and exiting the loop body, the result for 0 == e is unknown. However, as mentioned above, after changing int e = 1 to int e = 0, the result for 0 == e is true.

Here is the result of the program, please take a look, thank you.

#include <stdio.h>
int main() {   
  int e = 1;
  int *f;

  for (int i = 0; i < 1; i++) {
    e = 0;
    __analyzer_eval(0 == e);
  }

  __analyzer_eval(0 == e);
  f = e;

  __analyzer_eval(0 == f);
  *f = 1;

  return 0;
}
<source>: In function 'main':
<source>:8:5: warning: TRUE
    8 |     __analyzer_eval(0 == e);
      |     ^~~~~~~~~~~~~~~~~~~~~~~
<source>:8:5: warning: TRUE
<source>:11:3: warning: UNKNOWN
   11 |   __analyzer_eval(0 == e);
      |   ^~~~~~~~~~~~~~~~~~~~~~~
<source>:14:3: warning: UNKNOWN
   14 |   __analyzer_eval(0 == f);
      |   ^~~~~~~~~~~~~~~~~~~~~~~
muchang commented 1 year ago

GCC can only infer the value of e when e is assigned to the same value in lines 3 and 7. It would be related to the challenge of finding the invariant for the loop.

This false negative is kind of interesting, but we should report other more convincing issues first in my opinion.

Geoffrey1014 commented 1 year ago

I got a false negative error when compiling the following program with gcc(trunk) -fanalyzer -O0 . It is obvious that *f = 1; ( at line 15 ) will lead to a NPD error, but gcc static analyzer can not find it.

And i found that analyzer did not know __analyzer_eval(0 == e); and __analyzer_eval(0 == f); were both true. In addition, i observed that analyzer seemed to enter the loop for two times (it evaluated __analyzer_eval(0 == e); for two times). I think this may hint at something wrong. https://godbolt.org/z/EjYqhsrWe

In addition, CSA does a better job : https://godbolt.org/z/54n5so49P

#include <stdio.h>
extern void __analyzer_eval (int);
int main() {   
  int e = 1;
  int *f;

  for (int i = 0; i < 1; i++) {
    e = 0;
    __analyzer_eval(0 == e);
  }
  __analyzer_eval(0 == e);
  f = (int*) e;

  __analyzer_eval(0 == f);
  *f = 1;

  return 0;
}

Output:

<source>: In function 'main':
<source>:12:7: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
   12 |   f = (int*) e;
      |       ^
<source>:9:5: warning: TRUE
    9 |     __analyzer_eval(0 == e);
      |     ^~~~~~~~~~~~~~~~~~~~~~~
<source>:9:5: warning: TRUE
<source>:11:3: warning: UNKNOWN
   11 |   __analyzer_eval(0 == e);
      |   ^~~~~~~~~~~~~~~~~~~~~~~
<source>:14:3: warning: UNKNOWN
   14 |   __analyzer_eval(0 == f);
      |   ^~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 0

However, if I change int e = 1 to int e = 0 or to int * e, analyzer can find the NPD error correctly. So maybe the casting to pointer from integer leads to the problem.

ghost commented 10 months ago

CSA not FN: https://godbolt.org/z/W47Tx5rr3