Bug 2013 – interface to interface dynamic cast is incorrect in some cases

Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2008-04-19T12:18:00Z
Last change time
2017-07-22T12:36:10Z
Keywords
pull, wrong-code
Assigned to
nobody
Creator
dvdfrdmn
See also
https://issues.dlang.org/show_bug.cgi?id=1747

Attachments

IDFilenameSummaryContent-TypeSize
248iiir.dTest Casttext/plain735

Comments

Comment #0 by dvdfrdmn — 2008-04-19T12:18:30Z
When a class implements an interface that has re-implemented an ancestor interface, it is possible for a dynamic cast to produce the wrong result. I have this tagged as "wrong-code", but I believe the problem is due to both InterfaceDeclaration RTTI and the implementation of phobos/internal/cast.d:_d_isbaseof2.
Comment #1 by dvdfrdmn — 2008-04-19T12:19:00Z
Created attachment 248 Test Cast
Comment #2 by k.hara.pg — 2015-07-18T12:16:31Z
Still happens in D2. (In reply to David Friedman from comment #1) > Created attachment 248 [details] > Test Cast Simplified the test case: interface IA { int mA(); } interface IB : IA { int mB(); } interface IC : IB { } interface ID : IA, IC { int mD(); } class C : ID { int mA() { return 1; } int mB() { return 2; } int mD() { return 3; } } void main() { C c = new C; IA ia = c; IB ib = cast(IB)ia; assert(ib.mB() == 2); }
Comment #3 by k.hara.pg — 2015-07-18T13:02:30Z
The problem is in both dmd and druntime code. For the class/interface hierarchy: interface IA { ... } interface IB : IA { ... } interface IC : IB { } interface ID : IA, IC { ... } class C : ID { ... } The layout of pointer to vtbls in the class C instance object is: (IA) IB IA, IC C : ID ---------------------- 0 n n+ptrsize // Note: n is the size of __vtbl + __monitor + sum of C field sizes. // It's 8 with -m32. Currently dmd generates following tree of `object.Interface` structs to represent the hierarchy: +-> CI(IA).interfaces[] == [] | A | +-------------------------+ | | | CI(IB).interfaces[] == [CI(IA)/0] | A | +-------------------------+ | | | CI(IC).interfaces[] == [CI(IB)/0] | A | +---------------------------+----------+ | | | +----------------------+ | | | | | CI(ID).interfaces[] == [CI(IA)/0, CI(IC)/0] | A | +----------------------+ +----------+ | | CI(C).interfaces[] == [CI(ID)/n, CI(IC)/n+ptrsize] // Note: CI(X) == ClassInfo(X) == typeid(X).info // CI(X)/num --> num == object.Interface.offset For the cast from IA to IB, druntime once downcast IA to Object, then calculate offset from Object(== C) to IB. It's handled by _d_interface_cast(), _d_dynamic_cast(), and _d_isbaseof2() functions in druntime/src/rt/_cast.d. The problem is in _d_isbaseof2(). It should return n+ptrsize for the cast from Object to IB, but while the iteration of above thee by breadth-first, it incorrectly returns n. ------- The way to fix the issue: 1. Fix compiler-generated Interfaces[] tree 2. Fix _d_isbaseof2() function to calculate correct offset.
Comment #4 by k.hara.pg — 2015-07-18T13:08:58Z
Comment #5 by k.hara.pg — 2015-07-18T13:57:09Z
*** Issue 11796 has been marked as a duplicate of this issue. ***
Comment #6 by github-bugzilla — 2015-07-19T07:24:49Z
Commits pushed to master at https://github.com/D-Programming-Language/druntime https://github.com/D-Programming-Language/druntime/commit/c83a79c25dcf061ccbd4a86dfbbdf53c6e70c83c Issue 2013 - interface to interface dynamic cast is incorrect in some cases This is a preparation fix. Until the ClassInfo.interfaces[] generation fixed, the changed code keeps existing behavior. After the compiler fix, it will return correct offset value. https://github.com/D-Programming-Language/druntime/commit/4f19d340d3868bc2478aa6817969400868724a92 Merge pull request #1327 from 9rnsr/fix2013 Issue 2013 - interface to interface dynamic cast is incorrect in some cases
Comment #7 by github-bugzilla — 2015-07-19T08:08:40Z
Commits pushed to master at https://github.com/D-Programming-Language/dmd https://github.com/D-Programming-Language/dmd/commit/2c28cecaf5a19b60a4e06865b5dbc558043be089 fix Issue 2013 - interface to interface dynamic cast is incorrect in some cases For the runtime cast behavior, also requires fixing a druntime internal function `_d_isbaseof2()` in `druntime/src/rt/cast_.d`. https://github.com/D-Programming-Language/dmd/commit/f78b25c9fb00bf024cd1d6e394f696bba4f2187b Merge pull request #4819 from 9rnsr/fix1747_2013 Issue 1747 & 2013 - class/interface cast is incorrect in some cases
Comment #8 by github-bugzilla — 2015-07-21T05:57:41Z
Commits pushed to master at https://github.com/D-Programming-Language/druntime https://github.com/D-Programming-Language/druntime/commit/60d05732370bb0d649824f3240e28d1fa9bfbe3c Post-processing for Issue 2013 - Remove temporary branch till the compiler migration https://github.com/D-Programming-Language/druntime/commit/9575940f9f8c329785528a2bb78a6466ea7d7c42 Merge pull request #1330 from 9rnsr/fix2013 Post-processing for Issue 2013 - Remove temporary branch till the compiler migration
Comment #9 by github-bugzilla — 2015-10-04T18:19:04Z
Comment #10 by github-bugzilla — 2017-07-22T12:36:10Z
Commits pushed to dmd-cxx at https://github.com/dlang/dmd https://github.com/dlang/dmd/commit/2c28cecaf5a19b60a4e06865b5dbc558043be089 fix Issue 2013 - interface to interface dynamic cast is incorrect in some cases https://github.com/dlang/dmd/commit/f78b25c9fb00bf024cd1d6e394f696bba4f2187b Merge pull request #4819 from 9rnsr/fix1747_2013