Re: [PATCH] tree-object-size: Support strndup and strdup

2022-11-02 Thread Siddhesh Poyarekar

On 2022-09-23 09:02, Jakub Jelinek wrote:

Oh, so can addr_object_size be simplified to use get_base_address too?


You can try.  As you can see in get_base_address, that function
handles something that the above doesn't (looking through some MEM_REFs too).



I went down this rabbithole and it actually simplifies some cases but 
got sucked into flex array related issues that I need more time to 
figure out.  I'll stick to using get_base_address for now since I want 
to make sure this makes the stage 1 deadline.


Thanks,
Sid


Re: [PATCH] tree-object-size: Support strndup and strdup

2022-09-23 Thread Jakub Jelinek via Gcc-patches
On Thu, Sep 22, 2022 at 11:26:29AM -0400, Siddhesh Poyarekar wrote:
> On 2022-09-22 09:02, Jakub Jelinek wrote:
> > On Mon, Aug 15, 2022 at 03:23:11PM -0400, Siddhesh Poyarekar wrote:
> > > --- a/gcc/tree-object-size.cc
> > > +++ b/gcc/tree-object-size.cc
> > > @@ -495,6 +495,18 @@ decl_init_size (tree decl, bool min)
> > > return size;
> > >   }
> > > +/* Get the outermost object that PTR may point into.  */
> > > +
> > > +static tree
> > > +get_whole_object (const_tree ptr)
> > > +{
> > > +  tree pt_var = TREE_OPERAND (ptr, 0);
> > > +  while (handled_component_p (pt_var))
> > > +pt_var = TREE_OPERAND (pt_var, 0);
> > > +
> > > +  return pt_var;
> > > +}
> > 
> > Not sure why you want a new function for this.
> > This is essentially get_base_address (TREE_OPERAND (ptr, 0)).
> 
> Oh, so can addr_object_size be simplified to use get_base_address too?

You can try.  As you can see in get_base_address, that function
handles something that the above doesn't (looking through some MEM_REFs too).

> > Even if c_strlen (src, 1) is constant, I don't see what you can assume
> > for object size of strndup ("abcd\0efgh", n); for minimum, except 1.
> 
> Can't we assume MIN(5, n) for STRING_CST?

If you mean MIN(5, n + 1), for c_strlen constant yes, but say if you have
strndup (&"abcd\0efgh"[i], n); you can't just from seeing a base address
being a STRING_CST with certain length assume anything than 1.

> For ARRAY_REFs, it may end up being MIN(array_size, n) and not account for

No, for non-OST_MINIMUM array size of objects (or string literals) containing
the strings is relevant and you can indeed use MIN(__b{d}os (src), n + 1)
as maximum.  But for the minimum, the object size is irrelevant, you don't
know where in the string there are '\0's and they could appear anywhere
(unless you do string length range analysis).  With c_strlen on src
returning constant you know the exact string length and so you can use
MIN (c_strlen (src, 1) + 1, n + 1) as both minimum and maximum, but in all
other cases, 1 is the safe answer.

Jakub



Re: [PATCH] tree-object-size: Support strndup and strdup

2022-09-22 Thread Siddhesh Poyarekar

On 2022-09-22 09:02, Jakub Jelinek wrote:

On Mon, Aug 15, 2022 at 03:23:11PM -0400, Siddhesh Poyarekar wrote:

--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -495,6 +495,18 @@ decl_init_size (tree decl, bool min)
return size;
  }
  
+/* Get the outermost object that PTR may point into.  */

+
+static tree
+get_whole_object (const_tree ptr)
+{
+  tree pt_var = TREE_OPERAND (ptr, 0);
+  while (handled_component_p (pt_var))
+pt_var = TREE_OPERAND (pt_var, 0);
+
+  return pt_var;
+}


Not sure why you want a new function for this.
This is essentially get_base_address (TREE_OPERAND (ptr, 0)).


Oh, so can addr_object_size be simplified to use get_base_address too?


  /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
 OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
 If unknown, return size_unknown (object_size_type).  */
