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

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
   Last reconfirmed|                            |2024-05-31
           Keywords|                            |testsuite-fail
     Ever confirmed|0                           |1
   Target Milestone|---                         |15.0

--- Comment #1 from Richard Biener <rguenth at gcc dot gnu.org> ---
Huh, I honestly have no idea how those targets would differ here ...

I do see

void h (char * s)
{
  # PT = anything
  char * s_3(D) = s;
  char a[8];

  <bb 2> :
  __builtin_memset (&a, 0, 8);
  __builtin_strncpy (&a, s_3(D), 8);
  # USE = anything
  # CLB = anything
  frob (&a);
  a ={v} {CLOBBER(eos)};
  return;

for nds32-sim but

  Deleted dead call: __builtin_memset (&a, 0, 8);

void h (char * s)
{
  # PT = nonlocal null
  char * s_3(D) = s;
  char a[8];

  <bb 2> :
  __builtin_strncpy (&a, s_3(D), 8);
  # USE = nonlocal escaped null { D.2716 } (escaped)
  # CLB = nonlocal escaped null { D.2716 } (escaped)
  frob (&a);
  a ={v} {CLOBBER(eos)};
  return;

for x86-64.  But then the points-to solutions should not make any difference
for DSE in this case ... (the points-to difference is odd in the first place
of course).

So for the points-to difference this is caused by

-a = &NULL
+a = INTEGER

which likely means a different default of -fno-delete-null-pointer-checks
or ADDR_SPACE_ADDRESS_ZERO_VALID.  That causes us to bring in what the
object at (void *)0 points to, and that's ANYTHING since we do not track
objects at constant addresses in any way, and those might alias all other
objects.  The question is more why we generate a = &NULL at all, but that's
a pre-existing issue.  We now simply handle all this correctly (we didn't
before, with latent wrong-code).

Ah, and the DSE effect then is obviously that now 'strncpy (&a, s_3(D),..)'
reads from a since s_3(D) points to anything now (which includes 'a'), so
we can no longer remove/trim an earlier store to 'a'.

Ah, and the a = &NULL constraint is from the memset.

Since we pass a to frob it escapes and everything escaped memory points
to also escapes so anything escapes.

So I'd say it works correctly now.

There might be a missing indirection between NONLOCAL and ESCAPED.  Since
s = &NONLOCAL even when anything is in ESCAPED anything isn't NONLOCAL
itself (well, but of course technically s can point to NULL as well -
another latent incorrectness in PTA, we do not track NULL conservatively,
a correctness mistake with ADDR_SPACE_ADDRESS_ZERO_VALID).

Btw, changing the testcases to

extern void frob (char *);

void h (char *s)
{
  char a[8];
  __builtin_memset (a, 1, sizeof a);
  __builtin_strncpy (a, s, sizeof a);
  frob (a);
}

shows the same effect on x86_64 - suddenly 'a' points to ANYTHING
(0x010101010101...), which makes 's' point to ANYTHING and DSE is gone.

Confirmed for the testsuite regression.  I don't see how this is a bug
though.  Maybe the stack object 'a' can never be at address zero?  Or
any "fixed" address?  I'm not sure that such constraint can be modeled in PTA
("split" ANYTHING somehow).

Adding -fdelete-null-pointer-checks to the test makes it succeed also on
nds32le-elf.

Reply via email to