Geoffrey1014 / SA_Bugs

record bugs of static analyzers
3 stars 1 forks source link

GCC Static Analyzer emits wrong path note "(3) `e` is NULL". #11

Open Geoffrey1014 opened 1 year ago

Geoffrey1014 commented 1 year ago

date: 2022-11-15 commit: 225f9c8805fb1ba68a877383095f38a9563526ee args: -fanalyzer -O0 test:

#include <stdio.h>
void a( int *d  , int* e) { 
  printf("NPD_FLAG\n");
  e == 0 && (d = 0) != *e; // *f  result in npd
}
int main() {
    int i =5;
    a(0 ,&i);
}

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

Geoffrey1014 commented 1 year ago

I encountered a false positive when compiling the following MCVE program with gcc (trunk) with -fanalyzer -O0 in https://godbolt.org/z/qnM58d8v5

#include <stdio.h>
void a( int *d  , int* e) { 
  printf("NPD_FLAG\n");
  e == 0 && (d = 0) != *e; // *f  result in npd
}
int main() {
    int i =5;
    a(0 ,&i);
}

results in:

<source>: In function 'a':
<source>:4:21: warning: comparison between pointer and integer
    4 |   e == 0 && (d = 0) != *e; // *e  result in npd
      |                     ^~
<source>:4:24: warning: dereference of NULL 'e' [CWE-476] [-Wanalyzer-null-dereference]
    4 |   e == 0 && (d = 0) != *e; // *e  result in npd
      |                        ^~
  'a': events 1-4
    |
    |    4 |   e == 0 && (d = 0) != *e; // *e  result in npd
    |      |   ~~~~~~~^~~~~~~~~~~~~~~~
    |      |          |     |       |
    |      |          |     |       (4) dereference of NULL 'e'
    |      |          |     (2) ...to here
    |      |          |     (3) 'e' is NULL
    |      |          (1) following 'true' branch (when 'e' is NULL)...
    |
Compiler returned: 0

Gcc static analyzer reports " dereference of NULL 'e' " at line 4, which is a false positive, while it gives wrong path note "(3) 'e' is NULL".

If I change int *d to int d as the following one, the NPD warning disappears, while d is unrelated to e.

#include <stdio.h>
void a( int d  , int* e) { 
  printf("NPD_FLAG\n");
  e == 0 && (d = 0) != *e; // *f  result in npd
}
int main() {
    int i =5;
    a(0 ,&i);
}

If I change the original code to the following one by removing variable d, the NPD warning also disappears.

#include <stdio.h>
void a(int* e) { 
  printf("NPD_FLAG\n");
  e == 0 && *e; // *e  result in npd
}
int main() {
    int i =5;
    a(&i);
}
Geoffrey1014 commented 1 year ago

The origianl one is essentially same as this one.

report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107733

I got a false positive warning when compiling the following program with gcc(trunk) -fanalyzer -O0 in https://godbolt.org/z/YbeGcc5cd. After deleting int *d = 0;, the NPD disappears. I think it is ok for gcc to emit this FP warning, but deleting the unrelated code int *d = 0; should not affect the result. And the path note (3) 'e' is NULL is wrong, this may suggest some problems.

I have tried this with gcc 12, gcc 11, and gcc 10, and all of them have this phenomenon.

Program:

#include <stdio.h>
void a( int* e) { 
  printf("NPD_FLAG\n");
  if(e == 0){
       int *d = 0;
        *e = 1;
  } 
}
int main() {
    int i =5;
    a(&i);
}

Warning:

<source>: In function 'a':
<source>:6:12: warning: dereference of NULL 'e' [CWE-476] [-Wanalyzer-null-dereference]
    6 |         *e = 1;
      |         ~~~^~~
  'a': events 1-4
    |
    |    4 |   if(e == 0){
    |      |     ^
    |      |     |
    |      |     (1) following 'true' branch (when 'e' is NULL)...
    |    5 |        int *d = 0;
    |      |             ~
    |      |             |
    |      |             (2) ...to here
    |      |             (3) 'e' is NULL
    |    6 |         *e = 1;
    |      |         ~~~~~~
    |      |            |
    |      |            (4) dereference of NULL 'e'
    |
Geoffrey1014 commented 1 year ago

Thanks for your explanation. It helps a lot.

It's analyzing "a" twice: as called by main, and as a standalone function.

I am wondering if is there any option for gcc to specify main as the only top-level function, i.e., do not let a be analyzed standalone.

deleting the unrelated code int *d = 0; should not affect the result (but does)

I am also curious about why deleting int *d = 0; affects the analyzing results. Do you have thoughts on this?

ghost commented 1 year ago

CSA not FP: https://godbolt.org/z/haq6TrsxG.