This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Warn about compile-time detected freeing of automatic/static variables (PR c/36970)


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]