Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reasonVFTableBelongsToClass may get confused by embedded objects #214

Closed
sei-eschwartz opened this issue Feb 10, 2022 · 4 comments
Closed

Comments

@sei-eschwartz
Copy link
Collaborator

Embedded objects can make it seem like the enclosing object has vftables when it really does not.

Here's a pathological example: https://godbolt.org/z/8ca7WP6nG

Outer::Outer(void) PROC ; Outer::Outer, COMDAT
  push esi
  mov esi, ecx
  mov BYTE PTR bool volatile base, 1 ; base
  mov BYTE PTR bool volatile inherit, 1 ; inherit
  mov BYTE PTR bool volatile base, 1 ; base
  mov DWORD PTR [esi+12], OFFSET const EmbedMe::`vftable'
  lea ecx, DWORD PTR [esi+28]
  mov BYTE PTR bool volatile embed, 1 ; embed
  call EmbedMe2::EmbedMe2(void) ; EmbedMe2::EmbedMe2
  mov eax, esi
  mov BYTE PTR bool volatile outer, 1 ; outer
  pop esi
  ret 0
Outer::Outer(void) ENDP ; Outer::Outer

reasonVFTableBelongsToClass has three rules:

  • constructor looks for overwritten vftables, but that only happens for inheritance
  • destructor rule makes sure that the vftable is only installed by one class. This is probably conservative/safe, but an embedded and inlined destructor could prevent this from ever firing
  • hasnobase says if there are no base classes, then the vftable must be on the constructor's class. This completely neglects embedded objects!

This affects #213

@sei-eschwartz
Copy link
Collaborator Author

Effects #211 too.

Specifically, a constructor of an object that embeds zSTRING at two locations is confused with zSTRING itself. This case should be fairly easy to detect. A few ideas:

  • Can't merge with the VFTable because the VFTable is installed at two locations
  • Detect embedded class because VFTable is installed at two locations
  • Force inheritance or NOT embedded to use constructor rule

@edmcman
Copy link
Contributor

edmcman commented May 5, 2022

I've been working on this a lot more, and this line of code was attempting to ensure that there was inheritance so that we own the vftable:

% Constructors may inline embedded constructors. If non-offset

Sadly, there are a bunch of problems here:

  • There could be a zero-size derived class without a vftable and an embedded class with a vftable at Offset
  • There could be a derived class at Offset without a vftable, but containing an embedded class at (inner) offset 0
  • There could be multiple inheritance, which can cause a vftable that is owned by the outer class at an offset at which there is not an immediate base

@sei-eschwartz
Copy link
Collaborator Author

This is in ejs/vftablebelongs. Can it be merged?

@sei-eschwartz
Copy link
Collaborator Author

This is already merged internally

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants