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:
parent
1094da913b
commit
51bc54a661
|
@ -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>
|
2007-05-25 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
* config/i386/i386.c (__builtin_ia32_vec_ext_v2df): Mark it
|
* config/i386/i386.c (__builtin_ia32_vec_ext_v2df): Mark it
|
||||||
|
|
|
@ -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,
|
static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
|
||||||
bool *);
|
bool *);
|
||||||
static tree handle_sentinel_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_function_nonnull (tree, int, tree *);
|
||||||
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
|
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 },
|
handle_warn_unused_result_attribute },
|
||||||
{ "sentinel", 0, 1, false, true, true,
|
{ "sentinel", 0, 1, false, true, true,
|
||||||
handle_sentinel_attribute },
|
handle_sentinel_attribute },
|
||||||
|
{ "alloc_size", 1, 2, false, true, true,
|
||||||
|
handle_alloc_size_attribute },
|
||||||
{ "cold", 0, 0, true, false, false,
|
{ "cold", 0, 0, true, false, false,
|
||||||
handle_cold_attribute },
|
handle_cold_attribute },
|
||||||
{ "hot", 0, 0, true, false, false,
|
{ "hot", 0, 0, true, false, false,
|
||||||
|
@ -5579,6 +5582,37 @@ handle_malloc_attribute (tree *node, tree name, tree ARG_UNUSED (args),
|
||||||
return NULL_TREE;
|
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
|
/* Handle a "returns_twice" attribute; arguments as in
|
||||||
struct attribute_spec.handler. */
|
struct attribute_spec.handler. */
|
||||||
|
|
||||||
|
|
|
@ -1572,13 +1572,14 @@ The keyword @code{__attribute__} allows you to specify special
|
||||||
attributes when making a declaration. This keyword is followed by an
|
attributes when making a declaration. This keyword is followed by an
|
||||||
attribute specification inside double parentheses. The following
|
attribute specification inside double parentheses. The following
|
||||||
attributes are currently defined for functions on all targets:
|
attributes are currently defined for functions on all targets:
|
||||||
@code{noreturn}, @code{returns_twice}, @code{noinline}, @code{always_inline},
|
@code{alloc_size}, @code{noreturn}, @code{returns_twice}, @code{noinline},
|
||||||
@code{flatten}, @code{pure}, @code{const}, @code{nothrow}, @code{sentinel},
|
@code{always_inline}, @code{flatten}, @code{pure}, @code{const},
|
||||||
@code{format}, @code{format_arg}, @code{no_instrument_function},
|
@code{nothrow}, @code{sentinel}, @code{format}, @code{format_arg},
|
||||||
@code{section}, @code{constructor}, @code{destructor}, @code{used},
|
@code{no_instrument_function}, @code{section}, @code{constructor},
|
||||||
@code{unused}, @code{deprecated}, @code{weak}, @code{malloc},
|
@code{destructor}, @code{used}, @code{unused}, @code{deprecated},
|
||||||
@code{alias}, @code{warn_unused_result}, @code{nonnull},
|
@code{weak}, @code{malloc}, @code{alias}, @code{warn_unused_result},
|
||||||
@code{gnu_inline} and @code{externally_visible}, @code{hot}, @code{cold}.
|
@code{nonnull}, @code{gnu_inline} and @code{externally_visible},
|
||||||
|
@code{hot}, @code{cold}.
|
||||||
Several other attributes are defined for functions on particular target
|
Several other attributes are defined for functions on particular target
|
||||||
systems. Other attributes, including @code{section} are supported for
|
systems. Other attributes, including @code{section} are supported for
|
||||||
variables declarations (@pxref{Variable Attributes}) and for types (@pxref{Type
|
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.
|
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
|
@item always_inline
|
||||||
@cindex @code{always_inline} function attribute
|
@cindex @code{always_inline} function attribute
|
||||||
Generally, functions are not inlined unless optimization is specified.
|
Generally, functions are not inlined unless optimization is specified.
|
||||||
|
|
|
@ -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>
|
2007-05-25 Simon Martin <simartin@users.sourceforge.net>
|
||||||
Lee Millward <lee.millward@gmail.com>
|
Lee Millward <lee.millward@gmail.com>
|
||||||
|
|
||||||
|
|
|
@ -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" } */
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ Boston, MA 02110-1301, USA. */
|
||||||
#include "coretypes.h"
|
#include "coretypes.h"
|
||||||
#include "tm.h"
|
#include "tm.h"
|
||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
#include "toplev.h"
|
||||||
#include "diagnostic.h"
|
#include "diagnostic.h"
|
||||||
#include "tree-flow.h"
|
#include "tree-flow.h"
|
||||||
#include "tree-pass.h"
|
#include "tree-pass.h"
|
||||||
|
@ -229,39 +230,52 @@ static unsigned HOST_WIDE_INT
|
||||||
alloc_object_size (tree call, int object_size_type)
|
alloc_object_size (tree call, int object_size_type)
|
||||||
{
|
{
|
||||||
tree callee, bytes = NULL_TREE;
|
tree callee, bytes = NULL_TREE;
|
||||||
|
tree alloc_size;
|
||||||
|
int arg1 = -1, arg2 = -1;
|
||||||
|
|
||||||
gcc_assert (TREE_CODE (call) == CALL_EXPR);
|
gcc_assert (TREE_CODE (call) == CALL_EXPR);
|
||||||
|
|
||||||
callee = get_callee_fndecl (call);
|
callee = get_callee_fndecl (call);
|
||||||
if (callee
|
if (!callee)
|
||||||
&& DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
|
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))
|
switch (DECL_FUNCTION_CODE (callee))
|
||||||
{
|
{
|
||||||
|
case BUILT_IN_CALLOC:
|
||||||
|
arg2 = 1;
|
||||||
|
/* fall through */
|
||||||
case BUILT_IN_MALLOC:
|
case BUILT_IN_MALLOC:
|
||||||
case BUILT_IN_ALLOCA:
|
case BUILT_IN_ALLOCA:
|
||||||
if (call_expr_nargs (call) == 1
|
arg1 = 0;
|
||||||
&& 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;
|
|
||||||
default:
|
default:
|
||||||
break;
|
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))
|
if (bytes && host_integerp (bytes, 1))
|
||||||
return tree_low_cst (bytes, 1);
|
return tree_low_cst (bytes, 1);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue