Jump to page: 1 24  
Page
Thread overview
Delegate is left with a destroyed stack object
Oct 29, 2013
Ali Çehreli
Oct 29, 2013
Craig Dillabaugh
Oct 29, 2013
Ali Çehreli
Oct 29, 2013
Jacob Carlborg
Oct 29, 2013
Ali Çehreli
Oct 29, 2013
qznc
Oct 29, 2013
Dicebot
Oct 29, 2013
Peter Alexander
Oct 29, 2013
David Nadlinger
Oct 29, 2013
Ali Çehreli
Oct 29, 2013
Lionello Lunesu
Oct 29, 2013
David Nadlinger
Oct 30, 2013
Lionello Lunesu
Oct 30, 2013
David Nadlinger
Oct 30, 2013
Lionello Lunesu
Oct 30, 2013
Max Samukha
Oct 30, 2013
Max Samukha
Oct 30, 2013
deadalnix
Nov 05, 2013
Marco Leise
Oct 30, 2013
Timon Gehr
Oct 30, 2013
Peter Alexander
Oct 31, 2013
Brian Rogoff
Oct 31, 2013
Jacob Carlborg
Oct 31, 2013
Jakob Ovrum
Oct 31, 2013
Peter Alexander
Oct 29, 2013
David Nadlinger
Oct 29, 2013
Ali Çehreli
Oct 29, 2013
Maxim Fomin
Oct 30, 2013
Jacob Carlborg
Oct 30, 2013
David Nadlinger
Oct 30, 2013
Ali Çehreli
Oct 31, 2013
Xiaoxi
Oct 31, 2013
Maxim Fomin
Oct 31, 2013
Timon Gehr
October 29, 2013
Continuing the conversation from the following thread:

  http://forum.dlang.org/post/l4mi8l$1r1$1@digitalmars.com

(Note: The OP's example there behaves as expected on git head.)

The programmer thinks that the following delegate returned by foo() will print S(1) because the delegate uses the local 's' which is supposed to live long enough:

import std.stdio;

struct S
{
    int i;
    ~this() { i = 666; }
}

auto foo()
{
    S s = S(1);
    return { writeln(s); } ;  // <-- Uses local s
}

void main()
{
    foo()();
}

However, 's' gets destroyed upon leaving foo() and the delegate is left with a destroyed object; so the program prints S(666).

Is that by design or a bug?

Aside: Never mind that the destroyed object gets destroyed again, and again, and again. :) (Well, presumably after being copied to other object in its dead state, because the address of the object is not the same.) (Put a writeln() inside the destructor to see that in action.)

Ali
October 29, 2013
On Tuesday, 29 October 2013 at 17:55:45 UTC, Ali Çehreli wrote:
> Continuing the conversation from the following thread:
>
>   http://forum.dlang.org/post/l4mi8l$1r1$1@digitalmars.com
>
> (Note: The OP's example there behaves as expected on git head.)
>
> The programmer thinks that the following delegate returned by foo() will print S(1) because the delegate uses the local 's' which is supposed to live long enough:
>
> import std.stdio;
>
> struct S
> {
>     int i;
>     ~this() { i = 666; }
> }
>
> auto foo()
> {
>     S s = S(1);
>     return { writeln(s); } ;  // <-- Uses local s
> }
>
> void main()
> {
>     foo()();
> }
>
> However, 's' gets destroyed upon leaving foo() and the delegate is left with a destroyed object; so the program prints S(666).
>
> Is that by design or a bug?
>
> Aside: Never mind that the destroyed object gets destroyed again, and again, and again. :) (Well, presumably after being copied to other object in its dead state, because the address of the object is not the same.) (Put a writeln() inside the destructor to see that in action.)
>
> Ali

According to the Book of Revelations, 666 is the number of the
Beast (Rev. 13:18), and later (Revelations 19:20) it is stated
that the Beast will be thrown into a lake of fire and brimstone.

That may explain the repeated destruction of s :o)

Whether that is a bug or not, I am unsure.

