Consider the sample C++ program below where we have two classes, Custom and Defaulted, and two functions that have call-by-value arguments of types Custom and Defaulted, respectively. ~~~ #include <iostream> class Custom { public: Custom () { x = 10; } Custom (const Custom &arg) { x = 20; } int x; }; class Defaulted { public: Defaulted () { x = 30; } Defaulted (const Defaulted &arg) = default; int x; }; void cbv_custom (Custom c) { c.x += 1; std::cout << c.x << std::endl; } void cbv_defaulted (Defaulted d) { d.x += 1; std::cout << d.x << std::endl; } int main () { Custom custom; Defaulted def; cbv_custom (custom); cbv_defaulted (def); return 0; } ~~~ "Custom" has a user-defined copy-constructor. For this reason it is a non-trivial type and should be passed implicitly by reference. "Defaulted" is a trivial type and should be passed by value. ~~~ $ gdb -q ./sample Reading symbols from ./sample... (gdb) b 38 Breakpoint 1 at 0x1276: file sample.cpp, line 38. (gdb) run Starting program: /path/to/sample 21 31 Breakpoint 1, main () at sample.cpp:38 38 return 0; (gdb) p custom $1 = {x = 10} (gdb) p def $2 = {x = 30} ~~~ Let us now call cbv_custom. The expected output is 21. ~~~ (gdb) p cbv_custom(custom) 11 $3 = void (gdb) p custom $4 = {x = 11} ~~~ Here, GDB should have created a clone of the 'custom' object via the copy ctor and passed that clone to the function. However, GDB passed the 'custom' object itself, even without creating a naive copy. Let's now call the cbv_defaulted function. The expected output is 31. ~~~ (gdb) p cbv_defaulted(def) -11295 $5 = void ~~~ The return value seems like garbage at first sight, but it's not. ~~~ (gdb) p/x -11295 $6 = 0xffffd3e1 (gdb) p &def $7 = (Defaulted *) 0x7fffffffd3e0 ~~~ Here, GDB incorrectly inferred that Defaulted is non-trivial. Hence, it decided to pass the reference of the 'def' object as the argument, but it should've passed the argument by value. A set of patches that addresses this problem and its vicinity is available at https://sourceware.org/ml/gdb-patches/2019-06/msg00517.html
The master branch has been updated by Tankut Baris Aktemur <aktemur@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=099a6354dab7e74c990501929f383394fc8efd02 commit 099a6354dab7e74c990501929f383394fc8efd02 Author: Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> Date: Fri Dec 20 17:43:06 2019 +0100 infcall: handle pass-by-reference arguments appropriately If an aggregate argument is implicitly pass-by-reference, allocate a temporary object on the stack, initialize it via the copy constructor (if exists) or trivially by memcpy'ing. Pass the reference of the temporary to the callee function. After the callee returns, invoke the destructor of the temporary. gdb/ChangeLog: 2019-12-20 Tankut Baris Aktemur <tankut.baris.aktemur@intel.com> PR gdb/25054 * infcall.c (call_function_by_hand_dummy): Update the argument- passing section for call-by-value parameters. (struct destructor_info): New struct. (call_destructors): New auxiliary function. Change-Id: I18fa5d0df814dfa0defe9e862a88a6dbf1d99d01
Fixed with commit 099a6354dab7e74c990501929f383394fc8efd02 (and a few more direct/indirect predecessor commits).