[Bug c++/82021] New: Unnecessary null pointer check in global placement new (and also in any class-specific placement new operator declared as noexcept)
carl.cook at gmail dot com
gcc-bugzilla@gcc.gnu.org
Tue Aug 29 15:40:00 GMT 2017
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82021
Bug ID: 82021
Summary: Unnecessary null pointer check in global placement new
(and also in any class-specific placement new operator
declared as noexcept)
Product: gcc
Version: 7.2.1
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: carl.cook at gmail dot com
Target Milestone: ---
Hi,
This is just a minor nitpick, but after the clarification made in DR 1748
(http://open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1748), there is a
redundant null pointer check being performed within placement new.
The null pointer check is done (in general) to make sure that any memory passed
in is valid, and if not, no object initialization or deinitialization should
take place. However, after a clarification to 5.3.4.15, it now states for
placement new, passing null is undefined behavior (i.e. the caller must do any
pointer checks).
When using any version of gcc (from 7.2.1 and below), for any optimization
level, and for the following two forms of placement new:
* Global placement new (i.e. no user-defined operator placement new)
* User-defined placement new (with noexcept specified)
Then not only does the null pointer check still exist, but this seems to cause
the optimizer to really miss a few things. Below is an obviously silly example,
but you can see that the opportunitity to inline gets discarded, as does the
opportunity to optimize-out the call to malloc.
--
#include <memory>
int GetVal (int x) {
if (x == 0)
return 1;
else
return 2;
}
struct Object {
Object(int x)
: i(GetVal(x)) {}
int i;
};
void* GetBuffer() {
return malloc(sizeof(Object));
}
int MyFn(int i) {
void* mem = GetBuffer();
Object* object = new(mem)Object(i);
return object->i;
}
int main(int argc, char** argv) {
int rv = MyFn(*argv[0]);
return rv;
}
--
If the following is added, at level O2, then this entire program gets optimized
away (into returning the address of the first character of argv[0] as an
integer)
void* Object::operator new(size_t, void* where) { return where; }
e.g.
mov rax, QWORD PTR [rsi]
cmp BYTE PTR [rax], 0
setne al
movzx eax, al
add eax, 1
ret
I'm assuming that gcc now relies on the object-specific placement new to signal
a null pointer by way of throwing an exception, hence the optimizer can be more
aggressive. But I think the optimizer can now be just as agressive with all
forms of placement new.
More information about the Gcc-bugs
mailing list