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
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