Thread overview
[Issue 2318] New: flaw code generation building a function pointer table
Aug 27, 2008
d-bugmail
Sep 03, 2008
Sivo Schilling
Apr 08, 2009
d-bugmail
Feb 01, 2010
Don
August 27, 2008
http://d.puremagic.com/issues/show_bug.cgi?id=2318

           Summary: flaw code generation building a function pointer table
           Product: D
           Version: 1.034
          Platform: PC
        OS/Version: Windows
            Status: NEW
          Severity: normal
          Priority: P2
         Component: DMD
        AssignedTo: bugzilla@digitalmars.com
        ReportedBy: enzo.petrelli@fastwebnet.it


/***************************
        OS:                                     Vista SP1
        Compiler/linker:        Digital Mars D Compiler v1.034
        Tango/tangobos Lib:     tango-0.99.7-bin-win32-dmd.1.033
        Compiled with:          dmd -g -debug epfuntbl.d

        Debug version:
        Trying to build a table of 5 function pointers out of
        5 struct members, 1st and 3rd items are uncorrectly
        asssigned values

        Release version:
        A similar but slightly different behaviour is shown.
        Further, an "Access violation" is raised

 ***************************/

import std.cstream;

alias void function()   FnPtr;

void initTTest(TTest * pTst)
{
//      pTst.pVtbl = cast(void*) pTst.apFnc.ptr;
        pTst.apFnc[0] = cast(FnPtr) &pTst.func0;
        pTst.apFnc[1] = cast(FnPtr) &pTst.func1;
        pTst.apFnc[2] = cast(FnPtr) &pTst.func2;
        pTst.apFnc[3] = cast(FnPtr) &pTst.func3;
        pTst.apFnc[4] = cast(FnPtr) &pTst.func4;
}

struct TTest
{
        void *          pVtbl;
        FnPtr[5]        apFnc;

        void func0()
        {
                dout.writefln("func0");
        }
        void func1()
        {
                dout.writefln("func1");
        }
        void func2()
        {
                dout.writefln("func2");
        }
        void func3()
        {
                dout.writefln("func3");
        }
        void func4()
        {
                dout.writefln("func4");
        }
}

void main()
{
        TTest * pTst = new TTest;
        initTTest(pTst);
        for (int iIdx = 0; iIdx < pTst.apFnc.length; ++iIdx)
                dout.writefln("item#%d:0x%08X", iIdx, cast(int)
pTst.apFnc[iIdx]);
        pTst.apFnc[1]();
        pTst.apFnc[3]();
        pTst.apFnc[4]();
}

/*
execution produces:

item#0:0x019F3FE0
item#1:0x004020AC
item#2:0x019F3FE0
item#3:0x0040215C
item#4:0x004021B4
func1
func3
func4
*/

/*
disassembly shows that wrong code is generated for the 1st and 3rd
function pointer assignments:
function address is loaded into a register but the destination is
written from another one

5:    void initTTest(TTest * pTst)
00402010   enter       4,0
00402014   push        ebx
00402015   push        esi
00402016   mov         dword ptr [ebp-4],eax
6:    {
7:    //  pTst.pVtbl = cast(void*) pTst.apFnc.ptr;
8:        pTst.apFnc[0] = cast(FnPtr) &pTst.func0;
00402019   mov         eax,dword ptr [pTst]
0040201C   mov         ecx,offset _D8epfuntbl5TTest5func0MFZv (00402054)
00402021   mov         edx,dword ptr [pTst]
00402024   mov         dword ptr [edx+4],eax
9:        pTst.apFnc[1] = cast(FnPtr) &pTst.func1;
00402027   mov         ebx,edx
00402029   mov         ecx,offset _D8epfuntbl5TTest5func1MFZv (004020ac)
0040202E   mov         dword ptr [edx+8],ecx
10:       pTst.apFnc[2] = cast(FnPtr) &pTst.func2;
00402031   mov         eax,edx
00402033   mov         ecx,offset _D8epfuntbl5TTest5func2MFZv (00402104)
00402038   mov         dword ptr [edx+0Ch],eax
11:       pTst.apFnc[3] = cast(FnPtr) &pTst.func3;
0040203B   mov         esi,edx
0040203D   mov         ecx,offset _D8epfuntbl5TTest5func3MFZv (0040215c)
00402042   mov         dword ptr [edx+10h],ecx
12:       pTst.apFnc[4] = cast(FnPtr) &pTst.func4;
00402045   mov         ebx,edx
00402047   mov         ecx,offset _D8epfuntbl5TTest5func4MFZv (004021b4)
0040204C   mov         dword ptr [edx+14h],ecx
13:   }
0040204F   pop         esi
00402050   pop         ebx
00402051   leave
00402052   ret
00402053   int         3
*/


-- 

September 03, 2008
If you declare FnPtr as  void delegate() then these issues are gone. This works with both DMD 1.034 and DMD 2.018 on Win XP SP3 but using phobos instead of Tango/tangobos.


d-bugmail@puremagic.com Wrote:

> http://d.puremagic.com/issues/show_bug.cgi?id=2318
> 
>            Summary: flaw code generation building a function pointer table
>            Product: D
>            Version: 1.034
>           Platform: PC
>         OS/Version: Windows
>             Status: NEW
>           Severity: normal
>           Priority: P2
>          Component: DMD
>         AssignedTo: bugzilla@digitalmars.com
>         ReportedBy: enzo.petrelli@fastwebnet.it
> 
> 
> /***************************
>         OS:                                     Vista SP1
>         Compiler/linker:        Digital Mars D Compiler v1.034
>         Tango/tangobos Lib:     tango-0.99.7-bin-win32-dmd.1.033
>         Compiled with:          dmd -g -debug epfuntbl.d
> 
>         Debug version:
>         Trying to build a table of 5 function pointers out of
>         5 struct members, 1st and 3rd items are uncorrectly
>         asssigned values
> 
>         Release version:
>         A similar but slightly different behaviour is shown.
>         Further, an "Access violation" is raised
> 
>  ***************************/
> 
> import std.cstream;
> 
> alias void function()   FnPtr;
> 
> void initTTest(TTest * pTst)
> {
> //      pTst.pVtbl = cast(void*) pTst.apFnc.ptr;
>         pTst.apFnc[0] = cast(FnPtr) &pTst.func0;
>         pTst.apFnc[1] = cast(FnPtr) &pTst.func1;
>         pTst.apFnc[2] = cast(FnPtr) &pTst.func2;
>         pTst.apFnc[3] = cast(FnPtr) &pTst.func3;
>         pTst.apFnc[4] = cast(FnPtr) &pTst.func4;
> }
> 
> struct TTest
> {
>         void *          pVtbl;
>         FnPtr[5]        apFnc;
> 
>         void func0()
>         {
>                 dout.writefln("func0");
>         }
>         void func1()
>         {
>                 dout.writefln("func1");
>         }
>         void func2()
>         {
>                 dout.writefln("func2");
>         }
>         void func3()
>         {
>                 dout.writefln("func3");
>         }
>         void func4()
>         {
>                 dout.writefln("func4");
>         }
> }
> 
> void main()
> {
>         TTest * pTst = new TTest;
>         initTTest(pTst);
>         for (int iIdx = 0; iIdx < pTst.apFnc.length; ++iIdx)
>                 dout.writefln("item#%d:0x%08X", iIdx, cast(int)
> pTst.apFnc[iIdx]);
>         pTst.apFnc[1]();
>         pTst.apFnc[3]();
>         pTst.apFnc[4]();
> }
> 
> /*
> execution produces:
> 
> item#0:0x019F3FE0
> item#1:0x004020AC
> item#2:0x019F3FE0
> item#3:0x0040215C
> item#4:0x004021B4
> func1
> func3
> func4
> */
> 
> /*
> disassembly shows that wrong code is generated for the 1st and 3rd
> function pointer assignments:
> function address is loaded into a register but the destination is
> written from another one
> 
> 5:    void initTTest(TTest * pTst)
> 00402010   enter       4,0
> 00402014   push        ebx
> 00402015   push        esi
> 00402016   mov         dword ptr [ebp-4],eax
> 6:    {
> 7:    //  pTst.pVtbl = cast(void*) pTst.apFnc.ptr;
> 8:        pTst.apFnc[0] = cast(FnPtr) &pTst.func0;
> 00402019   mov         eax,dword ptr [pTst]
> 0040201C   mov         ecx,offset _D8epfuntbl5TTest5func0MFZv (00402054)
> 00402021   mov         edx,dword ptr [pTst]
> 00402024   mov         dword ptr [edx+4],eax
> 9:        pTst.apFnc[1] = cast(FnPtr) &pTst.func1;
> 00402027   mov         ebx,edx
> 00402029   mov         ecx,offset _D8epfuntbl5TTest5func1MFZv (004020ac)
> 0040202E   mov         dword ptr [edx+8],ecx
> 10:       pTst.apFnc[2] = cast(FnPtr) &pTst.func2;
> 00402031   mov         eax,edx
> 00402033   mov         ecx,offset _D8epfuntbl5TTest5func2MFZv (00402104)
> 00402038   mov         dword ptr [edx+0Ch],eax
> 11:       pTst.apFnc[3] = cast(FnPtr) &pTst.func3;
> 0040203B   mov         esi,edx
> 0040203D   mov         ecx,offset _D8epfuntbl5TTest5func3MFZv (0040215c)
> 00402042   mov         dword ptr [edx+10h],ecx
> 12:       pTst.apFnc[4] = cast(FnPtr) &pTst.func4;
> 00402045   mov         ebx,edx
> 00402047   mov         ecx,offset _D8epfuntbl5TTest5func4MFZv (004021b4)
> 0040204C   mov         dword ptr [edx+14h],ecx
> 13:   }
> 0040204F   pop         esi
> 00402050   pop         ebx
> 00402051   leave
> 00402052   ret
> 00402053   int         3
> */
> 
> 
> -- 
> 

April 08, 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2318


clugdbug@yahoo.com.au changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Severity|normal                      |critical




------- Comment #1 from clugdbug@yahoo.com.au  2009-04-08 07:42 -------
This also applies to D2.(DMD2.028).


-- 

February 01, 2010
http://d.puremagic.com/issues/show_bug.cgi?id=2318


Don <clugdbug@yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
                 CC|                            |clugdbug@yahoo.com.au
         Resolution|                            |INVALID


--- Comment #2 from Don <clugdbug@yahoo.com.au> 2010-02-01 07:26:10 PST ---
This is invalid: the code creates delegates, then casts them to function pointers.

To create the desired effect, this line:
  pTst.apFnc[0] = cast(FnPtr) &pTst.func0;

should be changed to:
  pTst.apFnc[0] = &TTest.func0;

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