Message ID | 20220406142527.2257191-1-jason@redhat.com |
---|---|
State | New |
Headers | show |
Series | [RFA(pointer-query)] c++: -Wplacement-new and anon union member [PR100370] | expand |
On Wed, Apr 6, 2022 at 4:26 PM Jason Merrill via Gcc-patches <gcc-patches@gcc.gnu.org> wrote: > > This bug was an object/value confusion; we are interested in the size > of *b.ip, but instead the code was calculating the size of b.ip itself. > > This seems to be because compute_objsize will compute the size of whatever > object it can find in the argument: if you pass it a VAR_DECL, it gives you > the size of that variable. If you pass it an ADDR_EXPR of a VAR_DECL, it > again gives you the size of the variable. The way you can tell the > difference is by looking at the deref member of access_ref: if it's -1, the > argument is a pointer to the object. Since that's what we're interested in, > we should check for that, like check_dangling_stores does. > > This regressed some tests because compute_objsize_r was wrongly zeroing > deref in the POINTER_PLUS_EXPR handling; adding an offset to a pointer > doesn't change whether the pointer is itself a variable or a pointer to > one. In fact, handling POINTER_PLUS_EXPR only really makes sense for deref > == -1, where we're adjusting a pointer to the variable. > > Tested x86_64-pc-linux-gnu, OK for trunk? OK. Thanks, Richard. > PR c++/100370 > > gcc/cp/ChangeLog: > > * init.cc (warn_placement_new_too_small): Check deref. > > gcc/ChangeLog: > > * pointer-query.cc (compute_objsize_r) [POINTER_PLUS_EXPR]: Require > deref == -1. > > gcc/testsuite/ChangeLog: > > * g++.dg/warn/Wplacement-new-size-11.C: New test. > --- > gcc/cp/init.cc | 5 +++++ > gcc/pointer-query.cc | 7 ++++--- > .../g++.dg/warn/Wplacement-new-size-11.C | 15 +++++++++++++++ > 3 files changed, 24 insertions(+), 3 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C > > diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc > index 01e762320f3..43097121244 100644 > --- a/gcc/cp/init.cc > +++ b/gcc/cp/init.cc > @@ -2811,6 +2811,11 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) > if (!objsize) > return; > > + /* We can only draw conclusions if ref.deref == -1, > + i.e. oper is the address of the object. */ > + if (ref.deref != -1) > + return; > + > offset_int bytes_avail = wi::to_offset (objsize); > offset_int bytes_need; > > diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc > index 4390535ef56..d93657f3206 100644 > --- a/gcc/pointer-query.cc > +++ b/gcc/pointer-query.cc > @@ -2299,9 +2299,10 @@ compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype, > if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry)) > return false; > > - /* Clear DEREF since the offset is being applied to the target > - of the dereference. */ > - pref->deref = 0; > + /* The below only makes sense if the offset is being applied to the > + address of the object. */ > + if (pref->deref != -1) > + return false; > > offset_int orng[2]; > tree off = pref->eval (TREE_OPERAND (ptr, 1)); > diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C > new file mode 100644 > index 00000000000..a6fe82e90ae > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C > @@ -0,0 +1,15 @@ > +// PR c++/100370 > +// { dg-do compile { target c++11 } } > + > +using size_t = decltype(sizeof(1)); > +inline void *operator new (size_t s, void *p) { return p; } > + > +int main() > +{ > + struct s1 { int iv[4]; }; > + struct s2 { union { char* cp; int* ip; }; }; > + > + s2 b; > + b.ip=new int[8]; > + new (b.ip+4) s1; // { dg-bogus "-Wplacement-new" } > +} > > base-commit: 44fe49401725055a740ce47e80561b6932b8cd01 > -- > 2.27.0 >
diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 01e762320f3..43097121244 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -2811,6 +2811,11 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) if (!objsize) return; + /* We can only draw conclusions if ref.deref == -1, + i.e. oper is the address of the object. */ + if (ref.deref != -1) + return; + offset_int bytes_avail = wi::to_offset (objsize); offset_int bytes_need; diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index 4390535ef56..d93657f3206 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -2299,9 +2299,10 @@ compute_objsize_r (tree ptr, gimple *stmt, bool addr, int ostype, if (!compute_objsize_r (ref, stmt, addr, ostype, pref, snlim, qry)) return false; - /* Clear DEREF since the offset is being applied to the target - of the dereference. */ - pref->deref = 0; + /* The below only makes sense if the offset is being applied to the + address of the object. */ + if (pref->deref != -1) + return false; offset_int orng[2]; tree off = pref->eval (TREE_OPERAND (ptr, 1)); diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C new file mode 100644 index 00000000000..a6fe82e90ae --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-11.C @@ -0,0 +1,15 @@ +// PR c++/100370 +// { dg-do compile { target c++11 } } + +using size_t = decltype(sizeof(1)); +inline void *operator new (size_t s, void *p) { return p; } + +int main() +{ + struct s1 { int iv[4]; }; + struct s2 { union { char* cp; int* ip; }; }; + + s2 b; + b.ip=new int[8]; + new (b.ip+4) s1; // { dg-bogus "-Wplacement-new" } +}