This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Warn about compile-time detected freeing of automatic/static variables (PR c/36970)
- From: Jakub Jelinek <jakub at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 30 Jul 2008 11:31:06 -0400
- Subject: [PATCH] Warn about compile-time detected freeing of automatic/static variables (PR c/36970)
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
This patch warns about some cases where free is called on an automatic
or static variable, rather than heap variable.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2008-07-30 Jakub Jelinek <jakub@redhat.com>
PR c/36970
* builtins.c (maybe_emit_free_warning): New function.
(expand_builtin): Process BUILT_IN_FREE even at -O0. Call
maybe_emit_free_warning for BUILT_IN_FREE.
* gcc.dg/free-1.c: New test.
* gcc.dg/free-2.c: New test.
--- gcc/builtins.c.jj 2008-07-28 16:44:55.000000000 +0200
+++ gcc/builtins.c 2008-07-30 15:35:43.000000000 +0200
@@ -207,6 +207,7 @@ static rtx expand_builtin_memory_chk (tr
enum built_in_function);
static void maybe_emit_chk_warning (tree, enum built_in_function);
static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
+static void maybe_emit_free_warning (tree);
static tree fold_builtin_object_size (tree, tree);
static tree fold_builtin_strcat_chk (tree, tree, tree, tree);
static tree fold_builtin_strncat_chk (tree, tree, tree, tree, tree);
@@ -6117,7 +6118,8 @@ expand_builtin (tree exp, rtx target, rt
if (!optimize
&& !called_as_built_in (fndecl)
&& DECL_ASSEMBLER_NAME_SET_P (fndecl)
- && fcode != BUILT_IN_ALLOCA)
+ && fcode != BUILT_IN_ALLOCA
+ && fcode != BUILT_IN_FREE)
return expand_call (exp, target, ignore);
/* The built-in function expanders test for target == const0_rtx
@@ -6994,6 +6996,10 @@ expand_builtin (tree exp, rtx target, rt
maybe_emit_sprintf_chk_warning (exp, fcode);
break;
+ case BUILT_IN_FREE:
+ maybe_emit_free_warning (exp);
+ break;
+
default: /* just do library call, if unknown builtin */
break;
}
@@ -11968,6 +11974,27 @@ maybe_emit_sprintf_chk_warning (tree exp
}
}
+/* Emit warning if a free is called with address of a variable. */
+
+static void
+maybe_emit_free_warning (tree exp)
+{
+ tree arg = CALL_EXPR_ARG (exp, 0);
+
+ STRIP_NOPS (arg);
+ if (TREE_CODE (arg) != ADDR_EXPR)
+ return;
+
+ arg = get_base_address (TREE_OPERAND (arg, 0));
+ if (arg == NULL || INDIRECT_REF_P (arg))
+ return;
+
+ if (SSA_VAR_P (arg))
+ warning (0, "%Kattempt to free a non-heap object %qD", exp, arg);
+ else
+ warning (0, "%Kattempt to free a non-heap object", exp);
+}
+
/* Fold a call to __builtin_object_size with arguments PTR and OST,
if possible. */
--- gcc/testsuite/gcc.dg/free-1.c.jj 2008-07-30 15:30:37.000000000 +0200
+++ gcc/testsuite/gcc.dg/free-1.c 2008-07-30 15:31:01.000000000 +0200
@@ -0,0 +1,26 @@
+/* PR c/36970 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern void free (void *);
+
+char *p, buf3[10], d;
+struct S { char a; int b; } *r;
+
+void foo (void)
+{
+ char buf[10], buf2[10], c;
+ static char buf4[10], e;
+ char *q = buf;
+ free (p);
+ free (q); /* { dg-warning "attempt to free a non-heap object" } */
+ free (buf2); /* { dg-warning "attempt to free a non-heap object" } */
+ free (&c); /* { dg-warning "attempt to free a non-heap object" } */
+ free (buf3); /* { dg-warning "attempt to free a non-heap object" } */
+ free (&d); /* { dg-warning "attempt to free a non-heap object" } */
+ free (buf4); /* { dg-warning "attempt to free a non-heap object" } */
+ free (&e); /* { dg-warning "attempt to free a non-heap object" } */
+ free (&r->a);
+ free ("abcd"); /* { dg-warning "attempt to free a non-heap object" } */
+ free (L"abcd"); /* { dg-warning "attempt to free a non-heap object" } */
+}
--- gcc/testsuite/gcc.dg/free-2.c.jj 2008-07-30 15:30:37.000000000 +0200
+++ gcc/testsuite/gcc.dg/free-2.c 2008-07-30 15:36:58.000000000 +0200
@@ -0,0 +1,26 @@
+/* PR c/36970 */
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+extern void free (void *);
+
+char *p, buf3[10], d;
+struct S { char a; int b; } *r;
+
+void foo (void)
+{
+ char buf[10], buf2[10], c;
+ static char buf4[10], e;
+ char *q = buf;
+ free (p);
+ free (q); /* At -O0 no warning is reported here. */
+ free (buf2); /* { dg-warning "attempt to free a non-heap object" } */
+ free (&c); /* { dg-warning "attempt to free a non-heap object" } */
+ free (buf3); /* { dg-warning "attempt to free a non-heap object" } */
+ free (&d); /* { dg-warning "attempt to free a non-heap object" } */
+ free (buf4); /* { dg-warning "attempt to free a non-heap object" } */
+ free (&e); /* { dg-warning "attempt to free a non-heap object" } */
+ free (&r->a);
+ free ("abcd"); /* { dg-warning "attempt to free a non-heap object" } */
+ free (L"abcd"); /* { dg-warning "attempt to free a non-heap object" } */
+}
Jakub