Should this always work?

Steven Schveighoffer schveiguy at gmail.com
Sat May 1 16:06:05 UTC 2021


On 5/1/21 12:55 AM, frame wrote:
> I always thought as long as an object implements an interface, it should 
> be able to cast it from a void* if it really points to a supporting object.
> 
> I have the similar structure:
> 
> 
> ```d
> interface AI {
>     string doSomething();
> }
> 
> template S() {
>     void foo() {
> 
>     }
> }
> 
> abstract class A : AI {
>     string doSomething() {
>         return "Hello, World";
>     }
> }
> 
> class B : A {
>     mixin S;
> 
>     void other() {
> 
>     }
> }
> 
> auto b = new B;
> auto p = cast(void*) b;
> auto c = cast(AI) p;
> 
> c.doSomething();
> ```
> 
> But in my code with the real object, this generates a RangeError, 
> AcccesError, memory garbage:
> ```d
> auto b = new B;
> auto p = cast(void*) b;
> auto c = cast(AI) p; // AI with corrupt data
> 
> c.doSomething(); // error
> ```
> 
> But this works:
> ```d
> auto b = new B;
> auto p = cast(void*) b;
> auto c = cast(A) p; // A with correct data
> 
> c.doSomething(); // no error
> ```
> 
> If the runtime could not successfully cast it to AI, it should return 
> null. Am I wrong here?

An interface cast involves a thunk (constant pointer adjustment) to get 
to the interface/object. The reason is because a class with interfaces 
stores interface vtable pointers inside the object, and your interface 
reference points at that. You can see when you cast between Object 
(concrete) type and Interface type, the pointer value changes.

So this will not work. It *does* work for base classes, because the 
class vtable pointer is stored at same point, and casting around class 
references does not involve a thunk.

If you want this to work, you have to know whether the void* pointer is 
pointing at an object, or an interface. If you know it's pointing at an 
object, you can get to the interface via:

auto c = cast(AI)cast(Object)p;

Which will perform the appropriate thunks.

If you know it's a pointer to the AI interface directly, you can just 
cast it directly.

-Steve


More information about the Digitalmars-d-learn mailing list