Craig
October 29, 2013
On 2013-10-29 18:55, Ali Çehreli wrote:
> Continuing the conversation from the following thread:
>
>    http://forum.dlang.org/post/l4mi8l$1r1$1@digitalmars.com
>
> (Note: The OP's example there behaves as expected on git head.)
>
> The programmer thinks that the following delegate returned by foo() will
> print S(1) because the delegate uses the local 's' which is supposed to
> live long enough:
>
> import std.stdio;
>
> struct S
> {
>      int i;
>      ~this() { i = 666; }
> }
>
> auto foo()
> {
>      S s = S(1);
>      return { writeln(s); } ;  // <-- Uses local s
> }
>
> void main()
> {
>      foo()();
> }
>
> However, 's' gets destroyed upon leaving foo() and the delegate is left
> with a destroyed object; so the program prints S(666).
>
> Is that by design or a bug?
>
> Aside: Never mind that the destroyed object gets destroyed again, and
> again, and again. :) (Well, presumably after being copied to other
> object in its dead state, because the address of the object is not the
> same.) (Put a writeln() inside the destructor to see that in action.)
>
> Ali

Shouldn't "s" be moved to the heap and not destroyed.

-- 
/Jacob Carlborg
October 29, 2013
On 10/29/2013 12:02 PM, Craig Dillabaugh wrote:

> the Beast will be thrown into a lake of fire and brimstone.
>
> That may explain the repeated destruction of s :o)

That's awesome! :)

Ali

October 29, 2013
On 10/29/2013 01:23 PM, Jacob Carlborg wrote:

> Shouldn't "s" be moved to the heap and not destroyed.

We are waiting for Walter to say the same thing and Kenji Hara to fix it last month. ;)

Ali

October 29, 2013
On Tuesday, 29 October 2013 at 17:55:45 UTC, Ali Çehreli wrote:
> Continuing the conversation from the following thread:
>
>   http://forum.dlang.org/post/l4mi8l$1r1$1@digitalmars.com
>
> (Note: The OP's example there behaves as expected on git head.)
>
> The programmer thinks that the following delegate returned by foo() will print S(1) because the delegate uses the local 's' which is supposed to live long enough:
>
> import std.stdio;
>
> struct S
> {
>     int i;
>     ~this() { i = 666; }
> }
>
> auto foo()
> {
>     S s = S(1);
>     return { writeln(s); } ;  // <-- Uses local s
> }
>
> void main()
> {
>     foo()();
> }
>
> However, 's' gets destroyed upon leaving foo() and the delegate is left with a destroyed object; so the program prints S(666).
>
> Is that by design or a bug?

Seems reasonable to me.

S s = S(1); // allocates on the stack, because value type, i is now 1
{ writeln(s); } // creates closure with reference to stack memory "&s"
return ... // returns and destroys local variable s, i is now 666
foo()() // calls closure with reference to invalid memory "&s"

Returning closures with reference to stack memory is a bad idea. Maybe @safe should prohibit this?
October 29, 2013
http://dlang.org/function.html

> The stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure.
October 29, 2013
On Tuesday, 29 October 2013 at 21:14:39 UTC, qznc wrote:
> Returning closures with reference to stack memory is a bad idea. Maybe @safe should prohibit this?

According to http://dlang.org/function.html

"The stack variables referenced by a nested function are still valid even after the function exits (this is different from D 1.0). This is called a closure."

It it completely valid to reference that memory. It gets moved onto the heap when you create the closure. The problem is that the destructor still gets called, so the variable is no longer in a valid state post return.
October 29, 2013
On Tuesday, 29 October 2013 at 21:14:39 UTC, qznc wrote:
> { writeln(s); } // creates closure with reference to stack memory "&s"
> return ... // returns and destroys local variable s, i is now 666
> foo()() // calls closure with reference to invalid memory "&s"

That's not how closures work in D – the local variables referenced by nested functions/closures will be allocated inside the "nested context" for the function, which is placed on the GC heap if a reference to it can be escaped. Play around with the example some more if you want: Barring any further DMD bugs, you are not going to get the contents of i to be corrupted (i.e. set to another garbage value).

The problem with the compiler behavior for the code in question is that it destructs a live object, and thus clearly breaks the type system.

I think the only correct resolution is to not destruct the object at the end of foo() – which incidentally also means that the destructor will never be invoked, just as for any other GC-finalized memory.

David
October 29, 2013
On 10/29/2013 02:32 PM, David Nadlinger wrote:

> The problem with the compiler behavior for the code in question is that
> it destructs a live object, and thus clearly breaks the type system.
>
> I think the only correct resolution is to not destruct the object at the
> end of foo() – which incidentally also means that the destructor will
> never be invoked, just as for any other GC-finalized memory.

To add to that, Maxim Fomin notes in the D.learn forum that there are the following conflicting requirements:

1) need to allocate struct into heap due to lambda

2) need to put dtor invocation in the end as usual.

The first one is supported by the closure spec. The second one is the well-know struct destruction upon leaving a scope.

Ali

« First   ‹ Prev
1 2 3 4