diff options
author | msebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4> | 2018-05-22 17:45:35 +0000 |
---|---|---|
committer | msebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4> | 2018-05-22 17:45:35 +0000 |
commit | 974404bd0c5965ee896378a4d9f37be6ec6366a2 (patch) | |
tree | 8bcb9d057f75ddb91c415569f50789f538e99968 /gcc/calls.c | |
parent | 30370ebb0134b7d9279c88b497139a0b7ab7db7d (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.c | 73 |
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); |