aboutsummaryrefslogtreecommitdiff
path: root/gcc/calls.c
diff options
context:
space:
mode:
authormsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>2018-05-22 17:45:35 +0000
committermsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>2018-05-22 17:45:35 +0000
commit974404bd0c5965ee896378a4d9f37be6ec6366a2 (patch)
tree8bcb9d057f75ddb91c415569f50789f538e99968 /gcc/calls.c
parent30370ebb0134b7d9279c88b497139a0b7ab7db7d (diff)
PR c/85623 - strncmp() warns about attribute 'nonstring' incorrectly in -Wstringop-overflow
gcc/ChangeLog: PR c/85623 * calls.c (maybe_warn_nonstring_arg): Use string length to set or ajust the presumed bound on an operation to avoid unnecessary warnings. gcc/testsuite/ChangeLog: PR c/85623 * c-c++-common/attr-nonstring-3.c: Adjust. * c-c++-common/attr-nonstring-4.c: Adjust. * c-c++-common/attr-nonstring-6.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@260541 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/calls.c')
-rw-r--r--gcc/calls.c73
1 files changed, 66 insertions, 7 deletions
diff --git a/gcc/calls.c b/gcc/calls.c
index f0e9d3b1cbb..d2eecf139e0 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -55,6 +55,7 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "builtins.h"
+#include "gimple-fold.h"
/* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */
#define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
@@ -1616,15 +1617,36 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
/* The bound argument to a bounded string function like strncpy. */
tree bound = NULL_TREE;
+ /* The range of lengths of a string argument to one of the comparison
+ functions. If the length is less than the bound it is used instead. */
+ tree lenrng[2] = { NULL_TREE, NULL_TREE };
+
/* 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))
{
- case BUILT_IN_STPNCPY:
- case BUILT_IN_STPNCPY_CHK:
+ case BUILT_IN_STRCMP:
case BUILT_IN_STRNCMP:
case BUILT_IN_STRNCASECMP:
+ {
+ /* For these, if one argument refers to one or more of a set
+ of string constants or arrays of known size, determine
+ the range of their known or possible lengths and use it
+ conservatively as the bound for the unbounded function,
+ and to adjust the range of the bound of the bounded ones. */
+ unsigned stride = with_bounds ? 2 : 1;
+ for (unsigned argno = 0; argno < nargs && !*lenrng; argno += stride)
+ {
+ tree arg = CALL_EXPR_ARG (exp, argno);
+ if (!get_attr_nonstring_decl (arg))
+ get_range_strlen (arg, lenrng);
+ }
+ }
+ /* Fall through. */
+
+ case BUILT_IN_STPNCPY:
+ case BUILT_IN_STPNCPY_CHK:
case BUILT_IN_STRNCPY:
case BUILT_IN_STRNCPY_CHK:
{
@@ -1651,6 +1673,33 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
if (bound)
get_size_range (bound, bndrng);
+ if (*lenrng)
+ {
+ /* Add one for the nul. */
+ lenrng[0] = const_binop (PLUS_EXPR, TREE_TYPE (lenrng[0]),
+ lenrng[0], size_one_node);
+ lenrng[1] = const_binop (PLUS_EXPR, TREE_TYPE (lenrng[1]),
+ lenrng[1], size_one_node);
+
+ if (!bndrng[0])
+ {
+ /* Conservatively use the upper bound of the lengths for
+ both the lower and the upper bound of the operation. */
+ bndrng[0] = lenrng[1];
+ bndrng[1] = lenrng[1];
+ bound = void_type_node;
+ }
+ else
+ {
+ /* Replace the bound on the oparation with the upper bound
+ of the length of the string if the latter is smaller. */
+ if (tree_int_cst_lt (lenrng[1], bndrng[0]))
+ bndrng[0] = lenrng[1];
+ else if (tree_int_cst_lt (lenrng[1], bndrng[1]))
+ bndrng[1] = lenrng[1];
+ }
+ }
+
/* Iterate over the built-in function's formal arguments and check
each const char* against the actual argument. If the actual
argument is declared attribute non-string issue a warning unless
@@ -1693,18 +1742,28 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp)
tree type = TREE_TYPE (decl);
+ /* The maximum number of array elements accessed. */
offset_int wibnd = 0;
if (bndrng[0])
wibnd = wi::to_offset (bndrng[0]);
+ /* Size of the array. */
offset_int asize = wibnd;
+ /* Determine the array size. For arrays of unknown bound and
+ pointers reset BOUND to trigger the appropriate warning. */
if (TREE_CODE (type) == ARRAY_TYPE)
- if (tree arrbnd = TYPE_DOMAIN (type))
- {
- if ((arrbnd = TYPE_MAX_VALUE (arrbnd)))
- asize = wi::to_offset (arrbnd) + 1;
- }
+ {
+ if (tree arrbnd = TYPE_DOMAIN (type))
+ {
+ if ((arrbnd = TYPE_MAX_VALUE (arrbnd)))
+ asize = wi::to_offset (arrbnd) + 1;
+ }
+ else if (bound == void_type_node)
+ bound = NULL_TREE;
+ }
+ else if (bound == void_type_node)
+ bound = NULL_TREE;
location_t loc = EXPR_LOCATION (exp);