OSDN Git Service

2007-05-25 Dirk Mueller <dmueller@suse.de>
authormueller <mueller@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 25 May 2007 21:18:15 +0000 (21:18 +0000)
committermueller <mueller@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 25 May 2007 21:18:15 +0000 (21:18 +0000)
            Marcus Meissner <meissner@suse.de>

        * doc/extend.texi (alloc_size): New attribute.
        * c-common.c (handle_alloc_size_attribute): New.
        * tree-object-size.c (alloc_object_size): Use alloc_size
        attribute, if available.

        * testsuite/gcc.dg/attr-alloc_size.c: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@125073 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-common.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/attr-alloc_size.c [new file with mode: 0644]
gcc/tree-object-size.c

index 1a22b1a..b659e78 100644 (file)
@@ -1,3 +1,11 @@
+2007-05-25  Dirk Mueller  <dmueller@suse.de>
+           Marcus Meissner <meissner@suse.de>
+
+       * doc/extend.texi (alloc_size): New attribute.
+       * c-common.c (handle_alloc_size_attribute): New.
+       * tree-object-size.c (alloc_object_size): Use alloc_size
+       attribute, if available.
+
 2007-05-25  H.J. Lu  <hongjiu.lu@intel.com>
 
        * config/i386/i386.c (__builtin_ia32_vec_ext_v2df): Mark it
index 48dcd5d..2edf807 100644 (file)
@@ -556,6 +556,7 @@ static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
                                                 bool *);
 static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
+static tree handle_alloc_size_attribute (tree *, tree, tree, int, bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
@@ -650,6 +651,8 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_warn_unused_result_attribute },
   { "sentinel",               0, 1, false, true, true,
                              handle_sentinel_attribute },
