PR tree-optimization/71831 - __builtin_object_size poor results with no

PR tree-optimization/71831 - __builtin_object_size poor results with no
	optimization

gcc/testsuite/ChangeLog:

	PR tree-optimization/71831
	* gcc.dg/builtin-object-size-16.c: New test.
	* gcc.dg/builtin-object-size-17.c: New test.

gcc/ChangeLog:

	PR tree-optimization/71831
	* tree-object-size.h: Return bool instead of the size and add
	argument for the size.
	* tree-object-size.c (compute_object_offset): Update signature.
	(addr_object_size): Same.
	(compute_builtin_object_size): Return bool instead of the size
	and add argument for the size.  Handle POINTER_PLUS_EXPR when
	optimization is disabled.
	(expr_object_size): Adjust.
	(plus_stmt_object_size): Adjust.
	(pass_object_sizes::execute): Adjust.
	* builtins.c (fold_builtin_object_size): Adjust.
	* doc/extend.texi (Object Size Checking): Update.
	* ubsan.c (instrument_object_size): Adjust.

From-SVN: r239953
This commit is contained in:
Martin Sebor 2016-09-02 02:14:50 +00:00 committed by Martin Sebor
parent 910f2f3d8a
commit 05a647564a
9 changed files with 572 additions and 143 deletions

View file

@ -1,3 +1,20 @@
2016-09-01 Martin Sebor <msebor@redhat.com>
PR tree-optimization/71831
* tree-object-size.h: Return bool instead of the size and add
argument for the size.
* tree-object-size.c (compute_object_offset): Update signature.
(addr_object_size): Same.
(compute_builtin_object_size): Return bool instead of the size
and add argument for the size. Handle POINTER_PLUS_EXPR when
optimization is disabled.
(expr_object_size): Adjust.
(plus_stmt_object_size): Adjust.
(pass_object_sizes::execute): Adjust.
* builtins.c (fold_builtin_object_size): Adjust.
* doc/extend.texi (Object Size Checking): Update.
* ubsan.c (instrument_object_size): Adjust.
2016-09-01 Martin Sebor <msebor@redhat.com>
* genmatch.c (parser::parse_expr): Increase buffer size to guarantee

View file

@ -9615,7 +9615,7 @@ fold_builtin_object_size (tree ptr, tree ost)
if (TREE_CODE (ptr) == ADDR_EXPR)
{
bytes = compute_builtin_object_size (ptr, object_size_type);
compute_builtin_object_size (ptr, object_size_type, &bytes);
if (wi::fits_to_tree_p (bytes, size_type_node))
return build_int_cstu (size_type_node, bytes);
}
@ -9624,9 +9624,8 @@ fold_builtin_object_size (tree ptr, tree ost)
/* If object size is not known yet, delay folding until
later. Maybe subsequent passes will help determining
it. */
bytes = compute_builtin_object_size (ptr, object_size_type);
if (bytes != (unsigned HOST_WIDE_INT) (object_size_type < 2 ? -1 : 0)
&& wi::fits_to_tree_p (bytes, size_type_node))
if (compute_builtin_object_size (ptr, object_size_type, &bytes)
&& wi::fits_to_tree_p (bytes, size_type_node))
return build_int_cstu (size_type_node, bytes);
}

View file

@ -10030,8 +10030,15 @@ __atomic_store_n(&lockvar, 0, __ATOMIC_RELEASE|__ATOMIC_HLE_RELEASE);
@findex __builtin___fprintf_chk
@findex __builtin___vfprintf_chk
GCC implements a limited buffer overflow protection mechanism
that can prevent some buffer overflow attacks.
GCC implements a limited buffer overflow protection mechanism that can
prevent some buffer overflow attacks by determining the sizes of objects
into which data is about to be written and preventing the writes when
the size isn't sufficient. The built-in functions described below yield
the best results when used together and when optimization is enabled.
For example, to detect object sizes across function boundaries or to
follow pointer assignments through non-trivial control flow they rely
on various optimization passes enabled with @option{-O2}. However, to
a limited extent, they can be used without optimization as well.
@deftypefn {Built-in Function} {size_t} __builtin_object_size (void * @var{ptr}, int @var{type})
is a built-in construct that returns a constant number of bytes from

