public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug c++/109495] New: Stack is used (unexpectedly) for copying on-heap objects (while clang doesn't)
@ 2023-04-13 11:08 gcc-bug-reports at xhtml dot guru
  2023-04-13 11:10 ` [Bug c++/109495] Stack is used (unexpectedly) for copying on-heap objects (no problem in clang) gcc-bug-reports at xhtml dot guru
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: gcc-bug-reports at xhtml dot guru @ 2023-04-13 11:08 UTC (permalink / raw)
  To: gcc-bugs

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

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-04-14  8:12 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-04-13 11:08 [Bug c++/109495] New: Stack is used (unexpectedly) for copying on-heap objects (while clang doesn't) gcc-bug-reports at xhtml dot guru
2023-04-13 11:10 ` [Bug c++/109495] Stack is used (unexpectedly) for copying on-heap objects (no problem in clang) gcc-bug-reports at xhtml dot guru
2023-04-13 11:49 ` [Bug middle-end/109495] " rguenth at gcc dot gnu.org
2023-04-13 12:16 ` jakub at gcc dot gnu.org
2023-04-13 12:45 ` rguenth at gcc dot gnu.org
2023-04-13 12:59 ` rguenth at gcc dot gnu.org
2023-04-13 13:00 ` jakub at gcc dot gnu.org
2023-04-14  8:12 ` rguenth at gcc dot gnu.org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).