+  { "alloc_size",            1, 2, false, true, true,
+                             handle_alloc_size_attribute },
   { "cold",                   0, 0, true,  false, false,
                              handle_cold_attribute },
   { "hot",                    0, 0, true,  false, false,
@@ -5579,6 +5582,37 @@ handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
+/* Handle a "alloc_size" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_alloc_size_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+                            int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree params = TYPE_ARG_TYPES (*node);
+  unsigned arg_count = 0;
+
+  for (; TREE_CHAIN (params); params = TREE_CHAIN (params))
+    arg_count ++;
+
+  for (; args; args = TREE_CHAIN (args))
+    {
+      tree position = TREE_VALUE (args);
+
+      if (TREE_CODE (position) != INTEGER_CST
+         || TREE_INT_CST_HIGH (position) 
+         || TREE_INT_CST_LOW (position) < 1
+         || TREE_INT_CST_LOW (position) > arg_count )
+       {
+         warning (OPT_Wattributes, 
+                  "alloc_size parameter outside range");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+    }
+  return NULL_TREE;
+}
+
 /* Handle a "returns_twice" attribute; arguments as in
    struct attribute_spec.handler.  */
 
index a09e453..5ebee3d 100644 (file)
@@ -1572,13 +1572,14 @@ The keyword @code{__attribute__} allows you to specify special
 attributes when making a declaration.  This keyword is followed by an
 attribute specification inside double parentheses.  The following
 attributes are currently defined for functions on all targets:
-@code{noreturn}, @code{returns_twice}, @code{noinline}, @code{always_inline},
-@code{flatten}, @code{pure}, @code{const}, @code{nothrow}, @code{sentinel},
-@code{format}, @code{format_arg}, @code{no_instrument_function},
-@code{section}, @code{constructor}, @code{destructor}, @code{used},
-@code{unused}, @code{deprecated}, @code{weak}, @code{malloc},
-@code{alias}, @code{warn_unused_result}, @code{nonnull},
-@code{gnu_inline} and @code{externally_visible}, @code{hot}, @code{cold}.
+@code{alloc_size}, @code{noreturn}, @code{returns_twice}, @code{noinline},
+@code{always_inline}, @code{flatten}, @code{pure}, @code{const},
+@code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg},
+@code{no_instrument_function}, @code{section}, @code{constructor},
+@code{destructor}, @code{used}, @code{unused}, @code{deprecated},
+@code{weak}, @code{malloc}, @code{alias}, @code{warn_unused_result},
+@code{nonnull}, @code{gnu_inline} and @code{externally_visible},
+@code{hot}, @code{cold}.
 Several other attributes are defined for functions on particular target
 systems.  Other attributes, including @code{section} are supported for
 variables declarations (@pxref{Variable Attributes}) and for types (@pxref{Type
@@ -1611,6 +1612,30 @@ is not defined in the same translation unit.
 
 Not all target machines support this attribute.
 
+@item alloc_size
+@cindex @code{alloc_size} attribute
+The @code{alloc_size} attribute is used to tell the compiler that the
+function return value points to memory, where the size is given by
+one or two of the functions parameters.  GCC uses this 
+information to improve the correctness of @code{__builtin_object_size}.
+
+The function parameter(s) denoting the allocated size are specified by
+one or two integer arguments supplied to the attribute.  The allocated size
+is either the value of the single function argument specified or the product
+of the two function arguments specified.  Argument numbering starts at
+one.
+
+For instance, 
+
+@smallexample
+void* my_calloc(size_t, size_t) __attribute__((alloc_size(1,2)))
+void my_realloc(void* size_t) __attribute__((alloc_size(2)))
+@end smallexample
+
+declares that my_calloc will return memory of the size given by
+the product of parameter 1 and 2 and that my_realloc will return memory
+of the size given by parameter 2.
+
 @item always_inline
 @cindex @code{always_inline} function attribute
 Generally, functions are not inlined unless optimization is specified.
index 0da350c..ed0ee7f 100644 (file)
@@ -1,3 +1,8 @@
+2007-05-25  Dirk Mueller  <dmueller@suse.de>
+           Marcus Meissner <meissner@suse.de>
+
+       * testsuite/gcc.dg/attr-alloc_size.c: New.
+
 2007-05-25  Simon Martin  <simartin@users.sourceforge.net>
            Lee Millward  <lee.millward@gmail.com>
 
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size.c b/gcc/testsuite/gcc.dg/attr-alloc_size.c
new file mode 100644 (file)
index 0000000..e646e5e
--- /dev/null
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wall" } */
+
+extern void abort (void);
+
+#include "../gcc.c-torture/execute/builtins/chk.h"
+
+extern char *mallocminus1(int size) __attribute__((alloc_size(-1))); /* { dg-warning "parameter outside range" } */
+extern char *malloc0(int size) __attribute__((alloc_size(0))); /* { dg-warning "parameter outside range" } */
+extern char *malloc1(int size) __attribute__((alloc_size(1)));
+extern char *malloc2(int empty, int size) __attribute__((alloc_size(2)));
+extern char *calloc1(int size, int elements) __attribute__((alloc_size(1,2)));
+extern char *calloc2(int size, int empty, int elements) __attribute__((alloc_size(1,3)));
+extern char *balloc1(void *size) __attribute__((alloc_size(1)));
+
+void
+test (void)
+{
+  char *p;
+
+  p = malloc0 (6);
+  strcpy (p, "Hello");
+  p = malloc1 (6);
+  strcpy (p, "Hello");
+  strcpy (p, "Hello World"); /* { dg-warning "will always overflow" "strcpy" } */
+  p = malloc2 (424242, 6);
+  strcpy (p, "World");
+  strcpy (p, "Hello World"); /* { dg-warning "will always overflow" "strcpy" } */
+  p = calloc1 (2, 5);
+  strcpy (p, "World");
+  strcpy (p, "Hello World"); /* { dg-warning "will always overflow" "strcpy" } */
+  p = calloc2 (2, 424242, 5);
+  strcpy (p, "World");
+  strcpy (p, "Hello World"); /* { dg-warning "will always overflow" "strcpy" } */
+}
+
index 1eb09cb..fee75a8 100644 (file)
@@ -24,6 +24,7 @@ Boston, MA 02110-1301, USA.  */
 #include "coretypes.h"
 #include "tm.h"
 #include "tree.h"
+#include "toplev.h"
 #include "diagnostic.h"
 #include "tree-flow.h"
 #include "tree-pass.h"
@@ -229,39 +230,52 @@ static unsigned HOST_WIDE_INT
 alloc_object_size (tree call, int object_size_type)
 {
   tree callee, bytes = NULL_TREE;
+  tree alloc_size;
+  int arg1 = -1, arg2 = -1;
 
   gcc_assert (TREE_CODE (call) == CALL_EXPR);
 
   callee = get_callee_fndecl (call);
-  if (callee
-      && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+  if (!callee)
+    return unknown[object_size_type];
+
+  alloc_size = lookup_attribute ("alloc_size", TYPE_ATTRIBUTES (TREE_TYPE(callee)));
+  if (alloc_size && TREE_VALUE (alloc_size))
+    {
+      tree p = TREE_VALUE (alloc_size);
+
+      arg1 = TREE_INT_CST_LOW (TREE_VALUE (p))-1;
+      if (TREE_CHAIN (p))
+         arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1;
+    }
+  if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
     switch (DECL_FUNCTION_CODE (callee))
       {
+      case BUILT_IN_CALLOC:
+       arg2 = 1;
+       /* fall through */
       case BUILT_IN_MALLOC:
       case BUILT_IN_ALLOCA:
-       if (call_expr_nargs (call) == 1
-           && TREE_CODE (CALL_EXPR_ARG (call, 0)) == INTEGER_CST)
-         bytes = fold_convert (sizetype, CALL_EXPR_ARG (call, 0));
-       break;
-      /*
-      case BUILT_IN_REALLOC:
-       if (call_expr_nargs (call) == 2
-           && TREE_CODE (CALL_EXPR_ARG (call, 1)) == INTEGER_CST)
-         bytes = fold_convert (sizetype, CALL_EXPR_ARG (call, 1));
-       break;
-       */
-      case BUILT_IN_CALLOC:
-       if (call_expr_nargs (call) == 2
-           && TREE_CODE (CALL_EXPR_ARG (call, 0)) == INTEGER_CST
-           && TREE_CODE (CALL_EXPR_ARG (call, 1)) == INTEGER_CST)
-         bytes = size_binop (MULT_EXPR,
-                             fold_convert (sizetype, CALL_EXPR_ARG (call, 0)),
-                             fold_convert (sizetype, CALL_EXPR_ARG (call, 1)));
-       break;
+       arg1 = 0;
       default:
        break;
       }
 
+  if (arg1 < 0 || arg1 >= call_expr_nargs (call)
+      || TREE_CODE (CALL_EXPR_ARG (call, arg1)) != INTEGER_CST
+      || (arg2 >= 0 
+         && (arg2 >= call_expr_nargs (call)
+             || TREE_CODE (CALL_EXPR_ARG (call, arg2)) != INTEGER_CST)))
+    return unknown[object_size_type];    
+
+  if (arg2 >= 0)
+    bytes = size_binop (MULT_EXPR,
+       fold_convert (sizetype, CALL_EXPR_ARG (call, arg1)),
+       fold_convert (sizetype, CALL_EXPR_ARG (call, arg2)));
+  else if (arg1 >= 0)
+    bytes = fold_convert (sizetype, CALL_EXPR_ARG (call, arg1));
+
   if (bytes && host_integerp (bytes, 1))
     return tree_low_cst (bytes, 1);