diff options
author | Martin Sebor <msebor@redhat.com> | 2020-08-28 13:13:28 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2020-08-28 13:18:28 -0600 |
commit | d14c547abd484d3540b692bb8048c4a6efe92c8b (patch) | |
tree | d3ba650daec2ba98a7b37f8f98ca5ef42c994ae9 /gcc/calls.c | |
parent | 26c24398d3615aef43e599f87911c1ecc3bd2841 (diff) | |
download | gcc-d14c547abd484d3540b692bb8048c4a6efe92c8b.zip gcc-d14c547abd484d3540b692bb8048c4a6efe92c8b.tar.gz gcc-d14c547abd484d3540b692bb8048c4a6efe92c8b.tar.bz2 |
Add -Wstringop-overread for reading past the end by string functions.
gcc/ChangeLog:
* attribs.c (init_attr_rdwr_indices): Use global access_mode.
* attribs.h (struct attr_access): Same.
* builtins.c (fold_builtin_strlen): Add argument.
(compute_objsize): Declare.
(get_range): Declare.
(check_read_access): New function.
(access_ref::access_ref): Define ctor.
(warn_string_no_nul): Add arguments. Handle -Wstrintop-overread.
(check_nul_terminated_array): Handle source strings of different
ranges of sizes.
(expand_builtin_strlen): Remove warning code, call check_read_access
instead. Declare locals closer to their initialization.
(expand_builtin_strnlen): Same.
(maybe_warn_for_bound): New function.
(warn_for_access): Remove argument. Handle -Wstrintop-overread.
(inform_access): Change argument type.
(get_size_range): New function.
(check_access): Remove unused arguments. Add new arguments. Handle
-Wstrintop-overread. Move warning code to helpers and call them.
Call check_nul_terminated_array.
(check_memop_access): Remove unnecessary and provide additional
arguments in calls.
(expand_builtin_memchr): Call check_read_access.
(expand_builtin_strcat): Remove unnecessary and provide additional
arguments in calls.
(expand_builtin_strcpy): Same.
(expand_builtin_strcpy_args): Same. Avoid testing no-warning bit.
(expand_builtin_stpcpy_1): Remove unnecessary and provide additional
arguments in calls.
(expand_builtin_stpncpy): Same.
(check_strncat_sizes): Same.
(expand_builtin_strncat): Remove unnecessary and provide additional
arguments in calls. Adjust comments.
(expand_builtin_strncpy): Remove unnecessary and provide additional
arguments in calls.
(expand_builtin_memcmp): Remove warning code. Call check_access.
(expand_builtin_strcmp): Call check_access instead of
check_nul_terminated_array.
(expand_builtin_strncmp): Handle -Wstrintop-overread.
(expand_builtin_fork_or_exec): Call check_access instead of
check_nul_terminated_array.
(expand_builtin): Same.
(fold_builtin_1): Pass additional argument.
(fold_builtin_n): Same.
(fold_builtin_strpbrk): Remove calls to check_nul_terminated_array.
(expand_builtin_memory_chk): Add comments.
(maybe_emit_chk_warning): Remove unnecessary and provide additional
arguments in calls.
(maybe_emit_sprintf_chk_warning): Same. Adjust comments.
* builtins.h (warn_string_no_nul): Add arguments.
(struct access_ref): Add member and ctor argument.
(struct access_data): Add members and ctor.
(check_access): Adjust signature.
* calls.c (maybe_warn_nonstring_arg): Return an indication of
whether a warning was issued. Issue -Wstrintop-overread instead
of -Wstringop-overflow.
(append_attrname): Adjust to naming changes.
(maybe_warn_rdwr_sizes): Same. Remove unnecessary and provide
additional arguments in calls.
* calls.h (maybe_warn_nonstring_arg): Return bool.
* doc/invoke.texi (-Wstringop-overread): Document new option.
* gimple-fold.c (gimple_fold_builtin_strcpy): Provide an additional
argument in call.
(gimple_fold_builtin_stpcpy): Same.
* tree-ssa-uninit.c (maybe_warn_pass_by_reference): Adjust to naming
changes.
* tree.h (enum access_mode): New type.
gcc/c-family/ChangeLog:
* c.opt (Wstringop-overread): New option.
gcc/testsuite/ChangeLog:
* c-c++-common/Warray-bounds-7.c: Adjust expected warnings.
* c-c++-common/Wrestrict.c: Remove xfail.
* c-c++-common/attr-nonstring-3.c: Adjust text of expected warnings.
* c-c++-common/attr-nonstring-6.c: Suppress -Wstringop-overread
instead of -Wstringop-overflow.
* c-c++-common/attr-nonstring-8.c: Adjust text of expected warnings.
* g++.dg/torture/Wsizeof-pointer-memaccess1.C: Also suppress
-Wstringop-overread.
* g++.dg/torture/Wsizeof-pointer-memaccess2.C: Same.
* gcc.dg/Warray-bounds-39.c: Adjust expected warnings.
* gcc.dg/Warray-bounds-40.c: Also suppress -Wstringop-overread.
* gcc.dg/Warray-bounds-58.c: Remove xfail. Also expect
-Wstringop-overread. Adjust text of expected warnings.
* gcc.dg/Wsizeof-pointer-memaccess1.c: Also suppress
-Wstringop-overread.
* gcc.dg/Wstringop-overflow-22.c: Adjust text of expected warnings.
* gcc.dg/Wstringop-overflow-33.c: Expect -Wstringop-overread.
* gcc.dg/Wstringop-overflow-9.c: Expect -Wstringop-overread.
* gcc.dg/attr-nonstring-2.c: Adjust text of expected warnings.
* gcc.dg/attr-nonstring-3.c: Same.
* gcc.dg/attr-nonstring-4.c: Same.
* gcc.dg/attr-nonstring.c: Expect -Wstringop-overread.
* gcc.dg/builtin-stringop-chk-5.c: Adjust comment.
* gcc.dg/builtin-stringop-chk-8.c: Enable -Wstringop-overread instead
of -Wstringop-overflow.
* gcc.dg/pr78902.c: Also expect -Wstringop-overread.
* gcc.dg/pr79214.c: Adjust text of expected warnings.
* gcc.dg/strcmpopt_10.c: Suppress valid -Wno-stringop-overread.
* gcc.dg/strlenopt-57.c: Also expect -Wstringop-overread.
* gcc.dg/torture/Wsizeof-pointer-memaccess1.c: Also suppress valid
-Wno-stringop-overread.
* gcc.dg/tree-ssa/builtins-folding-gimple-ub.c: Same.
* gcc.dg/uninit-33.c: Same.
* gcc.dg/warn-strnlen-no-nul-2.c: Adjust text of expected warning.
* gcc.dg/warn-strnlen-no-nul.c: Same.
* gcc.target/i386/strcmpopt_6.c: Suppress -Wstringop-overread.
* gcc.dg/Wstringop-overread-2.c: New test.
* gcc.dg/Wstringop-overread.c: New test.
Diffstat (limited to 'gcc/calls.c')
-rw-r--r-- | gcc/calls.c | 79 |
1 files changed, 47 insertions, 32 deletions
diff --git a/gcc/calls.c b/gcc/calls.c index a11da66..8ac94db 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1274,7 +1274,7 @@ get_size_range (tree exp, tree range[2], bool allow_zero /* = false */) if (range_type == VR_VARYING) { if (integral) - { + { /* Use the full range of the type of the expression when no value range information is available. */ range[0] = TYPE_MIN_VALUE (exptype); @@ -1559,22 +1559,23 @@ get_attr_nonstring_decl (tree expr, tree *ref) return NULL_TREE; } -/* Warn about passing a non-string array/pointer to a function that - expects a nul-terminated string argument. */ +/* Warn about passing a non-string array/pointer to a built-in function + that expects a nul-terminated string argument. Returns true if + a warning has been issued.*/ -void +bool maybe_warn_nonstring_arg (tree fndecl, tree exp) { if (!fndecl || !fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)) - return; + return false; - if (TREE_NO_WARNING (exp) || !warn_stringop_overflow) - return; + if (TREE_NO_WARNING (exp) || !warn_stringop_overread) + return false; /* Avoid clearly invalid calls (more checking done below). */ unsigned nargs = call_expr_nargs (exp); if (!nargs) - return; + return false; /* The bound argument to a bounded string function like strncpy. */ tree bound = NULL_TREE; @@ -1666,22 +1667,27 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp) if (bndrng[0]) { - /* Diagnose excessive bound prior the adjustment below and + /* Diagnose excessive bound prior to the adjustment below and regardless of attribute nonstring. */ tree maxobjsize = max_object_size (); if (tree_int_cst_lt (maxobjsize, bndrng[0])) { + bool warned = false; if (tree_int_cst_equal (bndrng[0], bndrng[1])) - warning_at (loc, OPT_Wstringop_overflow_, - "%K%qD specified bound %E " - "exceeds maximum object size %E", - exp, fndecl, bndrng[0], maxobjsize); + warned = warning_at (loc, OPT_Wstringop_overread, + "%K%qD specified bound %E " + "exceeds maximum object size %E", + exp, fndecl, bndrng[0], maxobjsize); else - warning_at (loc, OPT_Wstringop_overflow_, - "%K%qD specified bound [%E, %E] " - "exceeds maximum object size %E", - exp, fndecl, bndrng[0], bndrng[1], maxobjsize); - return; + warned = warning_at (loc, OPT_Wstringop_overread, + "%K%qD specified bound [%E, %E] " + "exceeds maximum object size %E", + exp, fndecl, bndrng[0], bndrng[1], + maxobjsize); + if (warned) + TREE_NO_WARNING (exp) = true; + + return warned; } } @@ -1710,6 +1716,7 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp) } } + bool any_arg_warned = false; /* 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 @@ -1820,19 +1827,19 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp) if (wi::ltu_p (asize, wibnd)) { if (bndrng[0] == bndrng[1]) - warned = warning_at (loc, OPT_Wstringop_overflow_, + warned = warning_at (loc, OPT_Wstringop_overread, "%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_, + warned = warning_at (loc, OPT_Wstringop_overread, "%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_, + warned = warning_at (loc, OPT_Wstringop_overread, "%qD argument %i declared attribute " "%<nonstring%> may be smaller than " "the specified bound [%E, %E]", @@ -1842,14 +1849,22 @@ maybe_warn_nonstring_arg (tree fndecl, tree exp) ; /* 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_, + warned = warning_at (loc, OPT_Wstringop_overread, "%qD argument %i declared attribute %<nonstring%>", fndecl, argno + 1); if (warned) - inform (DECL_SOURCE_LOCATION (decl), - "argument %qD declared here", decl); + { + inform (DECL_SOURCE_LOCATION (decl), + "argument %qD declared here", decl); + any_arg_warned = true; + } } + + if (any_arg_warned) + TREE_NO_WARNING (exp) = true; + + return any_arg_warned; } /* Issue an error if CALL_EXPR was flagged as requiring @@ -1896,11 +1911,11 @@ append_attrname (const std::pair<int, attr_access> &access, size_t len = strlen (attrstr); const char* const atname - = (access.second.mode == attr_access::read_only + = (access.second.mode == access_read_only ? "read_only" - : (access.second.mode == attr_access::write_only + : (access.second.mode == access_write_only ? "write_only" - : (access.second.mode == attr_access::read_write + : (access.second.mode == access_read_write ? "read_write" : "none"))); const char *sep = len ? ", " : ""; @@ -2045,7 +2060,7 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp) tree objsize = compute_objsize (ptr, 0); tree srcsize; - if (access.second.mode == attr_access::write_only) + if (access.second.mode == access_write_only) { /* For a write-only argument there is no source. */ srcsize = NULL_TREE; @@ -2055,8 +2070,8 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp) /* For read-only and read-write attributes also set the source size. */ srcsize = objsize; - if (access.second.mode == attr_access::read_only - || access.second.mode == attr_access::none) + if (access.second.mode == access_read_only + || access.second.mode == access_none) { /* For a read-only attribute there is no destination so clear OBJSIZE. This emits "reading N bytes" kind of @@ -2070,8 +2085,8 @@ maybe_warn_rdwr_sizes (rdwr_map *rwm, tree fndecl, tree fntype, tree exp) iteration so that accesses via different arguments are diagnosed. */ TREE_NO_WARNING (exp) = false; - check_access (exp, NULL_TREE, NULL_TREE, size, /*maxread=*/ NULL_TREE, - srcsize, objsize, access.second.mode != attr_access::none); + check_access (exp, size, /*maxread=*/ NULL_TREE, srcsize, objsize, + access.second.mode); if (TREE_NO_WARNING (exp)) /* If check_access issued a warning above, append the relevant |