+  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_whole_object (src);
+
+  if (!(object_size_type & OST_MINIMUM)
+ || (wholesrc && TREE_CODE (wholesrc) == STRING_CST))


Is this safe?  I mean get_whole_object will also skip ARRAY_REFs with
variable indexes etc. and the STRING_CST could have embedded '\0's
in it.
Even if c_strlen (src, 1) is constant, I don't see what you can assume
for object size of strndup ("abcd\0efgh", n); for minimum, except 1.


Can't we assume MIN(5, n) for STRING_CST?

For ARRAY_REFs, it may end up being MIN(array_size, n) and not account 
for the NUL termination but I was thinking of that as being a better 
option than bailing out.  Should we try harder here and return, e.g. 
strlen or some equivalent?



But on the other side, 1 is a safe minimum for OST_MINIMUM of both
strdup and strndup if you don't find anything more specific (exact strlen
for strndup) because the terminating '\0' will be always there.


OK, I can return size_one_node as the final return value for OST_MINIMUM 
if we don't find a suitable expression.



Other than that you'd need to consider INTEGER_CST second strndup argument
or ranges of the second argument etc.
E.g. maximum for OST_DYNAMIC could be for strndup (src, n)
MIN (__bdos (src, ?), n + 1).


Yeah, that's what I return in the end:

  return fold_build2 (MIN_EXPR, sizetype,
 fold_build2 (PLUS_EXPR, sizetype, size_one_node,n),
 sz);

where sz is __bdos(src)




@@ -2113,7 +2177,7 @@ const pass_data pass_data_object_sizes =
PROP_objsz, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
-  0, /* todo_flags_finish */
+  TODO_update_ssa_no_phi, /* todo_flags_finish */
  };
  
  class pass_object_sizes : public gimple_opt_pass

@@ -2153,7 +2217,7 @@ const pass_data pass_data_early_object_sizes =
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
-  0, /* todo_flags_finish */
+  TODO_update_ssa_no_phi, /* todo_flags_finish */
  };


This is quite expensive.  Do you really need full ssa update, or just
TODO_update_ssa_only_virtuals would be enough (is it for the missing
vuse on the strlen call if you emit it)?
In any case, would be better not to do that always, but only if you
really need it (emitted the strlen call somewhere; e.g. if __bdos is
never used, only __bos, it is certainly not needed), todo flags
can be both in todo_flags_finish and in return value from execute method.


Thanks, I'll find a cheaper way to do this.

Thanks,
Sid


Re: [PATCH] tree-object-size: Support strndup and strdup

2022-09-22 Thread Jakub Jelinek via Gcc-patches
On Mon, Aug 15, 2022 at 03:23:11PM -0400, Siddhesh Poyarekar wrote:
> --- a/gcc/tree-object-size.cc
> +++ b/gcc/tree-object-size.cc
> @@ -495,6 +495,18 @@ decl_init_size (tree decl, bool min)
>return size;
>  }
>  
> +/* Get the outermost object that PTR may point into.  */
> +
> +static tree
> +get_whole_object (const_tree ptr)
> +{
> +  tree pt_var = TREE_OPERAND (ptr, 0);
> +  while (handled_component_p (pt_var))
> +pt_var = TREE_OPERAND (pt_var, 0);
> +
> +  return pt_var;
> +}

Not sure why you want a new function for this.
This is essentially get_base_address (TREE_OPERAND (ptr, 0)).

>  /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR.
> OBJECT_SIZE_TYPE is the second argument from __builtin_object_size.
> If unknown, return size_unknown (object_size_type).  */
> +  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_whole_object (src);
> +
> +  if (!(object_size_type & OST_MINIMUM)
> +   || (wholesrc && TREE_CODE (wholesrc) == STRING_CST))

