digitalmars.D - Bug? NVI functions can't call normal interface functions?
- Johannes Pfau (38/38) Mar 17 2013 import core.stdc.stdio;
- Maxim Fomin (29/29) Mar 17 2013 Yes, this is a bug.
- Maxim Fomin (1/1) Mar 17 2013 Actually it was http://d.puremagic.com/issues/show_bug.cgi?id=4589
- Steven Schveighoffer (49/50) Mar 19 2013 I don't think this is the same problem.
- Johannes Pfau (6/68) Mar 20 2013 I'll report it soon and I already have a bug fix. (The compiler indeed
import core.stdc.stdio; interface Timer { final int run() { printf("Timer.run()\n"); fun(); return 1; }; int fun(); } interface Application { final int run() { printf("Application.run()\n"); fun(); return 2; }; int fun(); } class TimedApp : Timer, Application { int fun() { printf("TimedApp.fun()\n"); return 0; } } void main() { auto app = new TimedApp; (cast(Application)app).run(); (cast(Timer)app).run(); app.Application.run(); app.Timer.run(); } Output: ---- Application.run() TimedApp.fun() Timer.run() TimedApp.fun() Application.run() Timer.run() ---- Note how "TimedApp.fun()" is called if cast was used, but not if app.*Interface*. was called. I guess this is a bug?
Mar 17 2013
Yes, this is a bug. The funny thing here is that instead TimedApp.fun(), object.Object.toString() is called due to shift error in virtual table offset jumping. I guess due to interfaces' ABI a class instance isn't passed properly. Using override string toString() { printf("bzzzz\n"); return ""; } reveals the bug. Valgrind also doesn't detect error like this. Vtable storage layout may explain where bug comes from: _D4main8TimedApp6__vtblZ: dd offset FLAT:_D4main8TimedApp7__ClassZ 64 db 000h,000h,000h,000h ;.... dd offset FLAT:_D6object6Object8toStringMFZAya 64 db 000h,000h,000h,000h ;.... dd offset FLAT:_D6object6Object6toHashMFNbNeZm 64 db 000h,000h,000h,000h ;.... dd offset FLAT:_D6object6Object5opCmpMFC6ObjectZi 64 db 000h,000h,000h,000h ;.... dd offset FLAT:_D6object6Object8opEqualsMFC6ObjectZb 64 db 000h,000h,000h,000h ;.... dd offset FLAT:_D6object6Object8opEqualsMFC6ObjectC6ObjectZb 64 db 000h,000h,000h,000h ;.... dd offset FLAT:_D4main8TimedApp3funMFZi 64 db 000h,000h,000h,000h ;.... I remember Don was posting similar issue but do not remember the
Mar 17 2013
Actually it was http://d.puremagic.com/issues/show_bug.cgi?id=4589
Mar 17 2013
On Sun, 17 Mar 2013 09:59:03 -0400, Maxim Fomin <maxim maxim-fomin.ru> wrote:Actually it was http://d.puremagic.com/issues/show_bug.cgi?id=4589I don't think this is the same problem. I modified the program a bit: import core.stdc.stdio; interface Timer { final int run() { printf("Timer.run(), this=%x\n", cast(void*)this); fun(); return 1;} int fun(); } interface Application { final int run() { printf("Application.run(), this=%x\n", cast(void *)this); fun(); return 2; }; int fun(); } class TimedApp : Timer, Application { int fun() { printf("TimedApp.fun(), this=%x\n", cast(void*)this); return 0; } } void main() { auto app = new TimedApp; (cast(Application)app).run(); (cast(Timer)app).run(); app.Application.run(); app.Timer.run(); } New output: Application.run(), this=10007ff8 TimedApp.fun(), this=10007fe0 Timer.run(), this=10007ff0 TimedApp.fun(), this=10007fe0 Application.run(), this=10007fe0 Timer.run(), this=10007fe0 Note that Application.run() is given the interface pointer 10007ff8, whereas the *true* object pointer is 10007fe0. This is normal and expected. However, in the *last* call to Application.run (and Timer.run), it's given the pointer 10007fe0, the true object pointer. This gives it the completely WRONG vtable to use for calling fun. I think this is different than the bug I posted. It may be related, I don't know. If this bug is not already reported, it should be. -Steve
Mar 19 2013
Am Tue, 19 Mar 2013 17:51:52 -0400 schrieb "Steven Schveighoffer" <schveiguy yahoo.com>:On Sun, 17 Mar 2013 09:59:03 -0400, Maxim Fomin <maxim maxim-fomin.ru> wrote:I'll report it soon and I already have a bug fix. (The compiler indeed always passed the object pointer. This is valid for base classes, but not for interfaces. Adding an isInterface check + CastExpression solves this issue)Actually it was http://d.puremagic.com/issues/show_bug.cgi?id=4589I don't think this is the same problem. I modified the program a bit: import core.stdc.stdio; interface Timer { final int run() { printf("Timer.run(), this=%x\n", cast(void*)this); fun(); return 1;} int fun(); } interface Application { final int run() { printf("Application.run(), this=%x\n", cast(void *)this); fun(); return 2; }; int fun(); } class TimedApp : Timer, Application { int fun() { printf("TimedApp.fun(), this=%x\n", cast(void*)this); return 0; } } void main() { auto app = new TimedApp; (cast(Application)app).run(); (cast(Timer)app).run(); app.Application.run(); app.Timer.run(); } New output: Application.run(), this=10007ff8 TimedApp.fun(), this=10007fe0 Timer.run(), this=10007ff0 TimedApp.fun(), this=10007fe0 Application.run(), this=10007fe0 Timer.run(), this=10007fe0 Note that Application.run() is given the interface pointer 10007ff8, whereas the *true* object pointer is 10007fe0. This is normal and expected. However, in the *last* call to Application.run (and Timer.run), it's given the pointer 10007fe0, the true object pointer. This gives it the completely WRONG vtable to use for calling fun. I think this is different than the bug I posted. It may be related, I don't know. If this bug is not already reported, it should be. -Steve
Mar 20 2013