www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 1648] New: Casting a function literal to void* swallows the function or segfaults

reply d-bugmail puremagic.com writes:
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.


-- 
Nov 08 2007
next sibling parent d-bugmail puremagic.com writes:
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


-- 
Nov 08 2007
prev sibling next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
<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.
Nov 08 2007
parent reply Christopher Wright <dhasenan gmail.com> writes:
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.
Nov 08 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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.
Nov 08 2007
prev sibling parent reply d-bugmail puremagic.com writes:
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.


-- 
Nov 08 2007
parent reply Derek Parnell <derek nomail.afraid.org> writes:
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
Nov 08 2007
parent reply Derek Parnell <derek nomail.afraid.org> writes:
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
Nov 08 2007
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"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.
Nov 09 2007