diff mbox series

Fix bogus strncpy source length warning on source bound by constant

Message ID 20180311152201.9613-1-siddhesh@sourceware.org
State New
Headers show
Series Fix bogus strncpy source length warning on source bound by constant | expand

Commit Message

Siddhesh Poyarekar March 11, 2018, 3:22 p.m. UTC
Avoid issuing a bogus warning when the source of strncpy is bound by a
constant and is known to be less than the size of the destination.

Testsuite run is underway (not complete yet, but no new errors so far)
and a bootstrap is also underway, I'll report status once they're both
done.

gcc/

	* gcc/tree-ssa-strlen.c (handle_builtin_stxncpy): Check bounds
	of source length if available.

gcc/testsuite/

	* gcc.dg/builtin-stringop-chk-10.c: New test case.
---
 gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c | 17 +++++++++++++++++
 gcc/tree-ssa-strlen.c                          | 24 ++++++++++++++++++++++++
 2 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c

Comments

Richard Biener March 12, 2018, 9:56 a.m. UTC | #1
On Sun, Mar 11, 2018 at 4:22 PM, Siddhesh Poyarekar
<siddhesh@sourceware.org> wrote:
> Avoid issuing a bogus warning when the source of strncpy is bound by a
> constant and is known to be less than the size of the destination.
>
> Testsuite run is underway (not complete yet, but no new errors so far)
> and a bootstrap is also underway, I'll report status once they're both
> done.
>
> gcc/
>
>         * gcc/tree-ssa-strlen.c (handle_builtin_stxncpy): Check bounds
>         of source length if available.
>
> gcc/testsuite/
>
>         * gcc.dg/builtin-stringop-chk-10.c: New test case.
> ---
>  gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c | 17 +++++++++++++++++
>  gcc/tree-ssa-strlen.c                          | 24 ++++++++++++++++++++++++
>  2 files changed, 41 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c
>
> diff --git a/gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c b/gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c
> new file mode 100644
> index 00000000000..13e4bd2f049
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c
> @@ -0,0 +1,17 @@
> +/* Bogus -Wstringop-overflow on strncpy when size is based on strlen but is
> +   bound by a constant.
> +   { dg-do compile }
> +   { dg-options "-O2 -Wstringop-overflow" } */
> +
> +char dst[1024];
> +
> +void
> +f1 (const char *src)
> +{
> +  unsigned long limit = 512;
> +  unsigned long len = __builtin_strlen (src);  /* { dg-bogus "length computed here" } */
> +  if (len > limit)
> +    len = limit;
> +
> +  __builtin_strncpy (dst, src, len);   /* { dg-bogus "specified bound depends on the length of the source argument" } */
> +}
> diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
> index 72f6a17cd32..49a31a551f5 100644
> --- a/gcc/tree-ssa-strlen.c
> +++ b/gcc/tree-ssa-strlen.c
> @@ -2125,6 +2125,30 @@ handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi)
>        return;
>      }
>
> +  /* When LEN is MIN_EXPR of strlen and a constant, then the copy is bound by
> +     that constant.  If the destination size is also constant then compare with
> +     it to avoid a bogus warning.  */
> +  if (TREE_CODE (len) == SSA_NAME)
> +    {
> +      gimple *def_stmt = SSA_NAME_DEF_STMT (len);
> +
> +      if (is_gimple_assign (def_stmt)
> +         && gimple_assign_rhs_code (def_stmt) == MIN_EXPR)
> +       {
> +         /* RHS1 is the strlen, so check if RHS2 and DSTSIZE are constant.  */
> +         tree rhs2 = gimple_assign_rhs2 (def_stmt);
> +         tree dstsize = compute_objsize (dst, 1);
> +
> +         if (TREE_CODE (rhs2) == INTEGER_CST
> +             && TREE_CODE (dstsize) == INTEGER_CST
> +             && int_cst_value (rhs2) < int_cst_value (dstsize))

Please use tree_int_cst_lt (rhs1, dstsize) instead.

> +           {
> +             gimple_set_no_warning (stmt, true);

Why this?  There's only a single bit -- where do we warn from if you
don't do this here?

I also wonder why this code doesn't use range-info given the
INTEGER_CST constraints
range-info should tell us more than just handling MIN_EXPR?

Richard.

> +             return;
> +           }
> +       }
> +    }
> +
>    /* Retrieve the strinfo data for the string S that LEN was computed
>       from as some function F of strlen (S) (i.e., LEN need not be equal
>       to strlen(S)).  */
> --
> 2.14.3
>
Siddhesh Poyarekar March 13, 2018, 9:02 a.m. UTC | #2
On Monday 12 March 2018 03:26 PM, Richard Biener wrote:
> Please use tree_int_cst_lt (rhs1, dstsize) instead.
> 
>> +           {
>> +             gimple_set_no_warning (stmt, true);
> 
> Why this?  There's only a single bit -- where do we warn from if you
> don't do this here?

I incorrectly thought it was necessary to set that flag but I noticed
now that it isn't.  I'll remove it.

> I also wonder why this code doesn't use range-info given the
> INTEGER_CST constraints
> range-info should tell us more than just handling MIN_EXPR?

Right, I'll try using range-info.

Thanks,
Siddhesh
diff mbox series

Patch

diff --git a/gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c b/gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c
new file mode 100644
index 00000000000..13e4bd2f049
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-stringop-chk-10.c
@@ -0,0 +1,17 @@ 
+/* Bogus -Wstringop-overflow on strncpy when size is based on strlen but is
+   bound by a constant.
+   { dg-do compile }
+   { dg-options "-O2 -Wstringop-overflow" } */
+
+char dst[1024];
+
+void
+f1 (const char *src)
+{
+  unsigned long limit = 512;
+  unsigned long len = __builtin_strlen (src);	/* { dg-bogus "length computed here" } */
+  if (len > limit)
+    len = limit;
+
+  __builtin_strncpy (dst, src, len);	/* { dg-bogus "specified bound depends on the length of the source argument" } */
+}
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index 72f6a17cd32..49a31a551f5 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -2125,6 +2125,30 @@  handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi)
       return;
     }
 
+  /* When LEN is MIN_EXPR of strlen and a constant, then the copy is bound by
+     that constant.  If the destination size is also constant then compare with
+     it to avoid a bogus warning.  */
+  if (TREE_CODE (len) == SSA_NAME)
+    {
+      gimple *def_stmt = SSA_NAME_DEF_STMT (len);
+
+      if (is_gimple_assign (def_stmt)
+	  && gimple_assign_rhs_code (def_stmt) == MIN_EXPR)
+	{
+	  /* RHS1 is the strlen, so check if RHS2 and DSTSIZE are constant.  */
+	  tree rhs2 = gimple_assign_rhs2 (def_stmt);
+	  tree dstsize = compute_objsize (dst, 1);
+
+	  if (TREE_CODE (rhs2) == INTEGER_CST
+	      && TREE_CODE (dstsize) == INTEGER_CST
+	      && int_cst_value (rhs2) < int_cst_value (dstsize))
+	    {
+	      gimple_set_no_warning (stmt, true);
+	      return;
+	    }
+	}
+    }
+
   /* Retrieve the strinfo data for the string S that LEN was computed
      from as some function F of strlen (S) (i.e., LEN need not be equal
      to strlen(S)).  */