On Tue, Dec 17, 2019 at 09:53:43AM -0700, Martin Sebor wrote:
> I appreciate a cleanup but I don't have the impression this patch
> does clean anything up.  Because of all the formatting changes and
> no tests the effect of the changes isn't as clear as it should be.
> (I wish you would resist the urge to reformat existing code on this
> scale while also making changes with an observable effect in
> the same diff.)  But thanks to the detailed explanation above
> I think I can safely say that the builtins.c changes are not in
> line with what I would like to see.

As written, there were two real changes in gimple_call_alloc_size,
one in maybe_warn_overflow and the rest formatting fixes (which I really
can't ignore, e.g. semicolon after if (...) { ... }; ?).
From the above, it seems you are talking about just one change in
gimple_call_alloc_size (the setting of rng1[0] to 0 on overflow).

So, let's talk first about the first real change in gimple_call_alloc_size.
Without it, you get garbage on testcase like:
/* { dg-do compile { target lp64 } } */
/* { dg-options "-O2 -Wall" } */

__attribute__((noipa, alloc_size (1)))
char *
foo (int a)
{
  return (char *) __builtin_malloc (a);
}

void
bar (char *q)
{
  char *p = foo (-13);
  if (!p)
    return;
  __builtin_memcpy (p, q, (__SIZE_TYPE__) 0x100000002ULL);
}

alloc_size_test.c: In function ‘bar’:
alloc_size_test.c:17:3: warning: ‘__builtin_memcpy’ writing 4294967298 bytes 
into a region of size 4294967283 [-Wstringop-overflow=]
   17 |   __builtin_memcpy (p, q, (__SIZE_TYPE__) 0x100000002ULL);
      |   ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
alloc_size_test.c:14:13: note: at offset 0 to an object with size 4294967283 
allocated by ‘foo’ here
   14 |   char *p = foo (-13);
      |             ^~~~~~~~~
alloc_size_test.c:14:13: warning: argument 1 value ‘-13’ is negative 
[-Walloc-size-larger-than=]
alloc_size_test.c:6:1: note: in a call to allocation function ‘foo’ declared 
here
    6 | foo (int a)
      | ^~~

The first warning is wrong, there is no object with size 4294967283 aka
-13U, the allocation will almost certainly fail and there will be nothing
wrong in the testcase, but if it wouldn't fail, it would need to allocate
-13UL aka 18446744073709551603 bytes.  And the reason is that
gimple_call_alloc_size leaves bogus rng1[0] and rng1[1], of -13 with
precision 32, which the caller than extends to siz_prec, but with UNSIGNED
extension, which is reasonable assumption that it is given size (UNSIGNED)
wide_ints.

The second hunk, there can be still several cases, e.g. both low bound and
upper bound could overflow, such as on calloc (SIZE_MAX / 2 + 2, SIZE_MAX /
2 + 2).  In this case, the code would produce a range of (say let's assume
ilp32 in this case) of [0x4000000100000001, 0xffffffff].  What the caller
will do with such thing is hard to predict, there is from UNSIGNED siz_prec
conversion.  If you don't want the function to return real range of possible
values, but something else, it should be document what it is and not call it
range.  For the reasons you stated, perhaps for warnings (but never for code
generation!) it could be useful to have both range and likely range, where
the latter would be on the assumption that no overflow happens and so e.g.
for [64, SIZE_MAX] * [64, SIZE_MAX] it could return range of [0, SIZE_MAX]
and likely range of [64 * 64, SIZE_MAX].

And for the real change in maybe_warn_overflow, you can just try in the
debugger or using gprof see when that if (early out) will ever trigger, I'd
bet very rarely.
char *
foo (void)
{
  char *p = __builtin_calloc (32, 32);
  __builtin_memset (p, ' ', 32 * 32);
  return p;
}
gdb --args ./cc1 -quiet -O2 -Wall test.c
b tree-ssa-strlen.c:2051
r
p destsize
$1 = <integer_cst 0x7fffea94a0d8>
p len
$2 = <integer_cst 0x7fffea929f90>
p debug_generic_stmt (destsize)
1024
p debug_generic_stmt (len)
1024

        Jakub

Reply via email to