extend.texi (alloc_size): New attribute.

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.

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


Co-Authored-By: Marcus Meissner <meissner@suse.de>

From-SVN: r125073
This commit is contained in:
Dirk Mueller 2007-05-25 21:18:15 +00:00 committed by Dirk Mueller
parent 1094da913b
commit 51bc54a661
6 changed files with 150 additions and 28 deletions

View 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

View 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. */

View 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.

View 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>

View File

@ -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" } */
}

View 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);