[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-10-11 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #19 from CVS Commits  ---
The master branch has been updated by Richard Biener :

https://gcc.gnu.org/g:09a0affdb0598a54835ac4bb0dd6b54122c12916

commit r12-4319-g09a0affdb0598a54835ac4bb0dd6b54122c12916
Author: Richard Biener 
Date:   Mon Oct 11 16:06:03 2021 +0200

middle-end/101480 - overloaded global new/delete

The following fixes the issue of ignoring side-effects on memory
from overloaded global new/delete operators by not marking them
as effectively 'const' apart from other explicitely specified
side-effects.

This will cause

FAIL: g++.dg/warn/Warray-bounds-16.C  -std=gnu++1? (test for excess errors)

because we now no longer statically see the initialization loop
never executes because the call to operator new can now clobber 'a.m'.
This seems to be an issue with the warning code and/or ranger so
I'm leaving this FAIL to be addressed as followup.

2021-10-11  Richard Biener  

PR middle-end/101480
* gimple.c (gimple_call_fnspec): Do not mark operator new/delete
as const.

* g++.dg/torture/pr10148.C: New testcase.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-10-11 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Richard Biener  changed:

   What|Removed |Added

 CC||amacleod at redhat dot com

--- Comment #18 from Richard Biener  ---
(In reply to Martin Sebor from comment #16)
> (In reply to Richard Biener from comment #14)
> ...
> > the testcase does
> > 
> > m = i;
> > p = (int*) new unsigned char [sizeof (int) * m];
> > 
> > for (int i = 0; i < m; i++)
> >   new (p + i) int ();
> > 
> > and we likely have to assume that 'new' changes 'm'.
> 
> Why?  Because of the flow-insensitivity of the alias analysis?
> 
> m is a member of the class whose ctor has the loop above.  Neither the
> enclosing object nor the member actually escapes (the operator new to which
> p is passed in the loop is the nonreplaceable placement new), so there is no
> way it can be changed.

What we see is the global variable construction function which accesses
just 'a', and yes, the call to 'new' is considered clobbering global
variables (including 'a'):

   [local count: 1073741824]:
  MEM[(struct __as_base  &)] ={v} {CLOBBER};
  a.m = 0;
  _5 = operator new [] (0);
  a.p = _5;
  goto ; [100.00%]

   [local count: 8687547547]:
  _7 = (long unsigned int) i_6;
  _8 = _7 * 4;
  _9 = _5 + _8;
  MEM[(int *)_9] = 0;
  i_10 = i_6 + 1;

   [local count: 9761289362]:
  # i_6 = PHI <0(2), i_10(3)>
  _11 = a.m;
  if (i_6 < _11)
goto ; [89.00%]
  else
goto ; [11.00%]

   [local count: 1073741824]:
  return;

I suppose implementing the global operator new as accessing a.m would
be valid as IIRC lifetime of a starts when the CTOR is invoked, not
when it finished (otherwise the CTOR could not access the variable itself).

We somehow conclude that

_9: void * [1B, +INF]  EQUIVALENCES: { } (0 elements)

possibly because it cannot be NULL (?):

extract_range_from_stmt visiting:
_5 = operator new [] (0);
Found new range for _5: void * [1B, +INF]
marking stmt to be not simulated again

(huh?)

and then the -Warray-bounds warning concludes the access is always outside
of the allocated area.

I suspect when we'd arrive at VARYING we'd not issue the warning even
when the access would always extend beyond a zero-sized allocation.

I'm going to ignore this diagnostic issue, it concerns the 'offrange'
code I'm not familiar with at all (and maybe the value-range code for
which I now have to say sth similar).

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-10-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Richard Biener  changed:

   What|Removed |Added

   Assignee|unassigned at gcc dot gnu.org  |rguenth at gcc dot 
gnu.org
 Status|NEW |ASSIGNED

--- Comment #17 from Richard Biener  ---
I'm re-testing the patch and will investigate the failure more if it still
happens.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-28 Thread msebor at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Martin Sebor  changed:

   What|Removed |Added

 CC||msebor at gcc dot gnu.org

--- Comment #16 from Martin Sebor  ---
(In reply to Richard Biener from comment #14)
...
> the testcase does
> 
> m = i;
> p = (int*) new unsigned char [sizeof (int) * m];
> 
> for (int i = 0; i < m; i++)
>   new (p + i) int ();
> 
> and we likely have to assume that 'new' changes 'm'.

Why?  Because of the flow-insensitivity of the alias analysis?

m is a member of the class whose ctor has the loop above.  Neither the
enclosing object nor the member actually escapes (the operator new to which p
is passed in the loop is the nonreplaceable placement new), so there is no way
it can be changed.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-28 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Richard Biener  changed:

   What|Removed |Added

   Target Milestone|11.2|11.3

--- Comment #15 from Richard Biener  ---
GCC 11.2 is being released, retargeting bugs to GCC 11.3

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #14 from Richard Biener  ---
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 863bc0d17f1..e085d9de49a 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -1516,12 +1516,12 @@ gimple_call_fnspec (const gcall *stmt)
   && DECL_IS_OPERATOR_DELETE_P (fndecl)
   && DECL_IS_REPLACEABLE_OPERATOR (fndecl)
   && gimple_call_from_new_or_delete (stmt))
-return ".co ";
+return ". o ";
   /* Similarly operator new can be treated as malloc.  */
   if (fndecl
   && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl)
   && gimple_call_from_new_or_delete (stmt))
-return "mC";
+return "m ";
   return "";
 }


