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

Reply via email to