View file

@ -1,3 +1,9 @@
2016-09-01 Martin Sebor <msebor@redhat.com>
PR tree-optimization/71831
* gcc.dg/builtin-object-size-16.c: New test.
* gcc.dg/builtin-object-size-17.c: New test.
2016-09-01 Jerry DeLisle <jvdelisle@gcc.gnu.org>
PR libgfortran/77393

View file

@ -0,0 +1,201 @@
/* PR 71831 - __builtin_object_size poor results with no optimization
Verify that even without optimization __builtin_object_size returns
a meaningful result for a subset of simple expressins. In cases
where the result could not easily be made to match the one obtained
with optimization the built-in was made to fail instead. */
/* { dg-do run } */
/* { dg-options "-O0" } */
static int nfails;
#define TEST_FAILURE(line, obj, type, expect, result) \
__builtin_printf ("FAIL: line %i: __builtin_object_size(" \
#obj ", %i) == %zu, got %zu\n", \
line, type, expect, result), ++nfails
#define bos(obj, type) __builtin_object_size (obj, type)
#define size(obj, n) ((size_t)n == X ? sizeof *obj : (size_t)n)
#define test(expect, type, obj) \
do { \
if (bos (obj, type) != size (obj, expect)) \
TEST_FAILURE (__LINE__, obj, type, size (obj, expect), bos (obj, type)); \
} while (0)
#define T(r0, r1, r2, r3, obj) \
do { \
test (r0, 0, obj); \
test (r1, 1, obj); \
test (r2, 2, obj); \
test (r3, 3, obj); \
} while (0)
/* For convenience. Substitute for 'sizeof object' in test cases where
the size can vary from target to target. */
#define X (size_t)0xdeadbeef
/* __builtin_object_size checking results are inconsistent for equivalent
expressions (see bug 71831). To avoid having duplicate the inconsistency
at -O0 the built-in simply fails. The results hardcoded in this test
are those obtained with optimization (for easy comparison) but without
optimization the macros below turn them into expected failures . */
#if __OPTIMIZE__
# define F0(n) n
# define F1(n) n
# define F2(n) n
# define F3(n) n
#else
# define F0(n) -1
# define F1(n) -1
# define F2(n) 0
# define F3(n) 0
#endif
typedef __SIZE_TYPE__ size_t;
extern char ax[];
char ax2[]; /* { dg-warning "assumed to have one element" } */
extern char a0[0];
static char a1[1];
static char a2[2];
static char a9[9];
#if __SIZEOF_SHORT__ == 4
extern short ia0[0];
static short ia1[1];
static short ia9[9];
#elif __SIZEOF_INT__ == 4
extern int ia0[0];
static int ia1[1];
static int ia9[9];
#endif
static char a2x2[2][2];
static char a3x5[3][5];
struct Sx { char n, a[]; } sx;
struct S0 { char n, a[0]; } s0;
struct S1 { char n, a[1]; } s1;
struct S2 { char n, a[2]; } s2;
struct S9 { char n, a[9]; } s9;
struct S2x2 { char n, a[2][2]; } s2x2;
struct S3x5 { char n, a[3][5]; } s3x5;
static __attribute__ ((noclone, noinline)) void
test_arrays ()
{
T ( -1, -1, 0, 0, ax);
T ( 0, 0, 0, 0, a0);
T ( 1, 1, 1, 1, ax2);
T ( 1, 1, 1, 1, a1);
T ( 2, 2, 2, 2, a2);
T ( 9, 9, 9, 9, a9);
T ( 0, 0, 0, 0, a0);
T ( 1, 1, 1, 1, ax2);
T ( 0, 0, 0, 0, ia0);
T ( 4, 4, 4, 4, ia1);
T ( 36, 36, 36, 36, ia9);
/* Not all results for multidimensional arrays make sense (see
bug 77293). The expected results below simply reflect those
obtained at -O2 (modulo the known limitations at -O1). */
T ( 4, 4, 4, 4, a2x2);
T ( 4, 4, 4, 4, &a2x2[0]);
T ( 4, 2, 4, 2, &a2x2[0][0]);
T ( 0, F1 (0), 0, 0, &a2x2 + 1);
T ( 2, F1 ( 2), 2, F3 ( 2), &a2x2[0] + 1);
T ( 3, F1 ( 1), 3, F3 ( 3), &a2x2[0][0] + 1);
T ( 15, 15, 15, 15, a3x5);
T ( 15, 5, 15, 5, &a3x5[0][0] + 0);
T ( 14, F1 ( 4), 14, F3 (14), &a3x5[0][0] + 1);
T ( 1, 1, 1, 1, a1 + 0);
T ( 0, F1 (0), 0, 0, a1 + 1);
T ( 0, F1 ( 0), 0, 0, &a1 + 1);
/* In the following the offset is out of bounds which makes
the expression undefined. Still, verify that the returned
size is zero (and not some large number). */
T ( 0, F1 (0), 0, 0, a1 + 2);
T ( 2, 2, 2, 2, a2 + 0);
T ( 1, F1 ( 1), 1, F3 ( 1), a2 + 1);
T ( 0, F1 ( 0), 0, 0, a2 + 2);
}
static __attribute__ ((noclone, noinline)) void
test_structs (struct Sx *psx, struct S0 *ps0, struct S1 *ps1, struct S9 *ps9)
{
/* The expected size of a declared object with a flexible array member
is sizeof sx in all __builtin_object_size types. */
T ( X, X, X, X, &sx);
/* The expected size of an unknown object with a flexible array member
is unknown in all __builtin_object_size types. */
T ( -1, -1, 0, 0, psx);
/* The expected size of a flexible array member of a declared object
is zero. */
T ( 0, 0, 0, 0, sx.a);
/* The expected size of a flexible array member of an unknown object
is unknown. */
T ( -1, -1, 0, 0, psx->a);
/* The expected size of a declared object with a zero-length array member
is sizeof sx in all __builtin_object_size types. */
T ( X, X, X, X, &s0);
/* The expected size of an unknown object with a zero-length array member
is unknown in all __builtin_object_size types. */
T ( -1, -1, 0, 0, ps0);
/* The expected size of a zero-length array member of a declared object
is zero. */
T ( 0, 0, 0, 0, s0.a);
/* The expected size of a zero-length array member of an unknown object
is unknown. */
T ( -1, -1, 0, 0, ps0->a);
T ( X, X, X, X, &s1);
T ( 1, 1, 1, 1, s1.a);
T ( 0, F1 (0), 0, 0, s1.a + 1);
/* GCC treats arrays of all sizes that are the last member of a struct
as flexible array members. */
T ( -1, -1, 0, 0, ps1);
T ( -1, -1, 0, 0, ps1->a);
T ( -1, -1, 0, 0, ps1->a + 1);
T ( X, X, X, X, &s9);
T ( 9, 9, 9, 9, s9.a);
T ( 9, 9, 9, 9, s9.a + 0);
T ( 8, F1 ( 8), 8, F3 ( 8), s9.a + 1);
T ( 7, F1 ( 7), 7, F3 ( 7), s9.a + 2);
T ( 0, F1 ( 0), 0, F3 ( 0), s9.a + 9);
/* The following make little sense but see bug 77301. */
T ( -1, -1, 0, 0, ps9);
T ( -1, -1, 0, 0, ps9->a);
T ( -1, -1, 0, 0, ps9->a + 1);
}
int
main()
{
test_arrays ();
test_structs (&sx, &s0, &s1, &s9);
if (nfails)
__builtin_abort ();
return 0;
}

