diff options
author | Martin Sebor <msebor@redhat.com> | 2021-03-08 13:28:52 -0700 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2021-03-08 13:28:52 -0700 |
commit | 7f5ff78ff3f971c11ec67f422b2fd34281db9123 (patch) | |
tree | b7458cb5524353d63a17efea75f21868f8259978 /gcc/tree-ssa-strlen.c | |
parent | b64551af5159ea30b5941ddd430001b13936822c (diff) | |
download | gcc-7f5ff78ff3f971c11ec67f422b2fd34281db9123.zip gcc-7f5ff78ff3f971c11ec67f422b2fd34281db9123.tar.gz gcc-7f5ff78ff3f971c11ec67f422b2fd34281db9123.tar.bz2 |
PR middle-end/97631 - bogus "writing one too many bytes" warning for memcpy with strlen argument
gcc/ChangeLog:
PR middle-end/97631
* tree-ssa-strlen.c (maybe_warn_overflow): Test rawmem.
(handle_builtin_stxncpy_strncat): Rename locals. Determine
destination size from allocation calls. Issue a more appropriate
kind of warning.
(handle_builtin_memcpy): Pass true as rawmem to maybe_warn_overflow.
(handle_builtin_memset): Same.
gcc/testsuite/ChangeLog:
PR middle-end/97631
* c-c++-common/Wstringop-overflow.c: Remove unexpected warnings.
Add an xfail.
* c-c++-common/Wstringop-truncation.c: Add expected warnings.
* gcc.dg/Wstringop-overflow-10.c: Also enable -Wstringop-truncation.
* gcc.dg/Wstringop-overflow-66.c: New test.
* gcc.dg/tree-ssa/strncpy-2.c: Adjust expected warning.
Diffstat (limited to 'gcc/tree-ssa-strlen.c')
-rw-r--r-- | gcc/tree-ssa-strlen.c | 60 |
1 files changed, 37 insertions, 23 deletions
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index 8912a11..cccd4a0 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -1992,17 +1992,12 @@ maybe_warn_overflow (gimple *stmt, tree len, pointer_query &ptr_qry, && wi::leu_p (lenrng[1], spcrng[1])) return; - if (lenrng[0] == spcrng[1] - && (len != destsize - || !si || !is_strlen_related_p (si->ptr, len))) - return; - location_t loc = gimple_or_expr_nonartificial_location (stmt, dest); bool warned = false; if (wi::leu_p (lenrng[0], spcrng[1])) { if (len != destsize - && (!si || !is_strlen_related_p (si->ptr, len))) + && (!si || rawmem || !is_strlen_related_p (si->ptr, len))) return; warned = (writefn @@ -3083,7 +3078,12 @@ handle_builtin_stxncpy_strncat (bool append_p, gimple_stmt_iterator *gsi) tree dst = gimple_call_arg (stmt, 0); tree src = gimple_call_arg (stmt, 1); tree len = gimple_call_arg (stmt, 2); - tree dstsize = NULL_TREE, srcsize = NULL_TREE; + /* An upper bound of the size of the destination. */ + tree dstsize = NULL_TREE; + /* The length of the destination and source strings (plus 1 for those + whose FULL_STRING_P is set, i.e., whose length is exact rather than + a lower bound). */ + tree dstlenp1 = NULL_TREE, srclenp1 = NULL_TREE;; int didx = get_stridx (dst); if (strinfo *sidst = didx > 0 ? get_strinfo (didx) : NULL) @@ -3096,11 +3096,16 @@ handle_builtin_stxncpy_strncat (bool append_p, gimple_stmt_iterator *gsi) { /* String is known to be nul-terminated. */ tree type = TREE_TYPE (sidst->nonzero_chars); - dstsize = fold_build2 (PLUS_EXPR, type, sidst->nonzero_chars, + dstlenp1 = fold_build2 (PLUS_EXPR, type, sidst->nonzero_chars, build_int_cst (type, 1)); } else - dstsize = sidst->nonzero_chars; + dstlenp1 = sidst->nonzero_chars; + } + else if (TREE_CODE (sidst->ptr) == SSA_NAME) + { + gimple *def_stmt = SSA_NAME_DEF_STMT (sidst->ptr); + dstsize = gimple_call_alloc_size (def_stmt); } dst = sidst->ptr; @@ -3121,19 +3126,19 @@ handle_builtin_stxncpy_strncat (bool append_p, gimple_stmt_iterator *gsi) if (sisrc->full_string_p) { tree type = TREE_TYPE (sisrc->nonzero_chars); - srcsize = fold_build2 (PLUS_EXPR, type, sisrc->nonzero_chars, + srclenp1 = fold_build2 (PLUS_EXPR, type, sisrc->nonzero_chars, build_int_cst (type, 1)); } else - srcsize = sisrc->nonzero_chars; + srclenp1 = sisrc->nonzero_chars; } src = sisrc->ptr; } else - srcsize = NULL_TREE; + srclenp1 = NULL_TREE; - if (check_bounds_or_overlap (stmt, dst, src, dstsize, srcsize)) + if (check_bounds_or_overlap (stmt, dst, src, dstlenp1, srclenp1)) { gimple_set_no_warning (stmt, true); return; @@ -3165,9 +3170,10 @@ handle_builtin_stxncpy_strncat (bool append_p, gimple_stmt_iterator *gsi) /* When -Wstringop-truncation is set, try to determine truncation before diagnosing possible overflow. Truncation is implied by the LEN argument being equal to strlen(SRC), regardless of - whether its value is known. Otherwise, issue the more generic - -Wstringop-overflow which triggers for LEN arguments that in - any meaningful way depend on strlen(SRC). */ + whether its value is known. Otherwise, when appending, or + when copying into a destination of known size, issue the more + generic -Wstringop-overflow which triggers for LEN arguments + that in any meaningful way depend on strlen(SRC). */ if (!append_p && sisrc == silen && is_strlen_related_p (src, len) @@ -3176,11 +3182,19 @@ handle_builtin_stxncpy_strncat (bool append_p, gimple_stmt_iterator *gsi) "copying as many bytes from a string as its length", stmt, func)) warned = true; - else if (silen && is_strlen_related_p (src, silen->ptr)) - warned = warning_at (callloc, OPT_Wstringop_overflow_, - "%G%qD specified bound depends on the length " - "of the source argument", - stmt, func); + else if ((append_p || !dstsize || len == dstlenp1) + && silen && is_strlen_related_p (src, silen->ptr)) + { + /* Issue -Wstringop-overflow when appending or when writing into + a destination of a known size. Otherwise, when copying into + a destination of an unknown size, it's truncation. */ + int opt = (append_p || dstsize + ? OPT_Wstringop_overflow_ : OPT_Wstringop_truncation); + warned = warning_at (callloc, opt, + "%G%qD specified bound depends on the length " + "of the source argument", + stmt, func); + } if (warned) { location_t strlenloc = pss->second; @@ -3216,7 +3230,7 @@ handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi, if (olddsi != NULL && !integer_zerop (len)) { - maybe_warn_overflow (stmt, len, ptr_qry, olddsi, false, false); + maybe_warn_overflow (stmt, len, ptr_qry, olddsi, false, true); adjust_last_stmt (olddsi, stmt, false, ptr_qry); } @@ -3684,7 +3698,7 @@ handle_builtin_memset (gimple_stmt_iterator *gsi, bool *zero_write, tree memset_size = gimple_call_arg (memset_stmt, 2); /* Check for overflow. */ - maybe_warn_overflow (memset_stmt, memset_size, ptr_qry, NULL, false, false); + maybe_warn_overflow (memset_stmt, memset_size, ptr_qry, NULL, false, true); /* Bail when there is no statement associated with the destination (the statement may be null even when SI1->ALLOC is not). */ |