diff options
author | Martin Sebor <msebor@redhat.com> | 2018-06-18 22:17:57 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2018-06-18 16:17:57 -0600 |
commit | 4252ccd73701a330db365ccd39829e27d0d3b42d (patch) | |
tree | 18e21cecd1210c34cebb0fd5809861a217fbf0eb /gcc/calls.c | |
parent | 9e03592e40e7da85f9779ea1988a69f154d1ba7f (diff) | |
download | gcc-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.c | 84 |
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%>", |