Is this safe?  I mean get_whole_object will also skip ARRAY_REFs with
variable indexes etc. and the STRING_CST could have embedded '\0's
in it.
Even if c_strlen (src, 1) is constant, I don't see what you can assume
for object size of strndup ("abcd\0efgh", n); for minimum, except 1.
But on the other side, 1 is a safe minimum for OST_MINIMUM of both
strdup and strndup if you don't find anything more specific (exact strlen
for strndup) because the terminating '\0' will be always there.
Other than that you'd need to consider INTEGER_CST second strndup argument
or ranges of the second argument etc.
E.g. maximum for OST_DYNAMIC could be for strndup (src, n)
MIN (__bdos (src, ?), n + 1).

> @@ -2113,7 +2177,7 @@ const pass_data pass_data_object_sizes =
>PROP_objsz, /* properties_provided */
>0, /* properties_destroyed */
>0, /* todo_flags_start */
> -  0, /* todo_flags_finish */
> +  TODO_update_ssa_no_phi, /* todo_flags_finish */
>  };
>  
>  class pass_object_sizes : public gimple_opt_pass
> @@ -2153,7 +2217,7 @@ const pass_data pass_data_early_object_sizes =
>0, /* properties_provided */
>0, /* properties_destroyed */
>0, /* todo_flags_start */
> -  0, /* todo_flags_finish */
> +  TODO_update_ssa_no_phi, /* todo_flags_finish */
>  };

This is quite expensive.  Do you really need full ssa update, or just
TODO_update_ssa_only_virtuals would be enough (is it for the missing
vuse on the strlen call if you emit it)?
In any case, would be better not to do that always, but only if you
really need it (emitted the strlen call somewhere; e.g. if __bdos is
never used, only __bos, it is certainly not needed), todo flags
can be both in todo_flags_finish and in return value from execute method.

Jakub



Re: [PATCH] tree-object-size: Support strndup and strdup

2022-09-15 Thread Siddhesh Poyarekar

Ping!

On 2022-09-07 15:21, Siddhesh Poyarekar wrote:

Ping!

On 2022-08-29 10:16, Siddhesh Poyarekar wrote:

Ping!

On 2022-08-15 15:23, Siddhesh Poyarekar wrote:

Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (get_whole_object): New function.
(addr_object_size): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.
(pass_data_object_sizes, pass_data_early_object_sizes): Set
todo_flags_finish to TODO_update_ssa_no_phi.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
  .../gcc.dg/builtin-dynamic-object-size-0.c    | 43 +++
  .../gcc.dg/builtin-dynamic-object-size-1.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-2.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-3.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-4.c    |  2 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 64 +++-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++-
  gcc/tree-object-size.cc   | 76 +--
  10 files changed, 366 insertions(+), 14 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c

index 01a280b2d7b..7f023708b15 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, 
size_t end, int incr)

    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
@@ -651,6 +685,15 @@ main (int argc, char **argv)
    int *t = test_pr105736 ();
    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) != 0)
+    FAIL ();
    if (nfails > 0)
  __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c

index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
  /* { 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
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c

index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 @@
  /* { dg-do run } */
