core.sys.windows.com.ComObject apparently has wrongly laid out Vtable
Carl Sturtivant
sturtivant at gmail.com
Tue Mar 19 23:36:39 UTC 2024
On Tuesday, 19 March 2024 at 18:35:38 UTC, Richard (Rikki) Andrew
Cattermole wrote:
> It's worth noting that for every class and interface in a given
> class hierarchy, each have different vtables for a given object.
Nevertheless, a given virtual method may occur with the same
index in the Vtable of a class and in the Vtable of a class that
inherits from it and overrides that method, so dynamic lookup
finds a given method in a given position in a Vtable irrespective
of the exact class in the hierarchy it occurs in: statically
determined code can then look it up in the Vtable by its fixed
index at the point in source that a method call occurs. And the
case of COM this position is determined by the COM interface
being implemented, where AddRef is always in position 1 after
QueryInterface for example.
> This is why you must cast the D object to IUnknown first before
> inspecting its reference.
I do not think this follows, either for a regular D object or a
COM object. For the first the class hierarchy can determine the
order of the virtual methods and overriding doesn't change the
index of a method with a given signature. For a COM object the
order of the methods in the Vtable is determined by the COM
interface that the object is implementing. In the case of this
thread, it's determined by the definition of IUnknown in COM.
Specifically, the ComObject class in D inherits from D's IUnknown
interface and this is modeling implementing the COM interface
IUnknown with an object with methods in positions 0,1,2 in the
Vtable implementing QueryInterface, AddRef and Release.
It should be possible to cast a ComObject which by definition
implements the COM interface IUnknown into a pointer to its first
word, which external COM expects to contain a pointer to its
Vtable, which external COM expects to contain pointers to those
three methods in positions 0,1,2.
However this casting doesn't produce a pointer to the COM object
needed in any external COM context. It produces a pointer 16
bytes short of that object, which makes no sense semantically.
What is it a pointer to? Something hidden by the implementation
that does not function as a COM object externally.
Casting to a pointer is producing an implementation dependent
pointer to an object NOT defined in source that happens to seem
to contain offset down two words the actual object that we have
defined in source, and the object pointed to seems to have a
bogus Vtable for COM purposes that doesn't work. We have no
reason whatsoever to be given access to this outer object. D does
not define what it is! And D is not producing a pointer to the
COM object that we defined.
This is a semantic bug: it defines casting to a pointer to have
silly undefined semantics.
Perhaps the reference to a COM object defined by a class that
inherits IUnknown is secretly represented by a pointer to this
outer object. That's no reason to have casting such a reference
to a pointer not be to compute a pointer to the COM object inside
that outer object, which is the only cast that has any meaning.
More information about the Digitalmars-d
mailing list