Geoffrey1014 / SA_Bugs

record bugs of static analyzers
2 stars 1 forks source link

GCC Static Analyzer cannot handle the initialization of an array with a for loop #16

Open 0-0x41 opened 1 year ago

0-0x41 commented 1 year ago

date: 2022-12-2 commit: 8c8ca873216387bc26046615c806b96f0345ff9d args: -O0 -fanalyzer test:

#include "stdio.h"
int main() {
    int i = 0;
    int *g = &i;
    int m[1];

    for (int j = 0; j < 1; j++) {
         m[j] = 0;
    }

    if (m[0])
        ;
    else
        g = m[i];

    printf("NPD_FLAG\n");
    *g = 1;
}

report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109190 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/KvoxvPq5c. When I replace the array m with the variable a (https://godbolt.org/z/jTzo9bEo9), the NPD appears.

#include "stdio.h"
int main() {
    int i = 0;
    int *g = &i;
    int m[1];

    for (int j = 0; j < 1; j++) {
         m[j] = 0;
    }

    if (m[0])
        ;
    else
        g = m[i];

    printf("NPD_FLAG\n");
    *g = 1;
}
0-0x41 commented 1 year ago

Also for this program, I made the following transformations, which produced a false positive. Similarly, when the array m is replaced by the variable a, then the false positive disappears (https://godbolt.org/z/cr6EhTYcj).

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

#include "stdio.h"
int main() {
    int i = 1;
    int *g = &i;
    int m[1];

    for (i = 0; i < 1; i++)
        m[i] = 1;

    if (m[0])
        ;
    else
        g = 0;

    printf("NPD_FLAG\n");
    *g = 1;
}
<source>:17:8: warning: dereference of NULL 'g' [CWE-476] [-Wanalyzer-null-dereference]
   17 |     *g = 1;
      |     ~~~^~~
  'main': events 1-8
    |
    |    7 |     for (int j = 0; j < 1; j++){
    |      |                     ~~^~~
    |      |                       |
    |      |                       (1) following 'true' branch (when 'j <= 0')...
    |      |                       (3) following 'false' branch (when 'j > 0')...
    |    8 |         a = 0;
    |      |         ~~~~~          
    |      |           |
    |      |           (2) ...to here
    |......
    |   11 |     if (a)
    |      |        ~               
    |      |        |
    |      |        (4) ...to here
    |      |        (5) following 'false' branch (when 'a == 0')...
    |......
    |   14 |         g = a;
    |      |         ~~~~~          
    |      |           |
    |      |           (6) ...to here
    |      |           (7) 'g' is NULL
    |......
    |   17 |     *g = 1;
    |      |     ~~~~~~             
    |      |        |
    |      |        (8) dereference of NULL 'g'
Geoffrey1014 commented 1 year ago

i think it is because gcc static analyzer can not model array very precisely. Modeling array is very hard. Maybe at some limited situation, for example, an array is initialized by never change, static analyzer should handle it.

0-0x41 commented 1 year ago

Indeed, gcc static analyzer does not generate FN / FP if I do initialization operations on it while the array is defined, which may be a combination problem under for loops and arrays.

#include "stdio.h"
int main()
{
    int i = 0;
    int *g = &i;
    int m[1] = {0};

    // for (int j = 0; j < 1; j++)
    // {
    //     m[j] = 0;
    // }

    if (m[0])
        ;
    else
        g = m[i];

    printf("NPD_FLAG\n");
    *g = 1;
}
Geoffrey1014 commented 1 year ago

GSA does not known m[0] after initialization. https://godbolt.org/z/ajxz1jcce But CSA does: https://godbolt.org/z/KWbaf4jbK Input:

#include "stdio.h"
void __analyzer_eval( int);

int main() {
    int i = 0;
    int *g = &i;
    int m[1];

    for (int j = 0; j < 1; j++) {
         m[j] = 0;
    }
    __analyzer_eval(m[0]);
    if (m[0]){
        __analyzer_eval(m[0]);
    }
    else{
        __analyzer_eval(m[0]);
        g = m[i];
    }

    printf("NPD_FLAG\n");
    *g = 1;
}

Output:

<source>: In function 'main':
<source>:18:11: warning: assignment to 'int *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
   18 |         g = m[i];
      |           ^
<source>:12:5: warning: UNKNOWN
   12 |     __analyzer_eval(m[0]);
      |     ^~~~~~~~~~~~~~~~~~~~~
<source>:14:9: warning: UNKNOWN
   14 |         __analyzer_eval(m[0]);
      |         ^~~~~~~~~~~~~~~~~~~~~
<source>:17:9: warning: UNKNOWN
   17 |         __analyzer_eval(m[0]);
      |         ^~~~~~~~~~~~~~~~~~~~~
Compiler returned: 0
ghost commented 10 months ago

CSA can handle: https://godbolt.org/z/9j7jj71Gd