On Wed, Aug 23, 2017 at 9:42 PM, Martin Sebor <mse...@gmail.com> wrote: > Bug 81908 is about a -Wstringop-overflow warning for a Fortran > test triggered by a recent VRP improvement. A simple test case > that approximates the warning is: > > void f (char *d, const char *s, size_t n) > { > if (n > 0 && n <= SIZE_MAX / 2) > n = 0; > > memcpy (d, s, n); // n in ~[1, SIZE_MAX / 2] > } > > Since the only valid value of n is zero the call to memcpy can > be considered a no-op (a value of n > SIZE_MAX is in excess of > the maximum size of the largest object and would surely make > the call crash). > > The important difference between the test case and Bug 81908 > is that in the latter, the code is emitted by GCC itself from > what appears to be correct source (looks like it's the result > of the loop distribution pass). I believe the warning for > the test case above and for other human-written code like it > is helpful, but warning for code emitted by GCC, even if it's > dead or unreachable, is obviously not (at least not to users). > > The attached patch enhances the gimple_fold_builtin_memory_op > function to eliminate this patholohgical case by making use > of range information to fold into no-ops calls to memcpy whose > size argument is in a range where the only valid value is zero. > This gets rid of the warning and improves the emitted code. > > Tested on x86_64-linux.
@@ -646,6 +677,12 @@ gimple_fold_builtin_memory_op (gimple_stmt_iterator *gsi, tree destvar, srcvar; location_t loc = gimple_location (stmt); + if (tree valid_len = only_valid_value (len)) + { + /* LEN is in range whose only valid value is zero. */ + len = valid_len; + } + /* If the LEN parameter is zero, return DEST. */ if (integer_zerop (len)) just enhance this check to if (integer_zerop (len) || size_must_be_zero_p (len)) ? 'only_valid_value' looks too generic for this. + if (!wi::fits_uhwi_p (min) || !wi::fits_uhwi_p (max)) + return NULL_TREE; + why? + if (wi::eq_p (min, wone) + && wi::geu_p (max + 1, ssize_max)) if (wi::eq_p (min, 1) && wi::gtu_p (max, wi::max_value (prec, SIGNED))) your ssize_max isn't signed size max, and max + 1 might overflow to zero. Richard. > Martin