Thread overview
[Issue 1648] New: Casting a function literal to void* swallows the function or segfaults
Nov 08, 2007
d-bugmail
Nov 08, 2007
d-bugmail
Nov 08, 2007
Christopher Wright
Nov 08, 2007
d-bugmail
Nov 08, 2007
Derek Parnell
Nov 09, 2007
Derek Parnell
November 08, 2007
http://d.puremagic.com/issues/show_bug.cgi?id=1648

           Summary: Casting a function literal to void* swallows the
                    function or segfaults
           Product: D
           Version: 2.007
          Platform: PC
        OS/Version: Linux
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla@digitalmars.com
        ReportedBy: dhasenan@gmail.com


When saving a delegate as a void* and only using one delegate from the same function, attempts to execute the delegate by casting to the original type do nothing.

When saving multiple delegates from the same function, if any of them are cast to void*, a segmentation fault occurs.

Casting is inherently dangerous, I know, but there's no other way to pass a delegate while ignoring its type.


-- 

November 08, 2007
http://d.puremagic.com/issues/show_bug.cgi?id=1648





------- Comment #1 from dhasenan@gmail.com  2007-11-08 08:04 -------
Created an attachment (id=204)
 --> (http://d.puremagic.com/issues/attachment.cgi?id=204&action=view)
a test case that shows the problem


-- 

November 08, 2007
<d-bugmail@puremagic.com> wrote in message news:bug-1648-3@http.d.puremagic.com/issues/...
> http://d.puremagic.com/issues/show_bug.cgi?id=1648
>
>           Summary: Casting a function literal to void* swallows the
>                    function or segfaults
>           Product: D
>           Version: 2.007
>          Platform: PC
>        OS/Version: Linux
>            Status: NEW
>          Severity: normal
>          Priority: P2
>         Component: DMD
>        AssignedTo: bugzilla@digitalmars.com
>        ReportedBy: dhasenan@gmail.com
>
>
> When saving a delegate as a void* and only using one delegate from the
> same
> function, attempts to execute the delegate by casting to the original type
> do
> nothing.
>
> When saving multiple delegates from the same function, if any of them are
> cast
> to void*, a segmentation fault occurs.
>
> Casting is inherently dangerous, I know, but there's no other way to pass
> a
> delegate while ignoring its type.
>
>
> -- 
>

delegate.sizeof != (void*).sizeof.

It's no real surprise that this doesn't work.  Delegates are not simple pointers; they are actually a struct with two members, but you shouldn't really be relying on the underlying implementation in any way.

What is it that you're trying to do, anyway?  Delegates are strongly typed for a reason -- the compiler can't generate the correct call sequence unless it knows the exact type of the delegate.  There's probably a much better way of doing what you want.


November 08, 2007
Jarrett Billingsley wrote:
> <d-bugmail@puremagic.com> wrote in message news:bug-1648-3@http.d.puremagic.com/issues/...
>> http://d.puremagic.com/issues/show_bug.cgi?id=1648
>>
>>           Summary: Casting a function literal to void* swallows the
>>                    function or segfaults
>>           Product: D
>>           Version: 2.007
>>          Platform: PC
>>        OS/Version: Linux
>>            Status: NEW
>>          Severity: normal
>>          Priority: P2
>>         Component: DMD
>>        AssignedTo: bugzilla@digitalmars.com
>>        ReportedBy: dhasenan@gmail.com
>>
>>
>> When saving a delegate as a void* and only using one delegate from the same
>> function, attempts to execute the delegate by casting to the original type do
>> nothing.
>>
>> When saving multiple delegates from the same function, if any of them are cast
>> to void*, a segmentation fault occurs.
>>
>> Casting is inherently dangerous, I know, but there's no other way to pass a
>> delegate while ignoring its type.
>>
>>
>> -- 
>>
> 
> delegate.sizeof != (void*).sizeof.
> 
> It's no real surprise that this doesn't work.  Delegates are not simple pointers; they are actually a struct with two members, but you shouldn't really be relying on the underlying implementation in any way.
> 
> What is it that you're trying to do, anyway?  Delegates are strongly typed for a reason -- the compiler can't generate the correct call sequence unless it knows the exact type of the delegate.  There's probably a much better way of doing what you want. 

(delegate*).sizeof == (void*).sizeof
The example casted the address of the delegate to void*.

I tried using Variant.coerce to retrieve a boxed delegate, but that failed (delegates aren't numeric types, objects, or strings, and coerce only supports those). Now I've found that Variant.peek does support delegates, so I'm set.
November 08, 2007
"Christopher Wright" <dhasenan@gmail.com> wrote in message news:fgve35$eet$1@digitalmars.com...
>
> (delegate*).sizeof == (void*).sizeof
> The example casted the address of the delegate to void*.
>

Ah, looking at your code again, I realize that I was wrong in reading it. Now I notice that it's just plain wrong:

void send (void delegate () func) {
    _funcptr = cast(void*)&func;
}

This is entirely wrong.  You're storing the address of a local variable in a class member, and then trying to call that in another function.  A quality compiler would give a warning/error on this, as it's an escaping reference to a local variable.


November 08, 2007
http://d.puremagic.com/issues/show_bug.cgi?id=1648


dhasenan@gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID




------- Comment #3 from dhasenan@gmail.com  2007-11-08 17:14 -------
As Jarrett Billingsley pointed out, the error was in my code: taking the address of a local variable.


-- 

November 08, 2007
On Thu, 8 Nov 2007 23:14:59 +0000 (UTC), d-bugmail@puremagic.com wrote:

> http://d.puremagic.com/issues/show_bug.cgi?id=1648
> 
> dhasenan@gmail.com changed:
> 
>            What    |Removed                     |Added
> ----------------------------------------------------------------------------
>              Status|NEW                         |RESOLVED
>          Resolution|                            |INVALID
> 
> ------- Comment #3 from dhasenan@gmail.com  2007-11-08 17:14 -------
> As Jarrett Billingsley pointed out, the error was in my code: taking the address of a local variable.

I made a slight change to the code and it seems to work. The 'send' member function now receives the address of the delegate rather than the delegate itself.

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

class Foo {
    private void* _funcptr;
    private void delegate()  _func;
    void send (void delegate ()* func) {
        _funcptr = cast(void*)func;
    }

    void sendTyped (void delegate () func) {
        _func = func;
    }

    void execute () {
        auto func = *cast(void delegate ()*) _funcptr;
        func();
    }

    void executeTyped () {
        _func();
    }
}

void main () {
    Foo foo = new Foo();
    // The following does nothing:
    auto func = { writefln("greetings"); };
    foo.send(&func);
    foo.execute();

    /* Uncommenting the following lines produces a segfault.
       Commenting the preceding lines and uncommenting the following
       produces the expected output. */
    foo.sendTyped({ writefln("this one is typed"); });
    foo.executeTyped();
}
-----------
-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
9/11/2007 10:46:28 AM
November 09, 2007
On Fri, 9 Nov 2007 10:48:15 +1100, Derek Parnell wrote:


> I made a slight change to the code and it seems to work.

Another change to make it clearer to read...

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

class Foo {
    alias void delegate()  dg;
    private dg* _funcptr;
    private dg  _func;

    void send (dg* func) {
        _funcptr = func;
    }

    void send (dg func) {
        _func = func;
        _funcptr = &_func;
    }

    void execute () {
        (*_funcptr)();
    }

}

void main () {
    Foo foo = new Foo();

    auto func = { writefln("greetings"); };
    foo.send(&func);
    foo.execute();

    foo.send({ writefln("this one is typed"); });
    foo.execute();
}
----------

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
9/11/2007 10:59:25 AM
November 09, 2007
"Derek Parnell" <derek@nomail.afraid.org> wrote in message news:1pvgn2j8ihvm$.1tg724zepcfnz.dlg@40tude.net...

> import std.stdio;
>
> class Foo {
>    alias void delegate()  dg;
>    private dg* _funcptr;
>    private dg  _func;
>
>    void send (dg* func) {
>        _funcptr = func;
>    }
>
>    void send (dg func) {
>        _func = func;
>        _funcptr = &_func;
>    }
>
>    void execute () {
>        (*_funcptr)();
>    }
>
> }
>
> void main () {
>    Foo foo = new Foo();
>
>    auto func = { writefln("greetings"); };
>    foo.send(&func);
>    foo.execute();
>
>    foo.send({ writefln("this one is typed"); });
>    foo.execute();
> }

That works, but you still have to make sure that you don't return from the function that called foo.send before calling foo.execute (assuming that all this doesn't necessarily happen in main).  If you made 'func' static, it'd be fine.