https://gcc.gnu.org/bugzilla/show_bug.cgi?id=112790
Bug ID: 112790
Summary: -Wanalyzer-deref-before-check false positives seen in
Linux kernel due to inlining
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: analyzer
Assignee: dmalcolm at gcc dot gnu.org
Reporter: dmalcolm at gcc dot gnu.org
Target Milestone: ---
https://godbolt.org/z/4fjjcfbPb
False positive on:
typedef unsigned char u8;
struct inode {
void *i_mapping;
u8 i_blkbits;
};
struct block_device {
struct inode *bd_inode;
};
int sync_blockdev(struct block_device *bdev);
int set_blocksize(struct block_device *bdev, u8 size) {
if (bdev->bd_inode->i_blkbits != size) {
sync_blockdev(bdev);
}
return 0;
}
extern int filemap_write_and_wait(void *);
int sync_blockdev(struct block_device *bdev) {
if (!bdev)
return 0;
return filemap_write_and_wait(bdev->bd_inode->i_mapping);
}
$ xgcc B. -Wall -fno-delete-null-pointer-checks -O2 -fanalyzer -g -S
False positive:
In function ‘sync_blockdev’,
inlined from ‘set_blocksize’ at t.c:12:5:
t.c:18:6: warning: check of ‘bdev’ for NULL after already dereferencing it
[-Wanalyzer-deref-before-check]
18 | if (!bdev)
| ^
‘set_blocksize’: events 1-4
|
| 11 | if (bdev->bd_inode->i_blkbits != size) {
| | ~~~~~^~~~~~~~~~
| | | |
| | | (1) pointer ‘bdev’ is dereferenced here
| | (2) following ‘true’ branch...
| 12 | sync_blockdev(bdev);
| | ~~~~~~~~~~~~~
| | |
| | (3) ...to here
| | (4) inlined call to ‘sync_blockdev’ from ‘set_blocksize’
|
+--> ‘sync_blockdev’: event 5
|
| 18 | if (!bdev)
| | ^
| | |
| | (5) pointer ‘bdev’ is checked for NULL here but it was
already dereferenced at (1)
|
The check from the inlined function shouldn't lead to this warning.
All of "-fno-delete-null-pointer-checks -O2 -fanalyzer -g" seem to be
necessary.
(reduced from block/bdev.c)