www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 2318] New: flaw code generation building a function pointer table

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


-- 
Aug 27 2008
next sibling parent Sivo Schilling <sivo.schilling web.de> writes:
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
 */
 
 
 -- 
 

Sep 03 2008
prev sibling next sibling parent d-bugmail puremagic.com writes:
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).


-- 
Apr 08 2009
prev sibling parent d-bugmail puremagic.com writes:
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: -------
Feb 01 2010