regresses

FAIL: g++.dg/warn/Warray-bounds-16.C  -std=gnu++14  scan-tree-dump-not
optimized "goto"
FAIL: g++.dg/warn/Warray-bounds-16.C  -std=gnu++14 (test for excess errors)

where we now diagnose

/home/rguenther/src/trunk/gcc/testsuite/g++.dg/warn/Warray-bounds-16.C:22:7:
warning: array subscript 0 is outside array bounds of 'void [0]'
[-Warray-bounds]
/home/rguenther/src/trunk/gcc/testsuite/g++.dg/warn/Warray-bounds-16.C:22:7:
warning: 'void* __builtin_memset(void*, int, long unsigned int)' offset [0, 3]
is out of the bounds [0, 0] [-Warray-bounds]

the testcase does

m = i;
p = (int*) new unsigned char [sizeof (int) * m];

for (int i = 0; i < m; i++)
  new (p + i) int ();

and we likely have to assume that 'new' changes 'm'.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #13 from Richard Biener  ---
In PR98130 I suggested "..o " for delete and it would be "m " for new (does
a C++ new expression really set/clobber errno?).

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #12 from Richard Biener  ---
That was because of PR98130 it seems.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread rguenther at suse dot de via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #11 from rguenther at suse dot de  ---
On Mon, 19 Jul 2021, redi at gcc dot gnu.org wrote:

> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480
> 
> Jonathan Wakely  changed:
> 
>What|Removed |Added
> 
>See Also||https://gcc.gnu.org/bugzill
>||a/show_bug.cgi?id=59894
> 
> --- Comment #9 from Jonathan Wakely  ---
> I don't think this optimization should be on by default. A switch that says
> "this program does not replace operator new and delete" would make it OK. That
> is the subject of PR 59894.

The odd thing is we do

  /* If the call is to a replaceable operator delete and results
 from a delete expression as opposed to a direct call to
 such operator, then we can treat it as free.  */
  if (fndecl
  && DECL_IS_OPERATOR_DELETE_P (fndecl)
  && DECL_IS_REPLACEABLE_OPERATOR (fndecl)
  && gimple_call_from_new_or_delete (stmt))
return ".co ";
  /* Similarly operator new can be treated as malloc.  */
  if (fndecl
  && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (fndecl)
  && gimple_call_from_new_or_delete (stmt))
return "mC";

so explicitely asking for the replaceable variants only (well, not sure
if ones that don't have DECL_IS_REPLACEABLE_OPERATOR set are any
"better" or worse here).  Then we have valid_new_delete_pair_p used by
new/delete pair removal which explicitely checks mangled symbol names.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread jens.maurer at gmx dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #10 from Jens Maurer  ---
I agree with Jonathan here: The difference is that "malloc" comes with the
compiler/library and cannot be replaced (within the scope of the C or C++
standards), but "operator new" is expressly specified to be replaceable by the
C++ standard. There is text in the standard that restricts what "operator new"
can and cannot do, but otherwise it is specified as-if a regular function call.

As-is, gcc 11 is non-conforming with this optimization turned on by default.

I'm all for providing an extra command-line switch so that the user can assert
that he's not replacing "operator new" anywhere in the program, but that switch
should be off by default.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Jonathan Wakely  changed:

   What|Removed |Added

   See Also||https://gcc.gnu.org/bugzill
   ||a/show_bug.cgi?id=59894

--- Comment #9 from Jonathan Wakely  ---
I don't think this optimization should be on by default. A switch that says
"this program does not replace operator new and delete" would make it OK. That
is the subject of PR 59894.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #8 from Jonathan Wakely  ---
But operator new is not defined in the runtime here, it's a replaceable global
allocation function. The assumption seems unsafe for replaceable functions that
users can define in their own code.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #7 from Richard Biener  ---
(In reply to Richard Biener from comment #6)
> As Jakub said the behavior is the same for malloc() since years.
> 
... 
> So it might work to disable the new/delete/malloc/free optimization when
> we see a definition of those functions.

But it's surely not enough to disable transforms like

 x = 0;
 ... = new ...;
 if (x != 0)
   ..

to elide the load from x after the 'new'.  Like with malloc we assume
that state of the runtime (where malloc / new is defined) is only
accessible via API calls and not visible to the compiler at the same
time its users are.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #6 from Richard Biener  ---
As Jakub said the behavior is the same for malloc() since years.

When you split the testcase like

> cat t.C
#include 
#include 

bool flag = false;

class C
{
  bool prev;

public:
  C() : prev(flag)
  {
flag = true; // #1
  }

  ~C() {
flag = prev;
  }
};

void g(int* p)
{
  delete p;
}

void f()
{
  int* p;
  {
C c;
p = new int;
  }
  g(p);
}

int main(int, char**)
{
  f();
}


> cat t2.C
#include 
#include 

extern bool flag;

void* operator new(unsigned long size)
{
  assert(flag);  // #2
  return malloc(size);
}

void operator delete(void *p)
{
  free(p);
}


it works as 'flag' is then global and no longer local to the TU.

So it might work to disable the new/delete/malloc/free optimization when
we see a definition of those functions.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread volker.schmidt at factset dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Volker Schmidt  changed:

   What|Removed |Added

 CC||volker.schmidt at factset dot 
com

--- Comment #5 from Volker Schmidt  ---
I would simply add, that we have breaking change to gcc here, that does do
something different, without any warning or documentation, simply based on the
idea (which I find no source to point too, that new should not use globals).

Without digging to deep, I find a number of areas (inter process communication,
inter processor communication, numa optimizations, architectures with special
function memory areas), where calling new is depended on a global status.

So I find this assumption, not very intuitive.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread jakub at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Jakub Jelinek  changed:

   What|Removed |Added

 CC||jakub at gcc dot gnu.org

--- Comment #4 from Jakub Jelinek  ---
It is extremely important optimization and is done only if new/delete is used,
not when one calls these operators.  While when one calls the operator by hand,
the C++ standard doesn't give the possibility of optimizing away e.g. a pair of
operator delete (operator new (23)), when delete new int; is used, it can be
optimized away.  With reading and modification of the global state, sure, under
the hood the function will need to read and store some global state, but the
point is that typically that state doesn't include anything that the callers
care about.  It is similar to malloc, if one defines in C or C++ malloc and
uses variables the callers of malloc set or read in the malloc implementation,
it will not work properly.  We have a -fno-builtin-malloc or -fno-builtin-free
for that case though, so people that want to do weird things can at the expense
of massive code penalization get what they want (better is to use some compiler
barriers for such state).  For the operator new/delete I think we don't have a
switch, maybe it should be added.  But it certainly should default to the
current state.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread jens.maurer at gmx dot net via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

--- Comment #3 from Jens Maurer  ---
"We treat the global operator new as not reading from global memory"

If I implement my own global "operator new" afresh, certainly it'll need to
access global memory, e.g. to read a global pointer to the heap or so.

I have carefully reviewed [expr.new] before posting this bug report. The
compiler can omit a call to an allocation function entirely (and e.g. provide
the memory on the stack, if the lifetime fits), but I haven't found any wording
that would allow making assumptions about the global memory behavior of the
allocation function when it is, in fact, called.

"we cannot do the optimization that was added"

I understand this might be an important optimization to offer (similar to
-ffast-float), but it would be good to have a separate command-line flag to
enable or disable it.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-19 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Richard Biener  changed:

   What|Removed |Added

 CC||jason at gcc dot gnu.org,
   ||rguenth at gcc dot gnu.org
   Priority|P3  |P2

--- Comment #2 from Richard Biener  ---
We treat the global operator new as not reading from global memory but here it
does.  I'm not sure if this overload is "valid".  There's also the distinction
made between replaceable and non-replaceable(?) operators.

If a replaced global operator new can have arbitrary side-effects we cannot do
the optimization that was added.

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-18 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Jonathan Wakely  changed:

   What|Removed |Added

 Status|UNCONFIRMED |NEW
   Last reconfirmed||2021-07-18
 Ever confirmed|0   |1

[Bug c++/101480] [11/12 Regression] Miscompiled code involving operator new

2021-07-18 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101480

Jonathan Wakely  changed:

   What|Removed |Added

  Known to work||10.3.0
   Keywords||wrong-code
  Known to fail||11.1.0, 12.0
Summary|Miscompiled code involving  |[11/12 Regression]
   |operator new|Miscompiled code involving
   ||operator new
   Target Milestone|--- |11.2
 CC||hubicka at gcc dot gnu.org

--- Comment #1 from Jonathan Wakely  ---
Started with r11-4745

Add fnspecs for C++ new and delete operators

gcc/ChangeLog:

* gimple.c (gimple_call_fnspec): Handle C++ new and delete.
* gimple.h (gimple_call_from_new_or_delete): Constify parameter.

gcc/testsuite/ChangeLog:

* g++.dg/ipa/devirt-24.C: Update template.