www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 9352] New: Memory corruption in delegate called by struct dtor

reply d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9352

           Summary: Memory corruption in delegate called by struct dtor
           Product: D
           Version: D2
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: major
          Priority: P2
         Component: DMD
        AssignedTo: nobody puremagic.com
        ReportedBy: hsteoh quickfur.ath.cx


--- Comment #0 from hsteoh quickfur.ath.cx 2013-01-18 12:07:19 PST ---
Code:

------------SNIP-----------
import std.stdio;

static ubyte canary[32] = [
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
        20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
];

struct S {
        ubyte[32] t;
        void delegate()[] destructor;

        this(int dummy) {
                t[] = canary[];
                writefln("ctor: %s", t);

                destructor ~= {
                        writefln("deleg: %s", t);
                };
        }

        ~this() {
                writefln("dtor: %s", t);

                // we're just undoing everything the constructor did, in
                // reverse order, same criteria
                foreach_reverse(d; destructor)
                        d();
        }
}

auto abc(int dummy) {
        return S(0);
}

void main() {
        auto input = abc(0);
        writefln("main: %s", input.t);
}
------------SNIP-----------

Output:
------------SNIP-----------
ctor: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
main: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
dtor: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
deleg: [0, 0, 0, 0, 0, 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 240, 239, 168,
189, 184, 127, 0, 0, 152, 34, 64, 0, 0, 0, 0, 0]
------------SNIP-----------

This code was minimized from Adam Ruppe's terminal.d. The function abc(int
dummy) is necessary; if S is constructed in main, the problem does not occur.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 18 2013
next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9352


Adam D. Ruppe <destructionator gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |destructionator gmail.com


--- Comment #1 from Adam D. Ruppe <destructionator gmail.com> 2013-01-18
12:15:10 PST ---
I think what's happening here is the delegate stores a pointed to the struct
made in the ctor, which is on the stack. It gets moved when it returns from the
function, but the delegate still points at the old memory, which gets
overwritten by whatever.

I figure the best fix would be for the struct copy to update the delegate
pointer (if I'm right about what's going on).

OR, we could ban it, since that is a (hidden) internal pointer which i think is
banned by the D spec.. probably for exactly this reason.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 18 2013
prev sibling next sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9352



--- Comment #2 from hsteoh quickfur.ath.cx 2013-01-18 12:22:26 PST ---
You're right, I added some writeln's to print the address of S.t, and here's
what I got:

ctor: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
canary address: 7FFF8F541110
main: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
canary address: 7FFF8F541190
dtor: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
canary address: 7FFF8F541190
deleg: [0, 0, 0, 0, 0, 0, 0, 0, 160, 111, 66, 0, 0, 0, 0, 0, 240, 79, 99, 213,
136, 127, 0, 0, 176, 34, 64, 0, 0, 0, 0, 0]
canary address: 7FFF8F541110

Notice that both in main and in the dtor, a different address from the original
address in the ctor is used. However, the delegate is using the original
address instead of the new address. So the problem is indeed that the delegate
is pointing to the invalidated copy of the struct.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 18 2013
prev sibling parent d-bugmail puremagic.com writes:
http://d.puremagic.com/issues/show_bug.cgi?id=9352



--- Comment #3 from hsteoh quickfur.ath.cx 2013-01-18 12:25:33 PST ---
Rather than banning this outright, I think a better approach may be to detect
when a delegate is referencing the struct on the stack, and create the struct
on the heap instead. Sorta like how local variables will be allocated on the
heap instead of the stack if the function returns a delegate that references
them.

(But I'm not sure how feasible it is to do this in a struct ctor, though!)

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
Jan 18 2013