GCC --Wanalyzer-null-dereference false negative with `*q == 0`
Opened this issue · 5 comments
date: 2023-1-9
commit: 8c8ca873216387bc26046615c806b96f0345ff9d
args: -O0 -fanalyzer
test:
#include "stdio.h"
void __analyzer_eval(int);
int *f(int *);
int *f(int *q)
{
__analyzer_eval(q == 0);
if (q == 0)
{
__analyzer_eval(q == 0);
if (*q == 0)
{
printf("Hello World!");
}
}
}
report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108403
fix:
original:
I got a false negative error when compiling the following program with gcc(trunk) -O0 -fanalyzer
in https://godbolt.org/z/4f7e3z8dE.
In this case, after entering the first if branch, the result of eval on line 10 is TRUE. At this time, the fact known to the analyzer is that the pointer q
is NULL, and then, for *q == 0
on line 11, analyzer does not generate an NPD warning, which is a little odd.
Here is the analysis result of the case. Thank you for taking the time to review this case.
Input:
#include "stdio.h"
void __analyzer_eval(int);
int *f(int *);
int *f(int *q)
{
__analyzer_eval(q == 0);
if (q == 0)
{
__analyzer_eval(q == 0);
if (*q == 0)
{
printf("Hello World!");
}
}
}
Output:
<source>: In function 'f':
<source>:7:5: warning: UNKNOWN
7 | __analyzer_eval(q == 0);
| ^~~~~~~~~~~~~~~~~~~~~~~
<source>:10:9: warning: TRUE
10 | __analyzer_eval(q == 0);
| ^~~~~~~~~~~~~~~~~~~~~~~
CSA correctly gives the NPD warning: https://godbolt.org/z/jP4hv4c6j and does not evaluate those evaluation statements in the second if
statement.
Hi, David.I think this case may be a duplicate of Bug 107733 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107733), because I can reduce it to the following case_1. But, I tried to modify this case to the following case_2 (https://godbolt.org/z/qTze3Mh6T). It seems that GCC adds two contradictory conditions (q == 0 and *q == 0) to equivlent classes. I do not think this still counts a duplicate of case_1. But I am not very sure. Could you spare some time to help me understand this case? Maybe I can help to contribute to GCC Static Analyzer. Thanks a lot!
case_1
#include "stdio.h"
int *f(int *q)
{
if (q == 0)
{
*q == 0;
}
}
case_2
#include "stdint.h"
#include "stdio.h"
#include <stdbool.h>
#include <stdlib.h>
extern void __analyzer_describe ();
extern void __analyzer_eval ();
extern void __analyzer_dump ();
extern void __analyzer_dump_state (const char *name, ...);
extern void __analyzer_dump_region_model ();
extern void __analyzer_dump_exploded_nodes ();
int *f(int *q)
{
if (q == 0 && *q == 0)
{
__analyzer_dump ();
__analyzer_eval (q == 0);
__analyzer_eval (*q == 0);
}
}
output of case_2:
rmodel:
stack depth: 1
frame (index 0): frame: 'f'@1
clusters within root region
cluster for: (*INIT_VAL(q_8(D)))
ESCAPED
m_called_unknown_fn: FALSE
constraint_manager:
equiv classes:
ec0: {(int)0 == INIT_VAL((*INIT_VAL(q_8(D)))) == [m_constant]'0'}
ec1: {(void *)0B == INIT_VAL(q_8(D)) == [m_constant]'0B'}
constraints:
<source>: In function 'f':
<source>:19:9: warning: TRUE
19 | __analyzer_eval (q == 0);
| ^~~~~~~~~~~~~~~~~~~~~~~~
<source>:20:9: warning: TRUE
20 | __analyzer_eval (*q == 0);
| ^~~~~~~~~~~~~~~~~~~~~~~~~
Compiler returned: 0
unrelated code has effect
https://godbolt.org/z/n9fjdfnf4
CSA not FN: https://godbolt.org/z/W9eresc93