Geoffrey1014 / SA_Bugs

record bugs of static analyzers
3 stars 1 forks source link

Unrelated code has effect on the analysis result of GCC Static Analyzer #19

Open 0-0x41 opened 1 year ago

0-0x41 commented 1 year ago

date: 2022-12-11 commit: 8c8ca873216387bc26046615c806b96f0345ff9d args: -O2 -fanalyzer test:

#include "stdio.h"
int main()
{
    int b = 1;
    int e = 2;
    int f = 3;
    int t = 4;
    int *g[] = {&e, &e};
    int *h = &b;
    int *l = &f;
    int *j = &f;

    for (int d = 0; d <= 1; d++)
    {
        *j = *h && (h = g[d]);
    }

    for (int c = 0; c <= 1; c++)
        for (int i = 0; i <= 1; i++)
        {
            int k;
            printf("NPD_FLAG\n");
            k = (l == &l);
        }
}

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

0-0x41 commented 1 year ago

For the following case, I made the following two unrelated code changes that will affect the analysis results of the analyzer. Here is the analysis result of this case before doing nothing, please take a look, thanks a lot.

#include "stdio.h"
int main()
{
    int b = 1;
    int e = 2;
    int f = 3;
    int t = 4;
    int *g[] = {&e, &e};
    int *h = &b;
    int *l = &f;
    int *j = &f;

    for (int d = 0; d <= 1; d++)
    {
        *j = *h && (h = g[d]);
    }

    for (int c = 0; c <= 1; c++)
        for (int i = 0; i <= 1; i++)
        {
            int k;
            printf("NPD_FLAG\n");
            k = (l == &l);
        }
}
<source>:15:14: warning: dereference of NULL 'h' [CWE-476] [-Wanalyzer-null-dereference]
   15 |         *j = *h && (h = g[d]);
      |              ^~
  'main': events 1-9
    |
    |   13 |     for (int d = 0; d <= 1; d++)
    |      |                     ~~^~~~
    |      |                       |
    |      |                       (1) following 'true' branch (when 'd != 2')...
    |      |                       (5) following 'true' branch (when 'd != 2')...
    |      |                       (7) following 'true' branch (when 'd != 2')...
    |   14 |     {
    |   15 |         *j = *h && (h = g[d]);
    |      |         ~~~~~~~~~~~~~~~~~~~~~
    |      |         |  | |  |
    |      |         |  | |  (3) following 'true' branch...
    |      |         |  | (9) dereference of NULL 'h'
    |      |         |  (4) ...to here
    |      |         (2) ...to here
    |      |         (6) ...to here
    |      |         (8) ...to here

(1) Comment out the statement printf("NPD_FLAG\n") in line 22, the NPD warning goes away (https://godbolt.org/z/bzYnPfEos).

(2) The pointer variables l and j point to the same address &f when they are defined. I think the GCC will do some relevant optimization under -O2, so I make a transformation: int *j = &t, then the NPD warning disappears, but when I add __analyzer_eval(j) in line 16, the NPD warning appears again. If the added statement is __analyzer_eval(0 == j), the NPD warning does not appear (https://godbolt.org/z/sMMsqxGaP).

muchang commented 1 year ago

The assembly code may indicate the root cause.

Geoffrey1014 commented 1 year ago

I have reduce this case to the following one.

Hi, David. I found a problem through the following case that the optimization has side effects on static analysis.

#include "stdio.h"
extern void __analyzer_describe ();
extern void __analyzer_eval ();
extern void __analyzer_dump ();

int main()
{
    int b = 1;
    int e = 2;
    int f = 3;
    int *g[] = {&e, &e};
    int *h = &b;
    int *j = &f;

    for (int d = 0; d <= 1; d++)
    {
        *j = (*h && (h = g[d]));
        // __analyzer_dump ();
        __analyzer_eval(h==0);
        // __analyzer_describe(0,h);
    }
    printf("NPD_FLAG %d\n", *j);

}

options: -O2 -fanalyzer Output:

<source>: In function 'main':
<source>:19:9: warning: FALSE
   19 |         __analyzer_eval(h==0);
      |         ^~~~~~~~~~~~~~~~~~~~~
<source>:19:9: warning: UNKNOWN
<source>:19:9: warning: TRUE
<source>:19:9: warning: TRUE
<source>:19:9: warning: UNKNOWN
<source>:19:9: warning: TRUE
<source>:19:9: warning: TRUE
<source>:19:9: warning: UNKNOWN
<source>:17:15: warning: dereference of NULL 'h' [CWE-476] [-Wanalyzer-null-dereference]
   17 |         *j = (*h && (h = g[d]));
      |               ^~
  'main': events 1-9
    |
    |   15 |     for (int d = 0; d <= 1; d++)
    |      |                     ~~^~~~
    |      |                       |
    |      |                       (1) following 'true' branch (when 'd != 2')...
    |      |                       (5) following 'true' branch (when 'd != 2')...
    |      |                       (7) following 'true' branch (when 'd != 2')...
    |   16 |     {
    |   17 |         *j = (*h && (h = g[d]));
    |      |         ~~~~~~~~~~~~~~~~~~~~~~~
    |      |         |  |  |  |
    |      |         |  |  |  (3) following 'true' branch...
    |      |         |  |  (9) dereference of NULL 'h'
    |      |         |  (4) ...to here
    |      |         (2) ...to here
    |      |         (6) ...to here
    |      |         (8) ...to here
    |
Compiler returned: 0

options : -O1 -fanalyzer Output:

<source>: In function 'main':
<source>:19:9: warning: FALSE
   19 |         __analyzer_eval(h==0);
      |         ^~~~~~~~~~~~~~~~~~~~~
<source>:19:9: warning: UNKNOWN
Compiler returned: 0

-O2: https://godbolt.org/z/GeTaeGMaf -O1: https://godbolt.org/z/adnY8aa3K

Geoffrey1014 commented 1 year ago

The problem that __analyzer_eval(h==0); is computed too many times has been kind of solved? https://godbolt.org/z/ba941MdM5

image
ghost commented 1 year ago

GSA optimization related, CSA does not have this problem.