View file

@ -0,0 +1,158 @@
/* PR 71831 - __builtin_object_size poor results with no optimization
Verify that even without optimization __builtin_object_size result
is folded into a constant and dead code that depends on it is
eliminated. */
/* { dg-do compile } */
/* { dg-options "-O0 -fdump-tree-ssa" } */
#define concat(a, b) a ## b
#define CAT(a, b) concat (a, b)
/* Create a symbol name unique to each tes and object size type. */
#define SYM(type) CAT (CAT (CAT (failure_on_line_, __LINE__), _type_), type)
/* References to the following undefined symbol which is unique for each
test case are expected to be eliminated. */
#define TEST_FAILURE(type) \
do { \
extern void SYM (type)(void); \
SYM (type)(); \
} while (0)
#define bos(obj, type) __builtin_object_size (obj, type)
#define size(obj, n) ((size_t)n == X ? sizeof *obj : (size_t)n)
#define test(expect, type, obj) \
do { \
if (bos (obj, type) != size (obj, expect)) \
TEST_FAILURE (type); \
} while (0)
#define FOLD_ALL(r0, r1, r2, r3, obj) \
do { \
test (r0, 0, obj); \
test (r1, 1, obj); \
test (r2, 2, obj); \
test (r3, 3, obj); \
} while (0)
#define FOLD_0_2(r0, r1, r2, r3, obj) \
do { \
test (r0, 0, obj); \
test (r2, 2, obj); \
} while (0)
/* For convenience. Substitute for 'sizeof object' in test cases where
the size can vary from target to target. */
#define X (size_t)0xdeadbeef
typedef __SIZE_TYPE__ size_t;
extern char ax[];
char ax2[]; /* { dg-warning "assumed to have one element" } */
extern char a0[0];
static char a1[1];
static char a2[2];
static char a9[9];
#if __SIZEOF_SHORT__ == 4
extern short ia0[0];
static short ia1[1];
static short ia9[9];
#elif __SIZEOF_INT__ == 4
extern int ia0[0];
static int ia1[1];
static int ia9[9];
#endif
static char a2x2[2][2];
static char a3x5[3][5];
struct Sx { char n, a[]; } sx;
struct S0 { char n, a[0]; } s0;
struct S1 { char n, a[1]; } s1;
struct S2 { char n, a[2]; } s2;
struct S9 { char n, a[9]; } s9;
struct S2x2 { char n, a[2][2]; } s2x2;
struct S3x5 { char n, a[3][5]; } s3x5;
static __attribute__ ((noclone, noinline)) void
test_arrays ()
{
FOLD_ALL ( 1, 1, 1, 1, ax2);
FOLD_ALL ( 1, 1, 1, 1, a1);
FOLD_ALL ( 2, 2, 2, 2, a2);
FOLD_ALL ( 9, 9, 9, 9, a9);
FOLD_ALL ( 0, 0, 0, 0, a0);
FOLD_ALL ( 1, 1, 1, 1, ax2);
FOLD_ALL ( 0, 0, 0, 0, ia0);
FOLD_ALL ( 4, 4, 4, 4, ia1);
FOLD_ALL ( 36, 36, 36, 36, ia9);
/* Not all results for multidimensional arrays make sense (see
bug 77293). The expected results below simply reflect those
obtained at -O2 (modulo the known limitations at -O1). */
FOLD_ALL ( 4, 4, 4, 4, a2x2);
FOLD_ALL ( 4, 4, 4, 4, &a2x2[0]);
FOLD_ALL ( 4, 2, 4, 2, &a2x2[0][0]);
FOLD_0_2 ( 0, F1 (0), 0, 0, &a2x2 + 1);
FOLD_0_2 ( 2, F1 ( 2), 2, F3 ( 2), &a2x2[0] + 1);
FOLD_0_2 ( 3, F1 ( 1), 3, F3 ( 3), &a2x2[0][0] + 1);
FOLD_ALL ( 15, 15, 15, 15, a3x5);
FOLD_ALL ( 15, 5, 15, 5, &a3x5[0][0] + 0);
FOLD_0_2 ( 14, F1 ( 4), 14, F3 (14), &a3x5[0][0] + 1);
FOLD_ALL ( 1, 1, 1, 1, a1 + 0);
FOLD_0_2 ( 0, F1 ( 0), 0, 0, &a1 + 1);
FOLD_ALL ( 2, 2, 2, 2, a2 + 0);
FOLD_0_2 ( 1, F1 ( 1), 1, F3 ( 1), a2 + 1);
FOLD_0_2 ( 0, F1 ( 0), 0, 0, a2 + 2);
}
static __attribute__ ((noclone, noinline)) void
test_structs (void)
{
/* The expected size of a declared object with a flexible array member
is sizeof sx in all __builtin_object_size types. */
FOLD_ALL ( X, X, X, X, &sx);
/* The expected size of a flexible array member of a declared object
is zero. */
FOLD_ALL ( 0, 0, 0, 0, sx.a);
/* The expected size of a declared object with a zero-length array member
is sizeof sx in all __builtin_object_size types. */
FOLD_ALL ( X, X, X, X, &s0);
/* The expected size of a zero-length array member of a declared object
is zero. */
FOLD_ALL ( 0, 0, 0, 0, s0.a);
FOLD_ALL ( X, X, X, X, &s1);
FOLD_ALL ( 1, 1, 1, 1, s1.a);
FOLD_0_2 ( 0, F1 (0), 0, 0, s1.a + 1);
FOLD_ALL ( X, X, X, X, &s9);
FOLD_ALL ( 9, 9, 9, 9, s9.a);
FOLD_ALL ( 9, 9, 9, 9, s9.a + 0);
FOLD_0_2 ( 8, F1 ( 8), 8, F3 ( 8), s9.a + 1);
FOLD_0_2 ( 7, F1 ( 7), 7, F3 ( 7), s9.a + 2);
FOLD_0_2 ( 0, F1 ( 0), 0, F3 ( 0), s9.a + 9);
}
int
main()
{
test_arrays ();
test_structs ();
return 0;
}
/* { dg-final { scan-tree-dump-not "failure_on_line" "ssa" } } */

