On Mon, 28 Jan 2019, Jakub Jelinek wrote: > Hi! > > While thinking about PR59813, I came up with following testcase. > Is that valid C++? > > What I want to highlight here that we need to treat the clobbers created > for C++ destructors differently from clobbers added for when variables go > out of scope. > Right now we end up with: > char buf2[128]; > char buf1[128]; > > <bb 2> [local count: 1073741824]: > foo (&buf1); > MEM[(struct &)&buf1] ={v} {CLOBBER}; > memset (&MEM[(void *)&buf1], 32, 128); > bar (&buf1); > MEM[(struct &)&buf1] ={v} {CLOBBER}; > baz (&buf2); > buf2 ={v} {CLOBBER}; > buf1 ={v} {CLOBBER}; > return; > where the MEM[(struct &)&buf1] ={v} {CLOBBER}; is what is coming from > the inlined dtor (and the earlier one from inlined ctor), while > buf1 ={v} {CLOBBER}; is what is added by the gimplifier for vars that go out > of scope. The var conflict code only considers clobbers with VAR_DECLs on > the lhs and thus the testcase is not miscompiled. > > Now, if I manually change the second clobber in the function > MEM[(struct &)&buf1] ={v} {CLOBBER}; > memset (&MEM[(void *)&buf1], 32, 128); > bar (&buf1); > - MEM[(struct &)&buf1] ={v} {CLOBBER}; > + buf1 ={v} {CLOBBER}; > baz (&buf2); > buf2 ={v} {CLOBBER}; > buf1 ={v} {CLOBBER}; > the testcase is miscompiled, so that just points at the need to never fold > the clobbers with MEM_REF on the lhs into the form with VAR_DECL on the lhs.
Eww :/ That means they are not semantically the same which IMHO is bad. If you make buf1 volatile does it trip over maybe_canonicalize_mem_ref_addr and miscompile? Or are we somehow doubly lucky and never share stack space of volatiles... Richard. > Tested on x86_64-linux and i686-linux, is the testcase ok for the trunk? > > 2019-01-28 Jakub Jelinek <ja...@redhat.com> > > * g++.dg/torture/alias-1.C: New test. > > --- gcc/testsuite/g++.dg/torture/alias-1.C.jj 2019-01-28 12:49:21.044341442 > +0100 > +++ gcc/testsuite/g++.dg/torture/alias-1.C 2019-01-28 12:49:04.697612121 > +0100 > @@ -0,0 +1,57 @@ > +// Verify we don't try to allocate the same stack slot for > +// buf1 and buf2 in qux. While there is a CLOBBER stmt for buf1 > +// from inlined destructor, the buf1 variable doesn't go out of scope > +// until after the baz call. > +// { dg-do run } > + > +#include <new> > +#include <cstring> > +#include <cstdlib> > + > +char *p; > +struct S { char buf[128]; S () { memset (buf, ' ', 128); }; ~S () {}; }; > + > +__attribute__((noipa)) void > +foo (char *x) > +{ > + p = x; > +} > + > +__attribute__((noipa)) int > +bar (S *x) > +{ > + return x->buf[12]; > +} > + > +__attribute__((noipa)) void > +baz (char *x) > +{ > + S *a = new (p) (S); > + S *b = new (x) (S); > + memset (a->buf, '0', 128); > + memset (b->buf, '1', 128); > + if (bar (a) != '0' || bar (b) != '1') > + abort (); > + b->~S (); > + a->~S (); > +} > + > +__attribute__((noipa)) void > +qux () > +{ > + char buf1[128]; > + foo (buf1); > + S *p = new (buf1) (S); > + bar (p); > + p->~S (); > + { > + char buf2[128]; > + baz (buf2); > + } > +} > + > +int > +main () > +{ > + qux (); > +} > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)