Possible GCC bug with copy-construction of object on itself?
Martin Sebor
msebor@gmail.com
Thu Feb 8 17:39:00 GMT 2018
On 02/08/2018 06:57 AM, Ole Kniemeyer wrote:
> Hi,
>
> I have a small code snippet where I'm not sure if it's a GCC bug or undefined behaviour, so maybe
> someone can help? The code is
>
> #include <new>
>
> void Func(void*);
>
> struct A
> {
> A() = default;
> A(const A& src)
> {
> Func(src.x);
> }
>
> void* x;
> };
>
> void Test(void* ptr)
> {
> A tmp;
> tmp.x = ptr;
> new (&tmp) A(tmp);
> }
>
> If you paste this code at gcc.godbolt.org and use -O3, GCC <= 5.X and Clang produce the code which
> I'd expect:
>
> Test(void*):
> jmp Func(void*)
>
> But GCC 6 and 7 call Func with a nullptr:
>
> Test(void*):
> xorl %edi, %edi
> jmp Func(void*)
>
> I admit that the code is a bit dubious because it copy-constructs a new A object with itself and
> the copy constructor doesn't copy anything, so is this undefined behavior or a GCC bug?
I think it's undefined. If it were to be well-defined then
the copy constructor of every non-trivial type would have
to worry about self-copying not just the way copy assignment
does, but it would also have to create a temporary copy of
its argument before constructing self to avoid clobbering it.
That's a catch-22.
Martin
PS Here's a small test case where GCC detects the undefined
behavior and complains that x i uninitialized. The change
was introduced in GCC 6 via r222135. The change description
explains why:
* constexpr.c (cxx_eval_store_expression): Ignore clobbers.
(build_constexpr_constructor_member_initializers): Loop to find
the BIND_EXPR.
* decl.c (start_preparsed_function): Clobber the object at the
beginning of a constructor.
The constructor marks the object under construction as clobbered
which the -Wuninitialized checker notices.
void* operator new (__SIZE_TYPE__, void *p) { return p; }
struct A
{
A() = default;
A(const A& src) {
x = src.x;
}
void* x;
};
void* Test(void* ptr)
{
A tmp;
tmp.x = ptr;
new (&tmp) A(tmp);
return tmp.x;
}
u.C:18:14: warning: âtmp.A::xâ is used uninitialized in this function
[-Wuninitialized]
return tmp.x;
^
More information about the Gcc-help
mailing list