Skip to content

Fix cross-module interface field/method vtable index mismatch#252

Merged
ASDAlexander77 merged 1 commit into
mainfrom
fix-interface-vtable-index-mismatch
Jul 19, 2026
Merged

Fix cross-module interface field/method vtable index mismatch#252
ASDAlexander77 merged 1 commit into
mainfrom
fix-interface-vtable-index-mismatch

Conversation

@ASDAlexander77

Copy link
Copy Markdown
Owner

Summary

  • Interface vtable slot numbers (InterfaceInfo::fields/methods's virtualIndex) were assigned by two inconsistent algorithms: declaration-time assignment used raw interleaved declaration order, while cast-time assignment (getVirtualTable) always puts all methods before all fields.
  • A module that only reads an already-typed interface value it imported (e.g. A.counter.count where A.counter is exported from another compiled module) never triggers the cast-time algorithm, so it kept the stale declaration-order index while the exporting module's real vtable used the methods-first layout - a field read could land on a method's vtable slot (a function pointer misread as a thisVal-relative byte offset) and crash the JIT with 0xC0000005.
  • Fix: InterfaceInfo::assignCanonicalVirtualIndexes() computes the canonical (extends-offset, then methods in order, then fields in order) layout once when an interface declaration finishes resolving, independent of any cast - so every module that parses/re-parses the same interface declaration (including the @dllimport textual redeclaration path used for -shared imports) agrees on slot numbers.
  • Re-enabled the Counter interface field/method regression coverage in export_object_literal_with_interface.ts / import_object_literal_with_interface.ts that was previously reverted (crashing) while this bug was still open.

Test plan

  • ctest -R export-import-object-literal-with-interface (both AOT and JIT variants) now pass
  • Full suite: ctest -C Debug - 714/714 passed, no regressions

🤖 Generated with Claude Code

Interface vtable slot numbers were assigned by two inconsistent
algorithms: declaration-time assignment used raw interleaved
declaration order, while cast-time assignment (getVirtualTable)
always puts methods before fields. Whichever module performs an
actual cast keeps the correct methods-first layout; a module that
only reads an already-typed interface value it imported never runs
the cast-time algorithm and keeps the stale declaration-order index,
so a field read could land on a method's vtable slot (a function
pointer misread as a byte offset) and crash the JIT with 0xC0000005.

Add InterfaceInfo::assignCanonicalVirtualIndexes(), a pure function
of the interface's own declaration, computed once when the
declaration finishes resolving so all modules that re-parse it agree.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 512d54c into main Jul 19, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the fix-interface-vtable-index-mismatch branch July 19, 2026 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant