Commit 5d0d5d68 by Martin Sebor Committed by Martin Sebor

PR tree-optimization/84480 - bogus -Wstringop-truncation despite assignment with…

PR tree-optimization/84480 - bogus -Wstringop-truncation despite assignment with an inlined string literal

gcc/ChangeLog:

	PR tree-optimization/84480
	* gimple-fold.c (gimple_fold_builtin_strcpy): Move warnings
	to maybe_diag_stxncpy_trunc.  Call it.
	* tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Integrate warnings
	from gimple_fold_builtin_strcpy.  Print inlining stack.
	(handle_builtin_stxncpy): Print inlining stack.
	* tree-ssa-strlen.h (maybe_diag_stxncpy_trunc): Declare.

gcc/testsuite/ChangeLog:

	PR tree-optimization/84480
	* c-c++-common/Wstringop-truncation.c: Adjust text of expected warnings.
	* g++.dg/warn/Wstringop-truncation-1.C: New test.

From-SVN: r257910
parent 73b8b822
2018-02-22 Martin Sebor <msebor@redhat.com>
PR tree-optimization/84480
* gimple-fold.c (gimple_fold_builtin_strcpy): Move warnings
to maybe_diag_stxncpy_trunc. Call it.
* tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Integrate warnings
from gimple_fold_builtin_strcpy. Print inlining stack.
(handle_builtin_stxncpy): Print inlining stack.
* tree-ssa-strlen.h (maybe_diag_stxncpy_trunc): Declare.
2018-02-22 H.J. Lu <hongjiu.lu@intel.com> 2018-02-22 H.J. Lu <hongjiu.lu@intel.com>
PR target/84176 PR target/84176
......
...@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h" #include "intl.h"
#include "calls.h" #include "calls.h"
#include "tree-vector-builder.h" #include "tree-vector-builder.h"
#include "tree-ssa-strlen.h"
/* Return true when DECL can be referenced from current unit. /* Return true when DECL can be referenced from current unit.
FROM_DECL (if non-null) specify constructor of variable DECL was taken from. FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
...@@ -1710,37 +1711,8 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi, ...@@ -1710,37 +1711,8 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi,
if (tree_int_cst_lt (ssize, len)) if (tree_int_cst_lt (ssize, len))
return false; return false;
if (!nonstring) /* Diagnose truncation that leaves the copy unterminated. */
{ maybe_diag_stxncpy_trunc (*gsi, src, len);
if (tree_int_cst_lt (len, slen))
{
tree fndecl = gimple_call_fndecl (stmt);
gcall *call = as_a <gcall *> (stmt);
warning_at (loc, OPT_Wstringop_truncation,
(tree_int_cst_equal (size_one_node, len)
? G_("%G%qD output truncated copying %E byte "
"from a string of length %E")
: G_("%G%qD output truncated copying %E bytes "
"from a string of length %E")),
call, fndecl, len, slen);
}
else if (tree_int_cst_equal (len, slen))
{
tree fndecl = gimple_call_fndecl (stmt);
gcall *call = as_a <gcall *> (stmt);
warning_at (loc, OPT_Wstringop_truncation,
(tree_int_cst_equal (size_one_node, len)
? G_("%G%qD output truncated before terminating nul "
"copying %E byte from a string of the same "
"length")
: G_("%G%qD output truncated before terminating nul "
"copying %E bytes from a string of the same "
"length")),
call, fndecl, len);
}
}
/* OK transform into builtin memcpy. */ /* OK transform into builtin memcpy. */
tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY); tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
......
2018-02-22 Martin Sebor <msebor@redhat.com>
PR tree-optimization/84480
* c-c++-common/Wstringop-truncation.c: Adjust text of expected warnings.
* g++.dg/warn/Wstringop-truncation-1.C: New test.
2018-02-22 H.J. Lu <hongjiu.lu@intel.com> 2018-02-22 H.J. Lu <hongjiu.lu@intel.com>
PR target/84176 PR target/84176
......
...@@ -188,7 +188,7 @@ void test_strncpy_ptr (char *d, const char* s, const char *t, int i) ...@@ -188,7 +188,7 @@ void test_strncpy_ptr (char *d, const char* s, const char *t, int i)
CPY (d, CHOOSE (s, t), 2); CPY (d, CHOOSE (s, t), 2);
CPY (d, CHOOSE ("", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 3" } */ CPY (d, CHOOSE ("", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 3" } */
CPY (d, CHOOSE ("1", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 1" } */ CPY (d, CHOOSE ("1", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 1 byte from a string of the same length" } */
CPY (d, CHOOSE ("12", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */ CPY (d, CHOOSE ("12", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */
CPY (d, CHOOSE ("123", "12"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */ CPY (d, CHOOSE ("123", "12"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */
...@@ -331,7 +331,7 @@ void test_strncpy_array (Dest *pd, int i, const char* s) ...@@ -331,7 +331,7 @@ void test_strncpy_array (Dest *pd, int i, const char* s)
/* This might be better written using memcpy() but it's safe so /* This might be better written using memcpy() but it's safe so
it probably shouldn't be diagnosed. It currently triggers it probably shouldn't be diagnosed. It currently triggers
a warning because of bug 81704. */ a warning because of bug 81704. */
strncpy (dst7, "0123456", sizeof dst7); /* { dg-bogus "truncated" "bug 81704" { xfail *-*-* } } */ strncpy (dst7, "0123456", sizeof dst7); /* { dg-bogus "\\\[-Wstringop-truncation]" "bug 81704" { xfail *-*-* } } */
dst7[sizeof dst7 - 1] = '\0'; dst7[sizeof dst7 - 1] = '\0';
sink (dst7); sink (dst7);
} }
...@@ -350,7 +350,7 @@ void test_strncpy_array (Dest *pd, int i, const char* s) ...@@ -350,7 +350,7 @@ void test_strncpy_array (Dest *pd, int i, const char* s)
} }
{ {
strncpy (pd->a5, "01234", sizeof pd->a5); /* { dg-bogus "truncated" "bug 81704" { xfail *-*-* } } */ strncpy (pd->a5, "01234", sizeof pd->a5); /* { dg-bogus "\\\[-Wstringop-truncation]" "bug 81704" { xfail *-*-* } } */
pd->a5[sizeof pd->a5 - 1] = '\0'; pd->a5[sizeof pd->a5 - 1] = '\0';
sink (pd); sink (pd);
} }
......
/* PR/tree-optimization/84480 - bogus -Wstringop-truncation despite
assignment with an inlined string literal
{ dg-do compile }
{ dg-options "-O2 -Wstringop-truncation" } */
#include <string.h>
template <size_t N>
class GoodString
{
public:
GoodString (const char *s, size_t slen = N)
{
if (slen > N)
slen = N;
strncpy (str, s, slen);
str[slen] = '\0';
}
private:
char str[N + 1];
};
void sink (void*);
void good_nowarn_size_m2 ()
{
GoodString<3> str ("12");
sink (&str);
}
void good_nowarn_size_m1 ()
{
GoodString<3> str ("123"); // { dg-bogus "\\\[-Wstringop-truncation]" }
sink (&str);
}
void good_nowarn_size_m1_var (const char* s)
{
GoodString<3> str (s); // { dg-bogus "\\\[-Wstringop-truncation]" }
sink (&str);
}
void call_good_nowarn_size_m1_var ()
{
good_nowarn_size_m1_var ("456");
}
template <size_t N>
class BadString1
{
public:
BadString1 (const char *s, size_t slen = N)
{
if (slen > N)
slen = N;
strncpy (str, s, slen);
}
private:
char str[N + 1];
};
void bad1_nowarn_size_m2 ()
{
BadString1<3> str ("12");
sink (&str);
}
template <size_t N>
class BadString2
{
public:
BadString2 (const char *s, size_t slen = N)
{
if (slen > N)
slen = N;
strncpy (str, s, slen); // { dg-warning "\\\[-Wstringop-truncation]" }
}
private:
char str[N + 1];
};
void bad2_warn_size_m1 ()
{
BadString2<3> str ("123");
sink (&str);
}
// { dg-message "inlined from .void bad2_warn_size_m1." "" { target *-*-* } 0 }
template <size_t N>
class BadString3
{
public:
BadString3 (const char *s, size_t slen = N)
{
if (slen > N)
slen = N;
strncpy (str, s, slen); // { dg-warning "\\\[-Wstringop-truncation]" }
}
private:
char str[N + 1];
};
void bad3_warn_size_m1_var (const char *s)
{
BadString3<3> str (s);
sink (&str);
}
void call_bad3_warn_size_m1_var ()
{
bad3_warn_size_m1_var ("456");
}
// { dg-message "inlined from .void call_bad3_warn_size_m1_var." "" { target *-*-* } 0 }
...@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see
#include "domwalk.h" #include "domwalk.h"
#include "tree-ssa-alias.h" #include "tree-ssa-alias.h"
#include "tree-ssa-propagate.h" #include "tree-ssa-propagate.h"
#include "tree-ssa-strlen.h"
#include "params.h" #include "params.h"
#include "ipa-chkp.h" #include "ipa-chkp.h"
#include "tree-hash-traits.h" #include "tree-hash-traits.h"
...@@ -1780,11 +1781,12 @@ is_strlen_related_p (tree src, tree len) ...@@ -1780,11 +1781,12 @@ is_strlen_related_p (tree src, tree len)
return false; return false;
} }
/* A helper of handle_builtin_stxncpy. Check to see if the specified /* Called by handle_builtin_stxncpy and by gimple_fold_builtin_strncpy
bound is a) equal to the size of the destination DST and if so, b) in gimple-fold.c.
if it's immediately followed by DST[CNT - 1] = '\0'. If a) holds Check to see if the specified bound is a) equal to the size of
and b) does not, warn. Otherwise, do nothing. Return true if the destination DST and if so, b) if it's immediately followed by
diagnostic has been issued. DST[CNT - 1] = '\0'. If a) holds and b) does not, warn. Otherwise,
do nothing. Return true if diagnostic has been issued.
The purpose is to diagnose calls to strncpy and stpncpy that do The purpose is to diagnose calls to strncpy and stpncpy that do
not nul-terminate the copy while allowing for the idiom where not nul-terminate the copy while allowing for the idiom where
...@@ -1795,7 +1797,7 @@ is_strlen_related_p (tree src, tree len) ...@@ -1795,7 +1797,7 @@ is_strlen_related_p (tree src, tree len)
a[sizeof a - 1] = '\0'; a[sizeof a - 1] = '\0';
*/ */
static bool bool
maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt) maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
{ {
gimple *stmt = gsi_stmt (gsi); gimple *stmt = gsi_stmt (gsi);
...@@ -1831,8 +1833,11 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt) ...@@ -1831,8 +1833,11 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
return false; return false;
/* Negative value is the constant string length. If it's less than /* Negative value is the constant string length. If it's less than
the lower bound there is no truncation. */ the lower bound there is no truncation. Avoid calling get_stridx()
int sidx = get_stridx (src); when ssa_ver_to_stridx is empty. That implies the caller isn't
running under the control of this pass and ssa_ver_to_stridx hasn't
been created yet. */
int sidx = ssa_ver_to_stridx.length () ? get_stridx (src) : 0;
if (sidx < 0 && wi::gtu_p (cntrange[0], ~sidx)) if (sidx < 0 && wi::gtu_p (cntrange[0], ~sidx))
return false; return false;
...@@ -1935,23 +1940,35 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt) ...@@ -1935,23 +1940,35 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
lenrange[0] = wi::shwi (0, prec); lenrange[0] = wi::shwi (0, prec);
} }
if (wi::geu_p (lenrange[0], cntrange[1])) gcall *call = as_a <gcall *> (stmt);
if (lenrange[0] == cntrange[1] && cntrange[0] == cntrange[1])
return warning_at (callloc, OPT_Wstringop_truncation,
(integer_onep (cnt)
? G_("%G%qD output truncated before terminating "
"nul copying %E byte from a string of the "
"same length")
: G_("%G%qD output truncated before terminating nul "
"copying %E bytes from a string of the same "
"length")),
call, func, cnt);
else if (wi::geu_p (lenrange[0], cntrange[1]))
{ {
/* The shortest string is longer than the upper bound of /* The shortest string is longer than the upper bound of
the count so the truncation is certain. */ the count so the truncation is certain. */
if (cntrange[0] == cntrange[1]) if (cntrange[0] == cntrange[1])
return warning_at (callloc, OPT_Wstringop_truncation, return warning_at (callloc, OPT_Wstringop_truncation,
integer_onep (cnt) integer_onep (cnt)
? G_("%qD output truncated copying %E byte " ? G_("%G%qD output truncated copying %E byte "
"from a string of length %wu") "from a string of length %wu")
: G_("%qD output truncated copying %E bytes " : G_("%G%qD output truncated copying %E bytes "
"from a string of length %wu"), "from a string of length %wu"),
func, cnt, lenrange[0].to_uhwi ()); call, func, cnt, lenrange[0].to_uhwi ());
return warning_at (callloc, OPT_Wstringop_truncation, return warning_at (callloc, OPT_Wstringop_truncation,
"%qD output truncated copying between %wu " "%G%qD output truncated copying between %wu "
"and %wu bytes from a string of length %wu", "and %wu bytes from a string of length %wu",
func, cntrange[0].to_uhwi (), call, func, cntrange[0].to_uhwi (),
cntrange[1].to_uhwi (), lenrange[0].to_uhwi ()); cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
} }
else if (wi::geu_p (lenrange[1], cntrange[1])) else if (wi::geu_p (lenrange[1], cntrange[1]))
...@@ -1961,16 +1978,16 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt) ...@@ -1961,16 +1978,16 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
if (cntrange[0] == cntrange[1]) if (cntrange[0] == cntrange[1])
return warning_at (callloc, OPT_Wstringop_truncation, return warning_at (callloc, OPT_Wstringop_truncation,
integer_onep (cnt) integer_onep (cnt)
? G_("%qD output may be truncated copying %E " ? G_("%G%qD output may be truncated copying %E "
"byte from a string of length %wu") "byte from a string of length %wu")
: G_("%qD output may be truncated copying %E " : G_("%G%qD output may be truncated copying %E "
"bytes from a string of length %wu"), "bytes from a string of length %wu"),
func, cnt, lenrange[1].to_uhwi ()); call, func, cnt, lenrange[1].to_uhwi ());
return warning_at (callloc, OPT_Wstringop_truncation, return warning_at (callloc, OPT_Wstringop_truncation,
"%qD output may be truncated copying between %wu " "%G%qD output may be truncated copying between %wu "
"and %wu bytes from a string of length %wu", "and %wu bytes from a string of length %wu",
func, cntrange[0].to_uhwi (), call, func, cntrange[0].to_uhwi (),
cntrange[1].to_uhwi (), lenrange[1].to_uhwi ()); cntrange[1].to_uhwi (), lenrange[1].to_uhwi ());
} }
...@@ -1982,9 +1999,9 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt) ...@@ -1982,9 +1999,9 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
the lower bound of the specified count but shorter than the the lower bound of the specified count but shorter than the
upper bound the copy may (but need not) be truncated. */ upper bound the copy may (but need not) be truncated. */
return warning_at (callloc, OPT_Wstringop_truncation, return warning_at (callloc, OPT_Wstringop_truncation,
"%qD output may be truncated copying between %wu " "%G%qD output may be truncated copying between "
"and %wu bytes from a string of length %wu", "%wu and %wu bytes from a string of length %wu",
func, cntrange[0].to_uhwi (), call, func, cntrange[0].to_uhwi (),
cntrange[1].to_uhwi (), lenrange[0].to_uhwi ()); cntrange[1].to_uhwi (), lenrange[0].to_uhwi ());
} }
} }
...@@ -2003,8 +2020,8 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt) ...@@ -2003,8 +2020,8 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
if (cntrange[0] == cntrange[1]) if (cntrange[0] == cntrange[1])
return warning_at (callloc, OPT_Wstringop_truncation, return warning_at (callloc, OPT_Wstringop_truncation,
"%qD specified bound %E equals destination size", "%G%qD specified bound %E equals destination size",
func, cnt); as_a <gcall *> (stmt), func, cnt);
} }
return false; return false;
...@@ -2103,14 +2120,15 @@ handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi) ...@@ -2103,14 +2120,15 @@ handle_builtin_stxncpy (built_in_function, gimple_stmt_iterator *gsi)
if (sisrc == silen if (sisrc == silen
&& is_strlen_related_p (src, len) && is_strlen_related_p (src, len)
&& warning_at (callloc, OPT_Wstringop_truncation, && warning_at (callloc, OPT_Wstringop_truncation,
"%qD output truncated before terminating nul " "%G%qD output truncated before terminating nul "
"copying as many bytes from a string as its length", "copying as many bytes from a string as its length",
func)) as_a <gcall *>(stmt), func))
warned = true; warned = true;
else if (silen && is_strlen_related_p (src, silen->ptr)) else if (silen && is_strlen_related_p (src, silen->ptr))
warned = warning_at (callloc, OPT_Wstringop_overflow_, warned = warning_at (callloc, OPT_Wstringop_overflow_,
"%qD specified bound depends on the length " "%G%qD specified bound depends on the length "
"of the source argument", func); "of the source argument",
as_a <gcall *>(stmt), func);
if (warned) if (warned)
{ {
location_t strlenloc = pss->second; location_t strlenloc = pss->second;
......
/* Declarations of tree-ssa-strlen API.
Copyright (C) 2018 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#ifndef GCC_TREE_SSA_STRLEN_H
#define GCC_TREE_SSA_STRLEN_H
extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
#endif // GCC_TREE_SSA_STRLEN_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment