D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 14639 - Assigning init value to struct uses stack, causing segfault
Summary: Assigning init value to struct uses stack, causing segfault
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: x86_64 Linux
: P1 normal
Assignee: No Owner
URL:
Keywords: pull
Depends on:
Blocks:
 
Reported: 2015-06-01 06:49 UTC by Tomer Filiba (weka)
Modified: 2020-03-28 09:29 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Tomer Filiba (weka) 2015-06-01 06:49:30 UTC
Consider the following snippet:

    struct Biggy {
        ulong[50000] a;
    }
    __gshared Biggy biggy;

    void main() {
        biggy = Biggy.init;
    }

produces the following code

    Dump of assembler code for function _Dmain:
    ...
    => 0x000000000047fa04 <+4>:	movabs $0x6faef0,%rsi
       0x000000000047fa0e <+14>:	movabs $0x7d6a90,%rdi
       0x000000000047fa18 <+24>:	mov    $0x1b774,%ecx
       0x000000000047fa1d <+29>:	rep movsq %ds:(%rsi),%es:(%rdi)

which is fine. However, adding a @disable this(this) to Biggy, i.e.,

    struct Biggy {
        ulong[50000] a;
        @disable this(this);
    }

produces

    Dump of assembler code for function _Dmain:
    ...
    => 0x000000000047fba4 <+4>:	movabs $0x7d6a88,%rsi
       0x000000000047fbae <+14>:	mov    $0x1b774,%ecx
       0x000000000047fbb3 <+19>:	pushq  (%rsi)
       0x000000000047fbb5 <+21>:	sub    $0x8,%rsi
       0x000000000047fbb9 <+25>:	loop   0x47fbb3 <_Dmain+19>
       0x000000000047fbbb <+27>:	movabs $0x7d6a90,%rdi
       0x000000000047fbc5 <+37>:	callq  0x47fb70 <_D7themain5Biggy8opAssignMFNaNbNcNiNjNfS7themain5BiggyZS7themain5Biggy>
       0x000000000047fbca <+42>:	add    $0xdbba0,%rsp

which, as you can see, copies Biggy.init onto the *stack* and then calls opAssign on it. Notice that Biggy does not define opAssign, and even if it did,  it doesn't make sense to *copy* the type's init to a temp location. 

Now since Biggy is big (~400KB), and the function is run on a stack-constrained fiber, we got a very peculiar segfault. 

Is there any reason for this odd behavior? I would have used memcpy, but &Biggy.init won't compile. 


-tomer (weka.io)
Comment 1 Walter Bright 2017-05-10 09:51:20 UTC
What's happening is the existence of the postblit, even though disabled, causes the compiler to do the assignment by calling opAssign, where the argument is passed by value. Passing by value means pushing it to the stack.
Comment 2 Walter Bright 2017-05-10 10:19:19 UTC
https://github.com/dlang/dmd/pull/6766
Comment 3 Walter Bright 2017-05-10 15:50:27 UTC
The code:

    biggy = Biggy.init;

gets rewritten to be:

    biggy = Biggy([0LU, ...]);

which is a construction. The postblit caused an opAssign() to be created, and the expression is further rewritten to:

    biggy.opAssign(Biggy([0LU, ...]));

which blows up the parameter stack because Biggy([0LU, ...]) is too big for it. The operation is not disabled because it gets constructed in place - a copy is not being made.

A possible compiler fix is to figure out that the generated opAssign is trivial and can be replaced with a bit copy. The code in opover.d:

                if (sd && !sd.hasIdentityAssign)
                {
                    /* This is bitwise struct assignment. */
                    return;
                }

can be modified to test for triviality of identity assign, and use a bitwise copy.
Comment 4 Walter Bright 2020-03-27 06:11:14 UTC
This:

    https://github.com/dlang/dmd/pull/10967

changes the

    biggy = Biggy.init;

implementation into a memset.
Comment 5 Dlang Bot 2020-03-27 08:22:31 UTC
@WalterBright updated dlang/dmd pull request #6766 "fix Issue 14639 - Assigning init value to struct uses stack, causing …" fixing this issue:

- fix Issue 14639 - Assigning init value to struct uses stack, causing segfault

https://github.com/dlang/dmd/pull/6766
Comment 6 Dlang Bot 2020-03-28 09:29:24 UTC
dlang/dmd pull request #6766 "fix Issue 14639 - Assigning init value to struct uses stack, causing …" was merged into master:

- a0b0b5783bffd806a45870d71aaa29c3883e5d7e by Walter Bright:
  fix Issue 14639 - Assigning init value to struct uses stack, causing segfault

https://github.com/dlang/dmd/pull/6766