-/* { 

Re: [PATCH] tree-object-size: Support strndup and strdup

2022-09-07 Thread Siddhesh Poyarekar

Ping!

On 2022-08-29 10:16, Siddhesh Poyarekar wrote:

Ping!

On 2022-08-15 15:23, Siddhesh Poyarekar wrote:

Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (get_whole_object): New function.
(addr_object_size): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.
(pass_data_object_sizes, pass_data_early_object_sizes): Set
todo_flags_finish to TODO_update_ssa_no_phi.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
  .../gcc.dg/builtin-dynamic-object-size-0.c    | 43 +++
  .../gcc.dg/builtin-dynamic-object-size-1.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-2.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-3.c    |  2 +-
  .../gcc.dg/builtin-dynamic-object-size-4.c    |  2 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 64 +++-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++-
  gcc/tree-object-size.cc   | 76 +--
  10 files changed, 366 insertions(+), 14 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c

index 01a280b2d7b..7f023708b15 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, 
size_t end, int incr)

    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
@@ -651,6 +685,15 @@ main (int argc, char **argv)
    int *t = test_pr105736 ();
    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) != 0)
+    FAIL ();
    if (nfails > 0)
  __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c

index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
  /* { 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
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c

index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 @@
  /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 

Re: [PATCH] tree-object-size: Support strndup and strdup

2022-08-29 Thread Siddhesh Poyarekar

Ping!

On 2022-08-15 15:23, Siddhesh Poyarekar wrote:

Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (get_whole_object): New function.
(addr_object_size): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.
(pass_data_object_sizes, pass_data_early_object_sizes): Set
todo_flags_finish to TODO_update_ssa_no_phi.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
  .../gcc.dg/builtin-dynamic-object-size-0.c| 43 +++
  .../gcc.dg/builtin-dynamic-object-size-1.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-2.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-3.c|  2 +-
  .../gcc.dg/builtin-dynamic-object-size-4.c|  2 +-
  gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 64 +++-
  gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++-
  gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++-
  gcc/tree-object-size.cc   | 76 +--
  10 files changed, 366 insertions(+), 14 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 01a280b2d7b..7f023708b15 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
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

@@ -651,6 +685,15 @@ main (int argc, char **argv)
int *t = test_pr105736 ();
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) != 0)
+FAIL ();
  
if (nfails > 0)

  __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
  /* { 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

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 @@
  /* { dg-do 

[PATCH] tree-object-size: Support strndup and strdup

2022-08-15 Thread Siddhesh Poyarekar
Use string length of input to strdup to determine the usable size of the
resulting object.  Avoid doing the same for strndup since there's a
chance that the input may be too large, resulting in an unnecessary
overhead or worse, the input may not be NULL terminated, resulting in a
crash where there would otherwise have been none.

gcc/ChangeLog:

* tree-object-size.cc (get_whole_object): New function.
(addr_object_size): Use it.
(strdup_object_size): New function.
(call_object_size): Use it.
(pass_data_object_sizes, pass_data_early_object_sizes): Set
todo_flags_finish to TODO_update_ssa_no_phi.

gcc/testsuite/ChangeLog:

* gcc.dg/builtin-dynamic-object-size-0.c (test_strdup,
test_strndup, test_strdup_min, test_strndup_min): New tests.
(main): Call them.
* gcc.dg/builtin-dynamic-object-size-1.c: Silence overread
warnings.
* gcc.dg/builtin-dynamic-object-size-2.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-3.c: Likewise.
* gcc.dg/builtin-dynamic-object-size-4.c: Likewise.
* gcc.dg/builtin-object-size-1.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-2.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
* gcc.dg/builtin-object-size-3.c: Silence overread warnings.
Declare free, strdup and strndup.
(test11): New test.
(main): Call it.
* gcc.dg/builtin-object-size-4.c: Silence overread warnings.
Declare free, strdup and strndup.
(test9): New test.
(main): Call it.
---
 .../gcc.dg/builtin-dynamic-object-size-0.c| 43 +++
 .../gcc.dg/builtin-dynamic-object-size-1.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-2.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-3.c|  2 +-
 .../gcc.dg/builtin-dynamic-object-size-4.c|  2 +-
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 64 +++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 63 ++-
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 63 ++-
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 63 ++-
 gcc/tree-object-size.cc   | 76 +--
 10 files changed, 366 insertions(+), 14 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 01a280b2d7b..7f023708b15 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -479,6 +479,40 @@ test_loop (int *obj, size_t sz, size_t start, size_t end, 
int incr)
   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
@@ -651,6 +685,15 @@ main (int argc, char **argv)
   int *t = test_pr105736 ();
   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) != 0)
+FAIL ();
 
   if (nfails > 0)
 __builtin_abort ();
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
index 7cc8b1c9488..8f17c8edcaf 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c
@@ -1,5 +1,5 @@
 /* { 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
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
index 267dbf48ca7..3677782ff1c 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c
@@ -1,5 +1,5 @@
 /* { dg-do run } */
-/* { dg-options "-O2" } */
+/* { dg-options "-O2 -Wno-stringop-overread" } */