From: Martin Sebor Date: Mon, 25 Jun 2018 20:33:28 +0000 (+0000) Subject: PR tree-optimization/85700 - Spurious -Wstringop-truncation warning with strncat X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=eec5f615cbad2de5ff10fbaa8c92f68cc5c6be00;p=gcc.git PR tree-optimization/85700 - Spurious -Wstringop-truncation warning with strncat gcc/ChangeLog: PR tree-optimization/85700 * gimple-fold.c (gimple_fold_builtin_strncat): Adjust comment. * tree-ssa-strlen.c (is_strlen_related_p): Handle integer subtraction. (maybe_diag_stxncpy_trunc): Distinguish strncat from strncpy. gcc/testsuite/ChangeLog: PR tree-optimization/85700 * gcc.dg/Wstringop-truncation-4.c: New test. From-SVN: r262110 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 07db821bf57..5334c36708d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2018-06-25 Martin Sebor + + PR tree-optimization/85700 + * gimple-fold.c (gimple_fold_builtin_strncat): Adjust comment. + * tree-ssa-strlen.c (is_strlen_related_p): Handle integer subtraction. + (maybe_diag_stxncpy_trunc): Distinguish strncat from strncpy. + 2018-06-25 Martin Sebor * doc/extend.texi (Zero-length arrays): Update and clarify. diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index a01bce7ab08..b02593596bf 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -2051,10 +2051,12 @@ gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi) if (!nowarn && cmpsrc == 0) { tree fndecl = gimple_call_fndecl (stmt); - - /* To avoid certain truncation the specified bound should also - not be equal to (or less than) the length of the source. */ location_t loc = gimple_location (stmt); + + /* To avoid possible overflow the specified bound should also + not be equal to the length of the source, even when the size + of the destination is unknown (it's not an uncommon mistake + to specify as the bound to strncpy the length of the source). */ if (warning_at (loc, OPT_Wstringop_overflow_, "%G%qD specified bound %E equals source length", stmt, fndecl, len)) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f2d9caffc0e..46064749e3f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2018-06-25 Martin Sebor + + PR tree-optimization/85700 + * gcc.dg/Wstringop-truncation-4.c: New test. + 2018-06-25 Fritz Reese PR fortran/82972 diff --git a/gcc/testsuite/gcc.dg/Wstringop-truncation-4.c b/gcc/testsuite/gcc.dg/Wstringop-truncation-4.c new file mode 100644 index 00000000000..f3948637d10 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-truncation-4.c @@ -0,0 +1,63 @@ +/* PR tree-optimization/85700 - Spurious -Wstringop-truncation warning + with strncat + { dg-do compile } + { dg-options "-O2 -Wno-stringop-overflow -Wstringop-truncation -ftrack-macro-expansion=0" } */ + +#define NOIPA __attribute__ ((noipa)) +#define strncat __builtin_strncat +#define strlen __builtin_strlen + +extern char a4[4], b4[4], ax[]; + +NOIPA void cat_a4_s1_1 (void) +{ + /* There is no truncation here but since the bound of 1 equals + the length of the source string it's likely a mistake that + could cause overflow so it's diagnosed by -Wstringop-overflow */ + strncat (a4, "1", 1); +} + +NOIPA void cat_a4_s1_2 (void) +{ + strncat (a4, "1", 2); +} + +NOIPA void cat_a4_s1_3 (void) +{ + strncat (a4, "1", 3); +} + +NOIPA void cat_a4_s1_4 (void) +{ + /* There is no truncation here but since the bound of 1 equals + the length of the source string it's likely a mistake that + could cause overflow so it's diagnosed by -Wstringop-overflow */ + strncat (a4, "1", 4); +} + +NOIPA void cat_a4_s1_5 (void) +{ + /* A bound in excess of the destination size is diagnosed by + -Wstringop-overflow. */ + strncat (a4, "1", 5); +} + +NOIPA void cat_a4_s1_dlen (void) +{ + strncat (a4, "1", sizeof a4 - strlen (a4) - 1); +} + +NOIPA void cat_a4_s2_dlen (void) +{ + strncat (a4, "12", sizeof a4 - strlen (a4) - 1); /* { dg-bogus "\\\[-Wstringop-truncation]" } */ +} + +NOIPA void cat_a4_b4_dlen (void) +{ + strncat (a4, b4, sizeof a4 - strlen (a4) - 1); /* { dg-bogus "\\\[-Wstringop-truncation]" } */ +} + +NOIPA void cat_ax_b4_dlen (void) +{ + strncat (ax, b4, 32 - strlen (ax) - 1); /* { dg-bogus "\\\[-Wstringop-truncation]" } */ +} diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index 92545b9ce4d..2da82a878e3 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -2014,6 +2014,12 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt) gcall *call = as_a (stmt); + /* Set to true for strncat whose bound is derived from the length + of the destination (the expected usage pattern). */ + bool cat_dstlen_bounded = false; + if (DECL_FUNCTION_CODE (func) == BUILT_IN_STRNCAT) + cat_dstlen_bounded = is_strlen_related_p (dst, cnt); + if (lenrange[0] == cntrange[1] && cntrange[0] == cntrange[1]) return warning_n (callloc, OPT_Wstringop_truncation, cntrange[0].to_uhwi (), @@ -2024,46 +2030,50 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt) "copying %E bytes from a string of the same " "length", call, func, cnt); - else if (wi::geu_p (lenrange[0], cntrange[1])) - { - /* The shortest string is longer than the upper bound of - the count so the truncation is certain. */ - if (cntrange[0] == cntrange[1]) - return warning_n (callloc, OPT_Wstringop_truncation, - cntrange[0].to_uhwi (), - "%G%qD output truncated copying %E byte " - "from a string of length %wu", - "%G%qD output truncated copying %E bytes " - "from a string of length %wu", - call, func, cnt, lenrange[0].to_uhwi ()); - - return warning_at (callloc, OPT_Wstringop_truncation, - "%G%qD output truncated copying between %wu " - "and %wu bytes from a string of length %wu", - call, func, cntrange[0].to_uhwi (), - cntrange[1].to_uhwi (), lenrange[0].to_uhwi ()); - } - else if (wi::geu_p (lenrange[1], cntrange[1])) + else if (!cat_dstlen_bounded) { - /* The longest string is longer than the upper bound of - the count so the truncation is possible. */ - if (cntrange[0] == cntrange[1]) - return warning_n (callloc, OPT_Wstringop_truncation, - cntrange[0].to_uhwi (), - "%G%qD output may be truncated copying %E " - "byte from a string of length %wu", - "%G%qD output may be truncated copying %E " - "bytes from a string of length %wu", - call, func, cnt, lenrange[1].to_uhwi ()); - - return warning_at (callloc, OPT_Wstringop_truncation, - "%G%qD output may be truncated copying between %wu " - "and %wu bytes from a string of length %wu", - call, func, cntrange[0].to_uhwi (), - cntrange[1].to_uhwi (), lenrange[1].to_uhwi ()); + if (wi::geu_p (lenrange[0], cntrange[1])) + { + /* The shortest string is longer than the upper bound of + the count so the truncation is certain. */ + if (cntrange[0] == cntrange[1]) + return warning_n (callloc, OPT_Wstringop_truncation, + cntrange[0].to_uhwi (), + "%G%qD output truncated copying %E byte " + "from a string of length %wu", + "%G%qD output truncated copying %E bytes " + "from a string of length %wu", + call, func, cnt, lenrange[0].to_uhwi ()); + + return warning_at (callloc, OPT_Wstringop_truncation, + "%G%qD output truncated copying between %wu " + "and %wu bytes from a string of length %wu", + call, func, cntrange[0].to_uhwi (), + cntrange[1].to_uhwi (), lenrange[0].to_uhwi ()); + } + else if (wi::geu_p (lenrange[1], cntrange[1])) + { + /* The longest string is longer than the upper bound of + the count so the truncation is possible. */ + if (cntrange[0] == cntrange[1]) + return warning_n (callloc, OPT_Wstringop_truncation, + cntrange[0].to_uhwi (), + "%G%qD output may be truncated copying %E " + "byte from a string of length %wu", + "%G%qD output may be truncated copying %E " + "bytes from a string of length %wu", + call, func, cnt, lenrange[1].to_uhwi ()); + + return warning_at (callloc, OPT_Wstringop_truncation, + "%G%qD output may be truncated copying between " + "%wu and %wu bytes from a string of length %wu", + call, func, cntrange[0].to_uhwi (), + cntrange[1].to_uhwi (), lenrange[1].to_uhwi ()); + } } - if (cntrange[0] != cntrange[1] + if (!cat_dstlen_bounded + && cntrange[0] != cntrange[1] && wi::leu_p (cntrange[0], lenrange[0]) && wi::leu_p (cntrange[1], lenrange[0] + 1)) {