https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123420
Bug ID: 123420
Summary: incorrect -Wfree-nonheap-object
Product: gcc
Version: 15.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: stefan11111 at shitposting dot expert
Target Milestone: ---
This bug happens with tinyX.
$ cat gcc-bug-2.c
/* Version with original tinyX types */
#include <stdlib.h>
#define xfreeData(reg) if ((reg)->data && (reg)->data->size) free((reg)->data)
typedef struct _Region RegionRec, *RegionPtr;
typedef struct _Box {
short x1, y1, x2, y2;
} BoxRec;
typedef struct _RegData {
long size;
long numRects;
/* BoxRec rects[size]; in memory but not explicitly declared */
} RegDataRec, *RegDataPtr;
struct _Region {
BoxRec extents;
RegDataPtr data;
};
/* static or not doesn't matter */
static RegDataRec miBrokenData = {0, 0};
int main()
{
/* Original tinyX bug */
RegionRec region = {{0, 0, 0, 0}, &miBrokenData};
xfreeData(®ion);
}
Compile:
$ gcc gcc-bug-2.c -o gcc-bug -O
gcc-bug-2.c: In function 'main':
gcc-bug-2.c:5:62: warning: 'free' called on unallocated object 'miBrokenData'
[-Wfree-nonheap-object]
5 | #define xfreeData(reg) if ((reg)->data && (reg)->data->size)
free((reg)->data)
|
^~~~~~~~~~~~~~~~~
gcc-bug-2.c:31:5: note: in expansion of macro 'xfreeData'
31 | xfreeData(®ion);
| ^~~~~~~~~
gcc-bug-2.c:25:19: note: declared here
25 | static RegDataRec miBrokenData = {0, 0};
| ^~~~~~~~~~~
$ cat gcc-bug-3.c
/* Simplified version */
#include <stdlib.h>
#define Free(data) if ((data) && (data)->size) free(data)
struct foo {
int size;
};
/* static or not doesn't matter */
static struct foo foo = {0};
int main()
{
Free(&foo);
}
$ gcc gcc-bug-3.c -o gcc-bug
gcc-bug-3.c: In function 'main':
gcc-bug-3.c:5:48: warning: 'free' called on unallocated object 'foo'
[-Wfree-nonheap-object]
5 | #define Free(data) if ((data) && (data)->size) free(data)
| ^~~~~~~~~~
gcc-bug-3.c:16:5: note: in expansion of macro 'Free'
16 | Free(&foo);
| ^~~~
gcc-bug-3.c:12:19: note: declared here
12 | static struct foo foo = {0};
| ^~~
In both cases, free is never called, since size is 0.
Also, even with -O3, the branch does not get optimized out:
$ objdump -d gcc-bug | less
<snip>
0000000000001050 <main>:
1050: 8b 0d be 2f 00 00 mov ecx,DWORD PTR [rip+0x2fbe]
# 4014 <foo>
1056: 85 c9 test ecx,ecx
1058: 75 03 jne 105d <main+0xd>
105a: 31 c0 xor eax,eax
105c: c3 ret
105d: 50 push rax
105e: 48 8d 3d af 2f 00 00 lea rdi,[rip+0x2faf] # 4014
<foo>
1065: e8 c6 ff ff ff call 1030 <free@plt>
106a: 31 c0 xor eax,eax
106c: 5a pop rdx
106d: c3 ret
106e: 66 90 xchg ax,ax
<snip>