Bug 2318 – flaw code generation building a function pointer table

Status
RESOLVED
Resolution
INVALID
Severity
critical
Priority
P2
Component
dmd
Product
D
Version
D1 (retired)
Platform
x86
OS
Windows
Creation time
2008-08-27T07:22:00Z
Last change time
2014-03-01T00:36:59Z
Keywords
wrong-code
Assigned to
nobody
Creator
enzo.petrelli
Blocks
3761

Comments

Comment #0 by enzo.petrelli — 2008-08-27T07:22:21Z
/*************************** 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 */
Comment #1 by clugdbug — 2009-04-08T07:42:55Z
This also applies to D2.(DMD2.028).
Comment #2 by clugdbug — 2010-02-01T07:26:10Z
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;