https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109495
Bug ID: 109495 Summary: Stack is used (unexpectedly) for copying on-heap objects (while clang doesn't) Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: gcc-bug-reports at xhtml dot guru Target Milestone: --- Could be a bug or could be a feature -- can't tell. Please help understand why GCC involves stack in certain conditions when copying on-heap objects (no problem in clang). Problem: In actual live project I have a large struct/class with a lot of data in it ("a lot" is defined as larger than Wframe-larger-than), I've also got many locations where that struct is copied (directly or indirectly), and got Wframe-larger-than enabled. In some cases I'm hitting the error on lines that _indirectly_ copy-construct the object from an object that's stored on heap into an object that is also stored on heap (i.e. heap-to-heap operation, if you will). After finding minimal case that reproduces the issue (https://godbolt.org/z/xcnP9E39a), disassembling the code and looking into potential reasons why GCC might want to use the stack (and thus trigger Wframe-larger-than), I see that (subjectively for no apparent reason) GCC involves stack as an intermediate buffer, which I am looking to avoid. clang doesn't use intermediate buffer in this same scenario. Some surprising observations (which make the problem go away) might be indicative of a bug in GCC: 1) If private member "y" of class Parent is made public, Wframe-larger-than goes away (https://godbolt.org/z/G7x5EWKEf); 2) If type of member "s" of struct Child is changed from std::string to int, the problem goes away (https://godbolt.org/z/zK6Wjj8nK); 3) If class Parent is adjusted so that there is no padding at the end, for example by changing type of "z" member of class Parent to short (https://godbolt.org/z/jsbsc6jcb) or by deleting member "z" altogether (https://godbolt.org/z/3jqaoKse9), the problem goes away; 4) If inheritance is taken out of the equation, for example by aggregating class Parent below class Child (instead of inheriting; https://godbolt.org/z/451K1s7bc), the problem goes away. Expected behavior: GCC not reporting Wframe-larger-than. Actual behavior: GCC reports Wframe-larger-than. // Code (attached as test.cpp): #include <string> class Parent { private: unsigned char y[ 1024 * 64 ]; // Beef up class' size past Wframe-larger-than public: short x; // sizeof == 2 -> increases alignment requirement to 2 char z; // sizeof == 1 -> triggers padding (1) at the end of struct }; struct Child : public Parent { std::string s; }; int main( int, char** ) { auto* ptr = new Child(); auto* ptr2 = new Child( *ptr ); // g++ reports frame-larger-than violation; clang doesn't. delete ptr2; delete ptr; return 0; } // Environment (gcc version): $ g++ --version g++ (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0 Copyright (C) 2021 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. // but it could be any GCC version. // Command line (gcc; https://godbolt.org/z/xcnP9E39a): $ g++ -Werror -Wframe-larger-than=4096 -o test test.cpp /code/Src/E2EE/dstepanovs.cpp: In copy constructor ‘Child::Child(const Child&)’: /code/Src/E2EE/dstepanovs.cpp:14:8: error: the frame size of 65568 bytes is larger than 4096 bytes [-Werror=frame-larger-than=] 14 | struct Child : public Parent | ^~~~~ cc1plus: all warnings being treated as errors // Compiling same code with same flags with clang yields no error (clang command line; https://godbolt.org/z/PMq5Yr3Tn): $ clang++ -Werror -Wframe-larger-than=4096 -o test test.cpp