aboutsummaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2018-06-18 22:17:57 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2018-06-18 16:17:57 -0600
commit4252ccd73701a330db365ccd39829e27d0d3b42d (patch)
tree18e21cecd1210c34cebb0fd5809861a217fbf0eb /gcc/calls.c
parent9e03592e40e7da85f9779ea1988a69f154d1ba7f (diff)
downloadgcc-4252ccd73701a330db365ccd39829e27d0d3b42d.zip
gcc-4252ccd73701a330db365ccd39829e27d0d3b42d.tar.gz
gcc-4252ccd73701a330db365ccd39829e27d0d3b42d.tar.bz2
PR middle-end/85602 - -Wsizeof-pointer-memaccess for strncat with size of source
gcc/c-family/ChangeLog: PR middle-end/85602 * c-warn.c (sizeof_pointer_memaccess_warning): Check for attribute nonstring. gcc/ChangeLog: PR middle-end/85602 * calls.c (maybe_warn_nonstring_arg): Handle strncat. * tree-ssa-strlen.c (is_strlen_related_p): Make extern. Handle integer subtraction. (maybe_diag_stxncpy_trunc): Handle nonstring source arguments. * tree-ssa-strlen.h (is_strlen_related_p): Declare. gcc/testsuite/ChangeLog: PR middle-end/85602 * gcc.dg/attr-nonstring-2.c: Adjust text of expected warning. * c-c++-common/attr-nonstring-8.c: New test. From-SVN: r261718
Diffstat (limited to 'gcc/calls.c')
-rw-r--r--gcc/calls.c84
1 files changed, 73 insertions, 11 deletions
diff --git a/gcc/calls.c b/gcc/calls.c
index 02562dd..1970f1c 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -49,6 +49,7 @@ along with GCC; see the file COPYING3. If not see
#include "rtl-iter.h"
#include "tree-vrp.h"
#include "tree-ssanames.h"
+#include "tree-ssa-strlen.h"
#include "intl.h"
#include "stringpool.h"
#include "attribs.h"
@@ -1627,8 +1628,10 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
/* It's safe to call "bounded" string functions with a non-string
argument since the functions provide an explicit bound for this
- purpose. */
- switch (DECL_FUNCTION_CODE (fndecl))
+ purpose. The exception is strncat where the bound may refer to
+ either the destination or the source. */
+ int fncode = DECL_FUNCTION_CODE (fndecl);
+ switch (fncode)
{
case BUILT_IN_STRCMP:
case BUILT_IN_STRNCMP:
@@ -1648,6 +1651,7 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
}
/* Fall through. */
+ case BUILT_IN_STRNCAT:
case BUILT_IN_STPNCPY:
case BUILT_IN_STRNCPY:
if (2 < nargs)
@@ -1772,15 +1776,36 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
if (!decl)
continue;
- tree type = TREE_TYPE (decl);
-
/* The maximum number of array elements accessed. */
offset_int wibnd = 0;
- if (bndrng[0])
+
+ if (argno && fncode == BUILT_IN_STRNCAT)
+ {
+ /* See if the bound in strncat is derived from the length
+ of the strlen of the destination (as it's expected to be).
+ If so, reset BOUND and FNCODE to trigger a warning. */
+ tree dstarg = CALL_EXPR_ARG (exp, 0);
+ if (is_strlen_related_p (dstarg, bound))
+ {
+ /* The bound applies to the destination, not to the source,
+ so reset these to trigger a warning without mentioning
+ the bound. */
+ bound = NULL;
+ fncode = 0;
+ }
+ else if (bndrng[1])
+ /* Use the upper bound of the range for strncat. */
+ wibnd = wi::to_offset (bndrng[1]);
+ }
+ else if (bndrng[0])
+ /* Use the lower bound of the range for functions other than
+ strncat. */
wibnd = wi::to_offset (bndrng[0]);
- /* Size of the array. */
+ /* Determine the size of the argument array if it is one. */
offset_int asize = wibnd;
+ bool known_size = false;
+ tree type = TREE_TYPE (decl);
/* Determine the array size. For arrays of unknown bound and
pointers reset BOUND to trigger the appropriate warning. */
@@ -1789,7 +1814,10 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
if (tree arrbnd = TYPE_DOMAIN (type))
{
if ((arrbnd = TYPE_MAX_VALUE (arrbnd)))
- asize = wi::to_offset (arrbnd) + 1;
+ {
+ asize = wi::to_offset (arrbnd) + 1;
+ known_size = true;
+ }
}
else if (bound == void_type_node)
bound = NULL_TREE;
@@ -1797,13 +1825,47 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
else if (bound == void_type_node)
bound = NULL_TREE;
+ /* In a call to strncat with a bound in a range whose lower but
+ not upper bound is less than the array size, reset ASIZE to
+ be the same as the bound and the other variable to trigger
+ the apprpriate warning below. */
+ if (fncode == BUILT_IN_STRNCAT
+ && bndrng[0] != bndrng[1]
+ && wi::ltu_p (wi::to_offset (bndrng[0]), asize)
+ && (!known_size
+ || wi::ltu_p (asize, wibnd)))
+ {
+ asize = wibnd;
+ bound = NULL_TREE;
+ fncode = 0;
+ }
+
bool warned = false;
if (wi::ltu_p (asize, wibnd))
- warned = warning_at (loc, OPT_Wstringop_overflow_,
- "%qD argument %i declared attribute %<nonstring%> "
- "is smaller than the specified bound %E",
- fndecl, argno + 1, bndrng[0]);
+ {
+ if (bndrng[0] == bndrng[1])
+ warned = warning_at (loc, OPT_Wstringop_overflow_,
+ "%qD argument %i declared attribute "
+ "%<nonstring%> is smaller than the specified "
+ "bound %wu",
+ fndecl, argno + 1, wibnd.to_uhwi ());
+ else if (wi::ltu_p (asize, wi::to_offset (bndrng[0])))
+ warned = warning_at (loc, OPT_Wstringop_overflow_,
+ "%qD argument %i declared attribute "
+ "%<nonstring%> is smaller than "
+ "the specified bound [%E, %E]",
+ fndecl, argno + 1, bndrng[0], bndrng[1]);
+ else
+ warned = warning_at (loc, OPT_Wstringop_overflow_,
+ "%qD argument %i declared attribute "
+ "%<nonstring%> may be smaller than "
+ "the specified bound [%E, %E]",
+ fndecl, argno + 1, bndrng[0], bndrng[1]);
+ }
+ else if (fncode == BUILT_IN_STRNCAT)
+ ; /* Avoid warning for calls to strncat() when the bound
+ is equal to the size of the non-string argument. */
else if (!bound)
warned = warning_at (loc, OPT_Wstringop_overflow_,
"%qD argument %i declared attribute %<nonstring%>",