View file

@ -51,8 +51,8 @@ static const unsigned HOST_WIDE_INT unknown[4] = {
};
static tree compute_object_offset (const_tree, const_tree);
static unsigned HOST_WIDE_INT addr_object_size (struct object_size_info *,
const_tree, int);
static bool addr_object_size (struct object_size_info *,
const_tree, int, unsigned HOST_WIDE_INT *);
static unsigned HOST_WIDE_INT alloc_object_size (const gcall *, int);
static tree pass_through_call (const gcall *);
static void collect_object_sizes_for (struct object_size_info *, tree);
@ -163,14 +163,18 @@ compute_object_offset (const_tree expr, const_tree var)
OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
If unknown, return unknown[object_size_type]. */
static unsigned HOST_WIDE_INT
static bool
addr_object_size (struct object_size_info *osi, const_tree ptr,
int object_size_type)
int object_size_type, unsigned HOST_WIDE_INT *psize)
{
tree pt_var, pt_var_size = NULL_TREE, var_size, bytes;
gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
/* Set to unknown and overwrite just before returning if the size
could be determined. */
*psize = unknown[object_size_type];
pt_var = TREE_OPERAND (ptr, 0);
while (handled_component_p (pt_var))
pt_var = TREE_OPERAND (pt_var, 0);
@ -183,8 +187,8 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
if (!osi || (object_size_type & 1) != 0
|| TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME)
{
sz = compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
object_size_type & ~1);
compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
object_size_type & ~1, &sz);
}
else
{
@ -224,7 +228,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
< offset_limit)
pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
else
return unknown[object_size_type];
return false;
if (pt_var != TREE_OPERAND (ptr, 0))
{
@ -339,7 +343,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
if (var != pt_var)
var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
else if (!pt_var_size)
return unknown[object_size_type];
return false;
else
var_size = pt_var_size;
bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
@ -369,14 +373,17 @@ addr_object_size (struct object_size_info *osi, const_tree ptr,
}
}
else if (!pt_var_size)
return unknown[object_size_type];
return false;
else
bytes = pt_var_size;
if (tree_fits_uhwi_p (bytes))
return tree_to_uhwi (bytes);
{
*psize = tree_to_uhwi (bytes);
return true;
}
return unknown[object_size_type];
return false;
}
@ -484,142 +491,177 @@ pass_through_call (const gcall *call)
}
/* Compute __builtin_object_size value for PTR. OBJECT_SIZE_TYPE is the
second argument from __builtin_object_size. */
/* Compute __builtin_object_size value for PTR and set *PSIZE to
the resulting value. OBJECT_SIZE_TYPE is the second argument
to __builtin_object_size. Return true on success and false
when the object size could not be determined. */
unsigned HOST_WIDE_INT
compute_builtin_object_size (tree ptr, int object_size_type)
bool
compute_builtin_object_size (tree ptr, int object_size_type,
unsigned HOST_WIDE_INT *psize)
{
gcc_assert (object_size_type >= 0 && object_size_type <= 3);
/* Set to unknown and overwrite just before returning if the size
could be determined. */
*psize = unknown[object_size_type];
if (! offset_limit)
init_offset_limit ();
if (TREE_CODE (ptr) == ADDR_EXPR)
return addr_object_size (NULL, ptr, object_size_type);
return addr_object_size (NULL, ptr, object_size_type, psize);
if (TREE_CODE (ptr) == SSA_NAME
&& POINTER_TYPE_P (TREE_TYPE (ptr))
&& computed[object_size_type] != NULL)
if (TREE_CODE (ptr) != SSA_NAME
|| !POINTER_TYPE_P (TREE_TYPE (ptr)))
return false;
if (computed[object_size_type] == NULL)
{
if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
if (optimize || object_size_type & 1)
return false;
/* When not optimizing, rather than failing, make a small effort
to determine the object size without the full benefit of
the (costly) computation below. */
gimple *def = SSA_NAME_DEF_STMT (ptr);
if (gimple_code (def) == GIMPLE_ASSIGN)
{
struct object_size_info osi;
bitmap_iterator bi;
unsigned int i;
if (num_ssa_names > object_sizes[object_size_type].length ())
object_sizes[object_size_type].safe_grow (num_ssa_names);
if (dump_file)
tree_code code = gimple_assign_rhs_code (def);
if (code == POINTER_PLUS_EXPR)
{
fprintf (dump_file, "Computing %s %sobject size for ",
(object_size_type & 2) ? "minimum" : "maximum",
(object_size_type & 1) ? "sub" : "");
print_generic_expr (dump_file, ptr, dump_flags);
fprintf (dump_file, ":\n");
}
tree offset = gimple_assign_rhs2 (def);
ptr = gimple_assign_rhs1 (def);
osi.visited = BITMAP_ALLOC (NULL);
osi.reexamine = BITMAP_ALLOC (NULL);
osi.object_size_type = object_size_type;
osi.depths = NULL;
osi.stack = NULL;
osi.tos = NULL;
/* First pass: walk UD chains, compute object sizes that
can be computed. osi.reexamine bitmap at the end will
contain what variables were found in dependency cycles
and therefore need to be reexamined. */
osi.pass = 0;
osi.changed = false;
collect_object_sizes_for (&osi, ptr);
/* Second pass: keep recomputing object sizes of variables
that need reexamination, until no object sizes are
increased or all object sizes are computed. */
if (! bitmap_empty_p (osi.reexamine))
{
bitmap reexamine = BITMAP_ALLOC (NULL);
/* If looking for minimum instead of maximum object size,
detect cases where a pointer is increased in a loop.
Although even without this detection pass 2 would eventually
terminate, it could take a long time. If a pointer is
increasing this way, we need to assume 0 object size.
E.g. p = &buf[0]; while (cond) p = p + 4; */
if (object_size_type & 2)
if (cst_and_fits_in_hwi (offset)
&& compute_builtin_object_size (ptr, object_size_type, psize))
{
osi.depths = XCNEWVEC (unsigned int, num_ssa_names);
osi.stack = XNEWVEC (unsigned int, num_ssa_names);
osi.tos = osi.stack;
osi.pass = 1;
/* collect_object_sizes_for is changing
osi.reexamine bitmap, so iterate over a copy. */
bitmap_copy (reexamine, osi.reexamine);
EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
if (bitmap_bit_p (osi.reexamine, i))
check_for_plus_in_loops (&osi, ssa_name (i));
free (osi.depths);
osi.depths = NULL;
free (osi.stack);
osi.stack = NULL;
osi.tos = NULL;
/* Return zero when the offset is out of bounds. */
unsigned HOST_WIDE_INT off = tree_to_shwi (offset);
*psize = off < *psize ? *psize - off : 0;
return true;
}
do
{
osi.pass = 2;
osi.changed = false;
/* collect_object_sizes_for is changing
osi.reexamine bitmap, so iterate over a copy. */
bitmap_copy (reexamine, osi.reexamine);
EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
if (bitmap_bit_p (osi.reexamine, i))
{
collect_object_sizes_for (&osi, ssa_name (i));
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Reexamining ");
print_generic_expr (dump_file, ssa_name (i),
dump_flags);
fprintf (dump_file, "\n");
}
}
}
while (osi.changed);
BITMAP_FREE (reexamine);
}
EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi)
bitmap_set_bit (computed[object_size_type], i);
/* Debugging dumps. */
if (dump_file)
{
EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi)
if (object_sizes[object_size_type][i]
!= unknown[object_size_type])
{
print_generic_expr (dump_file, ssa_name (i),
dump_flags);
fprintf (dump_file,
": %s %sobject size "
HOST_WIDE_INT_PRINT_UNSIGNED "\n",
(object_size_type & 2) ? "minimum" : "maximum",
(object_size_type & 1) ? "sub" : "",
object_sizes[object_size_type][i]);
}
}
BITMAP_FREE (osi.reexamine);
BITMAP_FREE (osi.visited);
}
return object_sizes[object_size_type][SSA_NAME_VERSION (ptr)];
return false;
}
return unknown[object_size_type];
if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
{
struct object_size_info osi;
bitmap_iterator bi;
unsigned int i;
if (num_ssa_names > object_sizes[object_size_type].length ())
object_sizes[object_size_type].safe_grow (num_ssa_names);
if (dump_file)
{
fprintf (dump_file, "Computing %s %sobject size for ",
(object_size_type & 2) ? "minimum" : "maximum",
(object_size_type & 1) ? "sub" : "");
print_generic_expr (dump_file, ptr, dump_flags);
fprintf (dump_file, ":\n");
}
osi.visited = BITMAP_ALLOC (NULL);
osi.reexamine = BITMAP_ALLOC (NULL);
osi.object_size_type = object_size_type;
osi.depths = NULL;
osi.stack = NULL;
osi.tos = NULL;
/* First pass: walk UD chains, compute object sizes that
can be computed. osi.reexamine bitmap at the end will
contain what variables were found in dependency cycles
and therefore need to be reexamined. */
osi.pass = 0;
osi.changed = false;
collect_object_sizes_for (&osi, ptr);
/* Second pass: keep recomputing object sizes of variables
that need reexamination, until no object sizes are
increased or all object sizes are computed. */
if (! bitmap_empty_p (osi.reexamine))
{
bitmap reexamine = BITMAP_ALLOC (NULL);
/* If looking for minimum instead of maximum object size,
detect cases where a pointer is increased in a loop.
Although even without this detection pass 2 would eventually
terminate, it could take a long time. If a pointer is
increasing this way, we need to assume 0 object size.
E.g. p = &buf[0]; while (cond) p = p + 4; */
if (object_size_type & 2)
{
osi.depths = XCNEWVEC (unsigned int, num_ssa_names);
osi.stack = XNEWVEC (unsigned int, num_ssa_names);
osi.tos = osi.stack;
osi.pass = 1;
/* collect_object_sizes_for is changing
osi.reexamine bitmap, so iterate over a copy. */
bitmap_copy (reexamine, osi.reexamine);
EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
if (bitmap_bit_p (osi.reexamine, i))
check_for_plus_in_loops (&osi, ssa_name (i));
free (osi.depths);
osi.depths = NULL;
free (osi.stack);
osi.stack = NULL;
osi.tos = NULL;
}
do
{
osi.pass = 2;
osi.changed = false;
/* collect_object_sizes_for is changing
osi.reexamine bitmap, so iterate over a copy. */
bitmap_copy (reexamine, osi.reexamine);
EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi)
if (bitmap_bit_p (osi.reexamine, i))
{
collect_object_sizes_for (&osi, ssa_name (i));
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Reexamining ");
print_generic_expr (dump_file, ssa_name (i),
dump_flags);
fprintf (dump_file, "\n");
}
}
}
while (osi.changed);
BITMAP_FREE (reexamine);
}
EXECUTE_IF_SET_IN_BITMAP (osi.reexamine, 0, i, bi)
bitmap_set_bit (computed[object_size_type], i);
/* Debugging dumps. */
if (dump_file)
{
EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi)
if (object_sizes[object_size_type][i]
!= unknown[object_size_type])
{
print_generic_expr (dump_file, ssa_name (i),
dump_flags);
fprintf (dump_file,
": %s %sobject size "
HOST_WIDE_INT_PRINT_UNSIGNED "\n",
(object_size_type & 2) ? "minimum" : "maximum",
(object_size_type & 1) ? "sub" : "",
object_sizes[object_size_type][i]);
}
}
BITMAP_FREE (osi.reexamine);
BITMAP_FREE (osi.visited);
}
*psize = object_sizes[object_size_type][SSA_NAME_VERSION (ptr)];
return *psize != unknown[object_size_type];
}
/* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME. */
@ -643,7 +685,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value)
|| !POINTER_TYPE_P (TREE_TYPE (value)));
if (TREE_CODE (value) == ADDR_EXPR)
bytes = addr_object_size (osi, value, object_size_type);
addr_object_size (osi, value, object_size_type, &bytes);
else
bytes = unknown[object_size_type];
@ -809,7 +851,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt)
unsigned HOST_WIDE_INT off = tree_to_uhwi (op1);
/* op0 will be ADDR_EXPR here. */
bytes = addr_object_size (osi, op0, object_size_type);
addr_object_size (osi, op0, object_size_type, &bytes);
if (bytes == unknown[object_size_type])
;
else if (off > offset_limit)
@ -1282,10 +1324,9 @@ pass_object_sizes::execute (function *fun)
&& lhs)
{
tree type = TREE_TYPE (lhs);
unsigned HOST_WIDE_INT bytes
= compute_builtin_object_size (ptr, object_size_type);
if (bytes != (unsigned HOST_WIDE_INT) (object_size_type == 1
? -1 : 0)
unsigned HOST_WIDE_INT bytes;
if (compute_builtin_object_size (ptr, object_size_type,
&bytes)
&& wi::fits_to_tree_p (bytes, type))
{
tree tem = make_ssa_name (type);

View file

@ -21,6 +21,6 @@ along with GCC; see the file COPYING3. If not see
#define GCC_TREE_OBJECT_SIZE_H
extern void init_object_sizes (void);
extern unsigned HOST_WIDE_INT compute_builtin_object_size (tree, int);
extern bool compute_builtin_object_size (tree, int, unsigned HOST_WIDE_INT *);
#endif // GCC_TREE_OBJECT_SIZE_H

View file

@ -1826,8 +1826,8 @@ instrument_object_size (gimple_stmt_iterator *gsi, bool is_lhs)
if (decl_p)
base_addr = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (base)), base);
unsigned HOST_WIDE_INT size = compute_builtin_object_size (base_addr, 0);
if (size != HOST_WIDE_INT_M1U)
unsigned HOST_WIDE_INT size;
if (compute_builtin_object_size (base_addr, 0, &size))
sizet = build_int_cst (sizetype, size);
else if (optimize)
{