https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105217

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |jsm28 at gcc dot gnu.org

--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I think pedantically both #c0 and #c3 or even
int
foo (void)
{
  char *p = __builtin_malloc (32);
  char *q = __builtin_realloc (p, 64);
  if (p == q)
    return __builtin_object_size (p, 0);
  else
    return -1;
}
are invalid (the pointer that is passed to realloc can't be used subsequently).
 If the comparison is in integral type, it is fuzzier.
The problem is that in real-world, this is a very common thing to do, either
with pointer or integral comparisons, often one needs to find out if it has
been reallocated and adjust say some embedded pointers in the allocation or
some other pointers so that they point into the new allocation rather than the
old one and for optimization purposes it is complete waste of time to do it
when the allocation wasn't actually moved.
The above also returns 32 when it should return 64, even with very old gcc
versions.
On the other side, the standard making that invalid makes a lot of sense,
otherwise we couldn't assume anything in case of
  char *p = __builtin_malloc (32);
  bar (p);
  return __builtin_object_size (p, 0);
because if we don't see into bar, it could do something like
  if (__builtin_realloc (p, 33) != p)
    exit (25);
or similar (or say realloc to smaller size, then bos2/bos3).
Even if the realloc is in the same function as the malloc, we might not know
that it is that exact pointer passed to realloc (say pointer is passed to some
function, that stores the pointer into global var, another function returns it,
we then pass it to realloc, or any other way of obfuscation).
I'm afraid in those cases we should just point at the standard that it is
undefined.
Then there is the case where we can clearly see that the pointer from malloc is
passed to realloc or can trace it to such easily.  I'd say in that case it
would be worthwhile to do some extra work.
For __bos the simplest solution would be if we detect something like that (e.g.
that the SSA_NAME passed to realloc has uses dominated by the realloc call
(though, even figuring that can mean we e.g. mark gimple stmts in each bb with
increasing uids to determine like reassoc what stmt is before another one) just
to punt, say we don't know anything about the SSA_NAME's size, or use
conservative choice from both malloc and realloc (maximum for bos0/bos1,
minimum for bos2/bos3).
For __bdos perhaps the same.  Another possibility would be to temporarily split
the SSA_NAME passed to realloc, kind like old VRP was introducing ASSERT_EXPRs.
So, basically when we see:
  whatever = realloc (p_34, ...);
rewrite that (temporarily?) to:
  p_121 = p_34;
  whatever = realloc (p_121, ...);
and change all p_34 uses dominated by the realloc stmt to p_121, and add the
p_121 = p_34; stmt to some hash table or otherwise mark it so that we wouldn't
propagate the objsz knowledge from p_34 to p_121, but instead set it on the
realloc call.  That won't cover the integral comparisons though I'm afraid...

Reply via email to