return __builtin_dynamic_object_size (ptr, 0);
}
+/* strdup/strndup. */
+
+size_t
+__attribute__ ((noinline))
+test_strdup (const char *in)
+{
+ char *res = __builtin_strdup (in);
+ return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup (const char *in, size_t bound)
+{
+ char *res = __builtin_strndup (in, bound);
+ return __builtin_dynamic_object_size (res, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strdup_min (const char *in)
+{
+ char *res = __builtin_strdup (in);
+ return __builtin_dynamic_object_size (res, 2);
+}
+
+size_t
+__attribute__ ((noinline))
+test_strndup_min (const char *in, size_t bound)
+{
+ char *res = __builtin_strndup (in, bound);
+ return __builtin_dynamic_object_size (res, 2);
+}
+
/* Other tests. */
struct TV4
int *t = test_pr105736 (&val3);
if (__builtin_dynamic_object_size (t, 0) != -1)
FAIL ();
+ const char *str = "hello world";
+ if (test_strdup (str) != __builtin_strlen (str) + 1)
+ FAIL ();
+ if (test_strndup (str, 4) != 5)
+ FAIL ();
+ if (test_strdup_min (str) != __builtin_strlen (str) + 1)
+ FAIL ();
+ if (test_strndup_min (str, 4) != 1)
+ FAIL ();
if (nfails > 0)
__builtin_abort ();
/* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
/* { dg-require-effective-target alloca } */
#define __builtin_object_size __builtin_dynamic_object_size
/* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
/* { dg-require-effective-target alloca } */
#define __builtin_object_size __builtin_dynamic_object_size
/* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
/* { dg-require-effective-target alloca } */
#define __builtin_object_size __builtin_dynamic_object_size
/* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
/* { dg-require-effective-target alloca } */
#define __builtin_object_size __builtin_dynamic_object_size
/* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
/* { dg-require-effective-target alloca } */
typedef __SIZE_TYPE__ size_t;
extern void exit (int);
extern void *malloc (size_t);
extern void *calloc (size_t, size_t);
+extern void free (void *);
extern void *alloca (size_t);
extern void *memcpy (void *, const void *, size_t);
extern void *memset (void *, int, size_t);
extern char *strcpy (char *, const char *);
+extern char *strdup (const char *);
+extern char *strndup (const char *, size_t);
struct A
{
}
}
+/* Tests for strdup/strndup. */
+size_t
+__attribute__ ((noinline))
+test11 (void)
+{
+ int i = 0;
+ const char *ptr = "abcdefghijklmnopqrstuvwxyz";
+ char *res = strndup (ptr, 21);
+ if (__builtin_object_size (res, 0) != 22)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr, 32);
+ if (__builtin_object_size (res, 0) != 27)
+ abort ();
+
+ free (res);
+
+ res = strdup (ptr);
+ if (__builtin_object_size (res, 0) != 27)
+ abort ();
+
+ free (res);
+
+ char *ptr2 = malloc (64);
+ strcpy (ptr2, ptr);
+
+ res = strndup (ptr2, 21);
+ if (__builtin_object_size (res, 0) != 22)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr2, 32);
+ if (__builtin_object_size (res, 0) != 33)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr2, 128);
+ if (__builtin_object_size (res, 0) != 64)
+ abort ();
+
+ free (res);
+
+ res = strdup (ptr2);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (res, 0) != 27)
+#else
+ if (__builtin_object_size (res, 0) != (size_t) -1)
+#endif
+ abort ();
+ free (res);
+ free (ptr2);
+
+ ptr = "abcd\0efghijklmnopqrstuvwxyz";
+ res = strdup (ptr);
+ if (__builtin_object_size (res, 0) != 5)
+ abort ();
+ free (res);
+
+ res = strndup (ptr, 24);
+ if (__builtin_object_size (res, 0) != 5)
+ abort ();
+ free (res);
+
+ res = strndup (ptr, 2);
+ if (__builtin_object_size (res, 0) != 3)
+ abort ();
+ free (res);
+
+ res = strdup (&ptr[4]);
+ if (__builtin_object_size (res, 0) != 1)
+ abort ();
+ free (res);
+
+ res = strndup (&ptr[4], 4);
+ if (__builtin_object_size (res, 0) != 1)
+ abort ();
+ free (res);
+
+ res = strndup (&ptr[4], 1);
+ if (__builtin_object_size (res, 0) != 1)
+ abort ();
+ free (res);
+}
+
int
main (void)
{
test8 ();
test9 (1);
test10 ();
+ test11 ();
exit (0);
}
/* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
/* { dg-require-effective-target alloca } */
typedef __SIZE_TYPE__ size_t;
extern void exit (int);
extern void *malloc (size_t);
extern void *calloc (size_t, size_t);
+extern void free (void *);
extern void *alloca (size_t);
extern void *memcpy (void *, const void *, size_t);
extern void *memset (void *, int, size_t);
extern char *strcpy (char *, const char *);
+extern char *strdup (const char *);
+extern char *strndup (const char *, size_t);
struct A
{
#endif
}
+/* Tests for strdup/strndup. */
+size_t
+__attribute__ ((noinline))
+test9 (void)
+{
+ const char *ptr = "abcdefghijklmnopqrstuvwxyz";
+ char *res = strndup (ptr, 21);
+ if (__builtin_object_size (res, 1) != 22)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr, 32);
+ if (__builtin_object_size (res, 1) != 27)
+ abort ();
+
+ free (res);
+
+ res = strdup (ptr);
+ if (__builtin_object_size (res, 1) != 27)
+ abort ();
+
+ free (res);
+
+ char *ptr2 = malloc (64);
+ strcpy (ptr2, ptr);
+
+ res = strndup (ptr2, 21);
+ if (__builtin_object_size (res, 1) != 22)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr2, 32);
+ if (__builtin_object_size (res, 1) != 33)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr2, 128);
+ if (__builtin_object_size (res, 1) != 64)
+ abort ();
+
+ free (res);
+
+ res = strdup (ptr2);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (res, 1) != 27)
+#else
+ if (__builtin_object_size (res, 1) != (size_t) -1)
+#endif
+ abort ();
+
+ free (res);
+ free (ptr2);
+
+ ptr = "abcd\0efghijklmnopqrstuvwxyz";
+ res = strdup (ptr);
+ if (__builtin_object_size (res, 1) != 5)
+ abort ();
+ free (res);
+
+ res = strndup (ptr, 24);
+ if (__builtin_object_size (res, 1) != 5)
+ abort ();
+ free (res);
+
+ res = strndup (ptr, 2);
+ if (__builtin_object_size (res, 1) != 3)
+ abort ();
+ free (res);
+
+ res = strdup (&ptr[4]);
+ if (__builtin_object_size (res, 1) != 1)
+ abort ();
+ free (res);
+
+ res = strndup (&ptr[4], 4);
+ if (__builtin_object_size (res, 1) != 1)
+ abort ();
+ free (res);
+
+ res = strndup (&ptr[4], 1);
+ if (__builtin_object_size (res, 1) != 1)
+ abort ();
+ free (res);
+}
+
int
main (void)
{
test6 ();
test7 ();
test8 (1);
+ test9 ();
exit (0);
}
/* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
/* { dg-require-effective-target alloca } */
typedef __SIZE_TYPE__ size_t;
extern void exit (int);
extern void *malloc (size_t);
extern void *calloc (size_t, size_t);
+extern void free (void *);
extern void *alloca (size_t);
extern void *memcpy (void *, const void *, size_t);
extern void *memset (void *, int, size_t);
extern char *strcpy (char *, const char *);
+extern char *strdup (const char *);
+extern char *strndup (const char *, size_t);
struct A
{
}
}
+/* Tests for strdup/strndup. */
+size_t
+__attribute__ ((noinline))
+test11 (void)
+{
+ const char *ptr = "abcdefghijklmnopqrstuvwxyz";
+ char *res = strndup (ptr, 21);
+ if (__builtin_object_size (res, 2) != 22)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr, 32);
+ if (__builtin_object_size (res, 2) != 27)
+ abort ();
+
+ free (res);
+
+ res = strdup (ptr);
+ if (__builtin_object_size (res, 2) != 27)
+ abort ();
+
+ free (res);
+
+ char *ptr2 = malloc (64);
+ strcpy (ptr2, ptr);
+
+ res = strndup (ptr2, 21);
+ if (__builtin_object_size (res, 2) != 1)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr2, 32);
+ if (__builtin_object_size (res, 2) != 1)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr2, 128);
+ if (__builtin_object_size (res, 2) != 1)
+ abort ();
+
+ free (res);
+
+ res = strdup (ptr2);
+
+#ifdef __builtin_object_size
+ if (__builtin_object_size (res, 2) != 27)
+#else
+ if (__builtin_object_size (res, 2) != 1)
+#endif
+ abort ();
+
+ free (res);
+ free (ptr2);
+
+ ptr = "abcd\0efghijklmnopqrstuvwxyz";
+ res = strdup (ptr);
+ if (__builtin_object_size (res, 2) != 5)
+ abort ();
+ free (res);
+
+ res = strndup (ptr, 24);
+ if (__builtin_object_size (res, 2) != 5)
+ abort ();
+ free (res);
+
+ res = strndup (ptr, 2);
+ if (__builtin_object_size (res, 2) != 3)
+ abort ();
+ free (res);
+
+ res = strdup (&ptr[4]);
+ if (__builtin_object_size (res, 2) != 1)
+ abort ();
+ free (res);
+
+ res = strndup (&ptr[4], 4);
+ if (__builtin_object_size (res, 2) != 1)
+ abort ();
+ free (res);
+
+ res = strndup (&ptr[4], 1);
+ if (__builtin_object_size (res, 2) != 1)
+ abort ();
+ free (res);
+}
+
int
main (void)
{
test8 ();
test9 (1);
test10 ();
+ test11 ();
exit (0);
}
/* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */
/* { dg-require-effective-target alloca } */
typedef __SIZE_TYPE__ size_t;
extern void exit (int);
extern void *malloc (size_t);
extern void *calloc (size_t, size_t);
+extern void free (void *);
extern void *alloca (size_t);
extern void *memcpy (void *, const void *, size_t);
extern void *memset (void *, int, size_t);
extern char *strcpy (char *, const char *);
+extern char *strdup (const char *);
+extern char *strndup (const char *, size_t);
struct A
{
#endif
}
+/* Tests for strdup/strndup. */
+size_t
+__attribute__ ((noinline))
+test9 (void)
+{
+ const char *ptr = "abcdefghijklmnopqrstuvwxyz";
+ char *res = strndup (ptr, 21);
+ if (__builtin_object_size (res, 3) != 22)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr, 32);
+ if (__builtin_object_size (res, 3) != 27)
+ abort ();
+
+ free (res);
+
+ res = strdup (ptr);
+ if (__builtin_object_size (res, 3) != 27)
+ abort ();
+
+ free (res);
+
+ char *ptr2 = malloc (64);
+ strcpy (ptr2, ptr);
+
+ res = strndup (ptr2, 21);
+ if (__builtin_object_size (res, 3) != 1)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr2, 32);
+ if (__builtin_object_size (res, 3) != 1)
+ abort ();
+
+ free (res);
+
+ res = strndup (ptr2, 128);
+ if (__builtin_object_size (res, 3) != 1)
+ abort ();
+
+ free (res);
+
+ res = strdup (ptr2);
+#ifdef __builtin_object_size
+ if (__builtin_object_size (res, 3) != 27)
+#else
+ if (__builtin_object_size (res, 3) != 1)
+#endif
+ abort ();
+
+ free (res);
+ free (ptr2);
+
+ ptr = "abcd\0efghijklmnopqrstuvwxyz";
+ res = strdup (ptr);
+ if (__builtin_object_size (res, 3) != 5)
+ abort ();
+ free (res);
+
+ res = strndup (ptr, 24);
+ if (__builtin_object_size (res, 3) != 5)
+ abort ();
+ free (res);
+
+ res = strndup (ptr, 2);
+ if (__builtin_object_size (res, 3) != 3)
+ abort ();
+ free (res);
+
+ res = strdup (&ptr[4]);
+ if (__builtin_object_size (res, 3) != 1)
+ abort ();
+ free (res);
+
+ res = strndup (&ptr[4], 4);
+ if (__builtin_object_size (res, 3) != 1)
+ abort ();
+ free (res);
+
+ res = strndup (&ptr[4], 1);
+ if (__builtin_object_size (res, 3) != 1)
+ abort ();
+ free (res);
+}
+
int
main (void)
{
test6 ();
test7 ();
test8 (1);
+ test9 ();
exit (0);
}
/* Maximum value of offset we consider to be addition. */
static unsigned HOST_WIDE_INT offset_limit;
+/* Tell the generic SSA updater what kind of update is needed after the pass
+ executes. */
+static unsigned todo;
+
/* Return true if VAL represents an initial size for OBJECT_SIZE_TYPE. */
static inline bool
return bytes ? bytes : size_unknown (object_size_type);
}
+/* Compute __builtin_object_size for CALL, which is a call to either
+ BUILT_IN_STRDUP or BUILT_IN_STRNDUP; IS_STRNDUP indicates which it is.
+ OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
+ If unknown, return size_unknown (object_size_type). */
+
+static tree
+strdup_object_size (const gcall *call, int object_size_type, bool is_strndup)
+{
+ tree src = gimple_call_arg (call, 0);
+ tree sz = size_unknown (object_size_type);
+ tree n = NULL_TREE;
+
+ if (is_strndup)
+ n = fold_build2 (PLUS_EXPR, sizetype, size_one_node,
+ gimple_call_arg (call, 1));
+ /* For strdup, simply emit strlen (SRC) + 1 and let the optimizer fold it the
+ way it likes. */
+ else
+ {
+ tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
+ if (strlen_fn)
+ {
+ sz = fold_build2 (PLUS_EXPR, sizetype, size_one_node,
+ build_call_expr (strlen_fn, 1, src));
+ todo = TODO_update_ssa_only_virtuals;
+ }
+ }
+
+ /* In all other cases, return the size of SRC since the object size cannot
+ exceed that. We cannot do this for OST_MINIMUM unless SRC points into a
+ string constant since otherwise the object size could go all the way down
+ to zero. */
+ if (!size_valid_p (sz, object_size_type)
+ || size_unknown_p (sz, object_size_type))
+ {
+ tree wholesrc = NULL_TREE;
+ if (TREE_CODE (src) == ADDR_EXPR)
+ wholesrc = get_base_address (TREE_OPERAND (src, 0));
+
+ /* If the source points within a string constant, we try to get its
+ length. */
+ if (wholesrc && TREE_CODE (wholesrc) == STRING_CST)
+ {
+ tree len = c_strlen (src, 0);
+ if (len)
+ sz = fold_build2 (PLUS_EXPR, sizetype, size_one_node, len);
+ }
+
+ /* For maximum estimate, our next best guess is the object size of the
+ source. */
+ if (size_unknown_p (sz, object_size_type)
+ && !(object_size_type & OST_MINIMUM))
+ compute_builtin_object_size (src, object_size_type, &sz);
+ }
+
+ /* String duplication allocates at least one byte, so we should never fail
+ for OST_MINIMUM. */
+ if ((!size_valid_p (sz, object_size_type)
+ || size_unknown_p (sz, object_size_type))
+ && (object_size_type & OST_MINIMUM))
+ sz = size_one_node;
+
+ /* Factor in the N. */
+ return n ? fold_build2 (MIN_EXPR, sizetype, n, sz) : sz;
+}
/* If object size is propagated from one of function's arguments directly
to its return value, return that argument for GIMPLE_CALL statement CALL.
{
int object_size_type = osi->object_size_type;
unsigned int varno = SSA_NAME_VERSION (ptr);
+ tree bytes = NULL_TREE;
gcc_assert (is_gimple_call (call));
gcc_assert (!object_sizes_unknown_p (object_size_type, varno));
gcc_assert (osi->pass == 0);
- tree bytes = alloc_object_size (call, object_size_type);
+
+ bool is_strdup = gimple_call_builtin_p (call, BUILT_IN_STRDUP);
+ bool is_strndup = gimple_call_builtin_p (call, BUILT_IN_STRNDUP);
+ if (is_strdup || is_strndup)
+ bytes = strdup_object_size (call, object_size_type, is_strndup);
+ else
+ bytes = alloc_object_size (call, object_size_type);
if (!size_valid_p (bytes, object_size_type))
bytes = size_unknown (object_size_type);
static unsigned int
object_sizes_execute (function *fun, bool early)
{
+ todo = 0;
+
basic_block bb;
FOR_EACH_BB_FN (bb, fun)
{
}
fini_object_sizes ();
- return 0;
+ return todo;
}
/* Simple pass to optimize all __builtin_object_size () builtins. */