[PATCH] avoid warning on constant strncpy until next statement is reachable (PR 87028)
Martin Sebor
msebor@gmail.com
Mon Aug 27 20:31:00 GMT 2018
On 08/25/2018 11:24 PM, Jeff Law wrote:
> On 08/24/2018 09:58 AM, Martin Sebor wrote:
>> The warning suppression for -Wstringop-truncation looks for
>> the next statement after a truncating strncpy to see if it
>> adds a terminating nul. This only works when the next
>> statement can be reached using the Gimple statement iterator
>> which isn't until after gimplification. As a result, strncpy
>> calls that truncate their constant argument that are being
>> folded to memcpy this early get diagnosed even if they are
>> followed by the nul assignment:
>>
>> const char s[] = "12345";
>> char d[3];
>>
>> void f (void)
>> {
>> strncpy (d, s, sizeof d - 1); // -Wstringop-truncation
>> d[sizeof d - 1] = 0;
>> }
>>
>> To avoid the warning I propose to defer folding strncpy to
>> memcpy until the pointer to the basic block the strnpy call
>> is in can be used to try to reach the next statement (this
>> happens as early as ccp1). I'm aware of the preference to
>> fold things early but in the case of strncpy (a relatively
>> rarely used function that is often misused), getting
>> the warning right while folding a bit later but still fairly
>> early on seems like a reasonable compromise. I fear that
>> otherwise, the false positives will drive users to adopt
>> other unsafe solutions (like memcpy) where these kinds of
>> bugs cannot be as readily detected.
>>
>> Tested on x86_64-linux.
>>
>> Martin
>>
>> PS There still are outstanding cases where the warning can
>> be avoided. I xfailed them in the test for now but will
>> still try to get them to work for GCC 9.
>>
>> gcc-87028.diff
>>
>>
>> PR tree-optimization/87028 - false positive -Wstringop-truncation strncpy with global variable source string
>> gcc/ChangeLog:
>>
>> PR tree-optimization/87028
>> * gimple-fold.c (gimple_fold_builtin_strncpy): Avoid folding when
>> statement doesn't belong to a basic block.
>> * tree-ssa-strlen.c (maybe_diag_stxncpy_trunc): Handle MEM_REF on
>> the left hand side of assignment.
>>
>> gcc/testsuite/ChangeLog:
>>
>> PR tree-optimization/87028
>> * c-c++-common/Wstringop-truncation.c: Remove xfails.
>> * gcc.dg/Wstringop-truncation-5.c: New test.
>>
>> diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
>> index 07341eb..284c2fb 100644
>> --- a/gcc/gimple-fold.c
>> +++ b/gcc/gimple-fold.c
>> @@ -1702,6 +1702,11 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi,
>> if (tree_int_cst_lt (ssize, len))
>> return false;
>>
>> + /* Defer warning (and folding) until the next statement in the basic
>> + block is reachable. */
>> + if (!gimple_bb (stmt))
>> + return false;
> I think you want cfun->cfg as the test here. They should be equivalent
> in practice.
>
>
>> diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
>> index d0792aa..f1988f6 100644
>> --- a/gcc/tree-ssa-strlen.c
>> +++ b/gcc/tree-ssa-strlen.c
>> @@ -1981,6 +1981,23 @@ maybe_diag_stxncpy_trunc (gimple_stmt_iterator gsi, tree src, tree cnt)
>> && known_eq (dstoff, lhsoff)
>> && operand_equal_p (dstbase, lhsbase, 0))
>> return false;
>> +
>> + if (code == MEM_REF
>> + && TREE_CODE (lhsbase) == SSA_NAME
>> + && known_eq (dstoff, lhsoff))
>> + {
>> + /* Extract the referenced variable from something like
>> + MEM[(char *)d_3(D) + 3B] = 0; */
>> + gimple *def = SSA_NAME_DEF_STMT (lhsbase);
>> + if (gimple_nop_p (def))
>> + {
>> + lhsbase = SSA_NAME_VAR (lhsbase);
>> + if (lhsbase
>> + && dstbase
>> + && operand_equal_p (dstbase, lhsbase, 0))
>> + return false;
>> + }
>> + }
> If you find yourself looking at SSA_NAME_VAR, you're usually barking up
> the wrong tree. It'd be easier to suggest something here if I could see
> the gimple (with virtual operands). BUt at some level what you really
> want to do is make sure the base of the MEM_REF is the same as what got
> passed as the destination of the strncpy. You'd want to be testing
> SSA_NAMEs in that case.
I replied to Richard with the code that this hunk handles:
https://gcc.gnu.org/ml/gcc-patches/2018-08/msg01697.html
I couldn't find any other way to determine that d_3(D) in
MEM[(char *)d_3(D) + 3B] = 0;
is the same as the first argument in:
__builtin_strncpy (d_3(D), "12345", 4);
The MEM_REF operand is an SSA_NAME whose DEF_STMT is
a GIMPLE_NOP and whose SSA_NAME_VAR is the PARAM_DECL d.
Where else can I get the variable from?
Martin
More information about the Gcc-patches
mailing list