Created attachment 32234 [details] Preprocessed, minimal testcase triggering unexpected behaviour The attached minimal testcase has the following function with default-constructed default argument: void do_something( foo f = {} ) { std::cout << "default argument is at " << &f << std::endl; } The constructor for foo outputs its address; I got the following output from a single run: constructed foo @ 0x7ffff10bdb7f default argument is at 0x7ffff10bdb60 It shows that only 1 foo was constructed, and not at the same address as that of the default argument. It's been a loooong week, but I can't see anything wrong with the code. In the real code on which this was based, a segfault was occurring when running the destructor of a foo that was move-constructed from the default argument, because the underlying memory was seemingly uninitialised. build command & output ---------------------- [rob@localhost tests]$ g++ -v -save-temps -Wall -Wextra --std=c++0x -fno-strict-aliasing -fwrapv -fno-aggressive-loop-optimizations default-args-fail.cpp -o ./default-args-fail Using built-in specs. COLLECT_GCC=g++ COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.2/lto-wrapper Target: x86_64-redhat-linux Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-gnu-unique-object --enable-linker-build-id --with-linker-hash-style=gnu --enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin --enable-initfini-array --enable-java-awt=gtk --disable-dssi --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-isl=/builddir/build/BUILD/gcc-4.8.2-20131212/obj-x86_64-redhat-linux/isl-install --with-cloog=/builddir/build/BUILD/gcc-4.8.2-20131212/obj-x86_64-redhat-linux/cloog-install --with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux Thread model: posix gcc version 4.8.2 20131212 (Red Hat 4.8.2-7) (GCC) COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-std=c++11' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' './default-args-fail' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-redhat-linux/4.8.2/cc1plus -E -quiet -v -D_GNU_SOURCE default-args-fail.cpp -mtune=generic -march=x86-64 -std=c++11 -Wall -Wextra -fno-strict-aliasing -fwrapv -fno-aggressive-loop-optimizations -fpch-preprocess -o default-args-fail.ii ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.2/include-fixed" ignoring nonexistent directory "/usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../x86_64-redhat-linux/include" #include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2 /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/x86_64-redhat-linux /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../include/c++/4.8.2/backward /usr/lib/gcc/x86_64-redhat-linux/4.8.2/include /usr/local/include /usr/include End of search list. COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-std=c++11' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' './default-args-fail' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-redhat-linux/4.8.2/cc1plus -fpreprocessed default-args-fail.ii -quiet -dumpbase default-args-fail.cpp -mtune=generic -march=x86-64 -auxbase default-args-fail -Wall -Wextra -std=c++11 -version -fno-strict-aliasing -fwrapv -fno-aggressive-loop-optimizations -o default-args-fail.s GNU C++ (GCC) version 4.8.2 20131212 (Red Hat 4.8.2-7) (x86_64-redhat-linux) compiled by GNU C version 4.8.2 20131212 (Red Hat 4.8.2-7), GMP version 5.1.2, MPFR version 3.1.2, MPC version 1.0.1 GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 GNU C++ (GCC) version 4.8.2 20131212 (Red Hat 4.8.2-7) (x86_64-redhat-linux) compiled by GNU C version 4.8.2 20131212 (Red Hat 4.8.2-7), GMP version 5.1.2, MPFR version 3.1.2, MPC version 1.0.1 GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 36de953cba87bab1ad58280401e36d59 COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-std=c++11' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' './default-args-fail' '-shared-libgcc' '-mtune=generic' '-march=x86-64' as -v --64 -o default-args-fail.o default-args-fail.s GNU assembler version 2.23.2 (x86_64-redhat-linux) using BFD version version 2.23.2 COMPILER_PATH=/usr/libexec/gcc/x86_64-redhat-linux/4.8.2/:/usr/libexec/gcc/x86_64-redhat-linux/4.8.2/:/usr/libexec/gcc/x86_64-redhat-linux/:/usr/lib/gcc/x86_64-redhat-linux/4.8.2/:/usr/lib/gcc/x86_64-redhat-linux/ LIBRARY_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.2/:/usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../lib64/:/lib/../lib64/:/usr/lib/../lib64/:/usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../:/lib/:/usr/lib/ COLLECT_GCC_OPTIONS='-v' '-save-temps' '-Wall' '-Wextra' '-std=c++11' '-fno-strict-aliasing' '-fwrapv' '-fno-aggressive-loop-optimizations' '-o' './default-args-fail' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/libexec/gcc/x86_64-redhat-linux/4.8.2/collect2 --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 -o ./default-args-fail /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../lib64/crt1.o /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../lib64/crti.o /usr/lib/gcc/x86_64-redhat-linux/4.8.2/crtbegin.o -L/usr/lib/gcc/x86_64-redhat-linux/4.8.2 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../lib64 -L/lib/../lib64 -L/usr/lib/../lib64 -L/usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../.. default-args-fail.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/x86_64-redhat-linux/4.8.2/crtend.o /usr/lib/gcc/x86_64-redhat-linux/4.8.2/../../../../lib64/crtn.o
...having realised that this might look like I just don't grok move construction I expanded my test - adding copy & move constructors & assignment operators to foo and re-running the test still gives the same result, i.e. the address of the function argument is not the address of a constructed object: constructed foo @ 0x7fff80e0f25f default argument is at 0x7fff80e0f240 (I can attach the enhanced test on request)
Possibly the same issue as Bug 59713
Adding a destructor didn't fix it for me - though it was destroyed for the same address as the constructed object. constructed foo @ 0x7fffa012e5ef default argument is at 0x7fffa012e5d0 destructed foo @ 0x7fffa012e5ef For what it's worth I tried putting a size_t member into the object being constructed, and using a member-initializer to set it to an identifiable bit pattern - even though the temporary was at an 'unconstructed' address, the size_t was repeatedly correct. The gremlins are messing with my head...
The problem only seems to occur when using the pattern "= {}" to default the parameter; "= foo{}" and "= foo()" don't seem to provoke the differing addresses. I have confirmed that member data set in the default constructor seems to be correct in the temporary despite it being at an 'unconstructed' address. The address of the 'unconstructed' temporary is consistently the size of the nearest whole word to sizeof(foo) below the actually-constructed address, so it seems the address isn't just random but possibly correct in itself. It seems that the copy/move constructor has been replaced by a memcpy(), thus losing the side-effects. I didn't state earlier but should confirm: this occurs with "-O0" turning off optimizations. Behaviour with clang (3.3 final) is as expected.
The following is a side-by-side diff of the disassembly of the incorrect version vs. a correct version (defaulting the parameter with = foo{}). The object foo has a single member of type char initialized in default, move, and copy ctors. incorrect version | correct version -------------------------------------------|----------------------------------- push %rbp push %rbp mov %rsp,%rbp mov %rsp,%rbp push %rbx push %rbx sub $0x28,%rsp | sub $0x18,%rsp lea -0x11(%rbp),%rax lea -0x11(%rbp),%rax mov %rax,%rdi mov %rax,%rdi callq 0x400bbe <_ZN3fooC2Ev> | callq 0x400bb8 <_ZN3fooC2Ev> movzbl -0x11(%rbp),%eax | lea -0x11(%rbp),%rax mov %al,-0x30(%rbp) < lea -0x30(%rbp),%rax < mov %rax,%rdi mov %rax,%rdi callq 0x4009f0 <_Z6test_a3foo> | callq 0x400a50 <_Z6test_b3foo> lea -0x11(%rbp),%rax lea -0x11(%rbp),%rax mov %rax,%rdi mov %rax,%rdi callq 0x400bfe <_ZN3fooD2Ev> | callq 0x400bf8 <_ZN3fooD2Ev> mov $0x0,%eax mov $0x0,%eax jmp 0x400b65 <main+85> | jmp 0x400b5e <main+78> mov %rax,%rbx mov %rax,%rbx lea -0x11(%rbp),%rax lea -0x11(%rbp),%rax mov %rax,%rdi mov %rax,%rdi callq 0x400bfe <_ZN3fooD2Ev> | callq 0x400bf8 <_ZN3fooD2Ev> mov %rbx,%rax mov %rbx,%rax mov %rax,%rdi mov %rax,%rdi callq 0x4008b0 <_Unwind_Resume@plt> callq 0x4008b0 <_Unwind_Resume@plt> add $0x28,%rsp | add $0x18,%rsp pop %rbx pop %rbx pop %rbp pop %rbp retq retq It does look like the incorrect version on the left could be bitwise-copying the default-constructed object. As an aside - both versions have a single constructor call but TWO destructor calls...
*** Bug 59713 has been marked as a duplicate of this bug. ***
Jason, I don't think this is a regression, but it can have pretty bad results from seemingly harmless code (double free and other crashes caused by shallow copies instead of calling copy constructors)
Author: jason Date: Mon Mar 10 21:06:59 2014 New Revision: 208465 URL: http://gcc.gnu.org/viewcvs?rev=208465&root=gcc&view=rev Log: PR c++/60367 * call.c (convert_default_arg): Remove special handling for CONSTRUCTOR. Added: trunk/gcc/testsuite/g++.dg/overload/defarg8.C Modified: trunk/gcc/cp/ChangeLog trunk/gcc/cp/call.c
*** Bug 58501 has been marked as a duplicate of this bug. ***
Author: jason Date: Tue May 13 16:05:01 2014 New Revision: 210381 URL: http://gcc.gnu.org/viewcvs?rev=210381&root=gcc&view=rev Log: PR c++/60367 * call.c (convert_default_arg): Remove special handling for CONSTRUCTOR. Added: branches/gcc-4_8-branch/gcc/testsuite/g++.dg/overload/defarg8.C Modified: branches/gcc-4_8-branch/gcc/cp/ChangeLog branches/gcc-4_8-branch/gcc/cp/call.c
Fixed for 4.8.3/4.9.0.
*** Bug 61751 has been marked as a duplicate of this bug. ***
This bug appears to be affecting 4.7.x series as well. Is there a chance to get this fixed for 4.7 as well? http://stackoverflow.com/questions/28837142/stdmap-argument-with-default-empty-map-segfaults-in-gcc
(In reply to Václav Zeman from comment #13) > This bug appears to be affecting 4.7.x series as well. Is there a chance to > get this fixed for 4.7 as well? No, the 4.7 branch is closed and there will be no more 4.7.x releases.