This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug tree-optimization/80532] New: warning on pointer access after free
- From: "msebor at gcc dot gnu.org" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Wed, 26 Apr 2017 18:12:23 +0000
- Subject: [Bug tree-optimization/80532] New: warning on pointer access after free
- Auto-submitted: auto-generated
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80532
Bug ID: 80532
Summary: warning on pointer access after free
Product: gcc
Version: 7.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: msebor at gcc dot gnu.org
Target Milestone: ---
Using the value of a pointer that points to an object whose lifetime has ended
is undefined, and a common source of bugs. In the following test case,
function free_list shows an example of one such bug (courtesy of Kernighan &
Ritchie) where a freed pointer is dereferenced.
Function foobar shows another example. That example is interesting because it
shows that GCC is smart enough to eliminate the first call to memset (because
the lifetime of the object the pointer points ends with the subsequent call to
free) but it doesn't eliminate the second call to free or the second call to
memset, even though that operate on an object whose lifetime has ended and will
almost certainly corrupt the heap. GCC also doesn't warn on those calls. It
would be a useful feature if GCC did both: warn and eliminate the undefined
calls/accesses.
$ cat c.c && gcc -O2 -S -Wall -Wextra -Wpedantic
-fdump-tree-optimized=/dev/stdout c.c
#include <stdlib.h>
#include <string.h>
struct node { struct node *next; int value; };
void free_list (struct node *head)
{
struct node *p;
for (p = head; p != 0; p = p->next)
free (p);
}
void foobar (void *p, unsigned n)
{
memset (p, 0, n);
free (p);
free (p);
memset (p, 0, n);
}
;; Function free_list (free_list, funcdef_no=14, decl_uid=2614, cgraph_uid=14,
symbol_order=14)
Removing basic block 5
Removing basic block 6
Removing basic block 7
Removing basic block 8
free_list (struct node * head)
{
struct node * p;
<bb 2> [15.00%]:
if (head_3(D) != 0B)
goto <bb 3>; [85.00%]
else
goto <bb 4>; [15.00%]
<bb 3> [85.00%]:
# p_9 = PHI <p_6(3), head_3(D)(2)>
free (p_9);
p_6 = p_9->next;
if (p_6 != 0B)
goto <bb 3>; [85.00%]
else
goto <bb 4>; [15.00%]
<bb 4> [15.00%]:
return;
}
;; Function foobar (foobar, funcdef_no=15, decl_uid=2622, cgraph_uid=15,
symbol_order=15)
foobar (void * p, unsigned int n)
{
long unsigned int _1;
<bb 2> [100.00%]:
_1 = (long unsigned int) n_2(D);
free (p_4(D));
free (p_4(D));
memset (p_4(D), 0, _1); [tail call]
return;
}
tmp$