Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
March 17, 2013 Bug? NVI functions can't call normal interface functions? | ||||
---|---|---|---|---|
| ||||
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? |
March 17, 2013 Re: Bug? NVI functions can't call normal interface functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Johannes Pfau | 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 #. |
March 17, 2013 Re: Bug? NVI functions can't call normal interface functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Maxim Fomin | Actually it was http://d.puremagic.com/issues/show_bug.cgi?id=4589 |
March 19, 2013 Re: Bug? NVI functions can't call normal interface functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Maxim Fomin | 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=4589
I 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
|
March 20, 2013 Re: Bug? NVI functions can't call normal interface functions? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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:
>
> > Actually it was http://d.puremagic.com/issues/show_bug.cgi?id=4589
>
> I 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
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)
|
Copyright © 1999-2021 by the D Language Foundation