Skip to content

Align manifest assembly MVID table to 4 bytes in composite R2R images#129017

Open
jtschuster wants to merge 1 commit into
dotnet:mainfrom
jtschuster:jtschuster/ideal-funicular
Open

Align manifest assembly MVID table to 4 bytes in composite R2R images#129017
jtschuster wants to merge 1 commit into
dotnet:mainfrom
jtschuster:jtschuster/ideal-funicular

Conversation

@jtschuster
Copy link
Copy Markdown
Member

Summary

Fixes a 32-bit ARM SIGBUS (alignment fault) when running composite Ready-to-Run images.

ManifestAssemblyMvidHeaderNode emits the assembly MVID table — a packed array of 16-byte GUIDs — with alignment: 1. The CoreCLR runtime reads each entry as a GUID by value (ReadyToRunInfo in readytoruninfo.cpp), and GUID has a natural alignment of 4. When the table landed on a non-4-aligned RVA, ARM32 faulted with BUS_ADRALN because it does not permit unaligned multi-word loads. x64/arm64 tolerate the unaligned access, so the crash only manifested on ARM32.

Why the table could land unaligned

The table's RVA depends on the size of the preceding Ordered ReadOnlyData node. In composites built with debug directory entries (e.g. --pdb), an odd-sized NativeDebugDirectoryEntryNode (RSDS record) sorts between RuntimeFunctionsTableNode and the MVID table and can push it off a 4-byte boundary.

The fix

Set the node alignment to 4 so the table is padded to a valid boundary regardless of predecessor size.

Validation

Reproduced on current main with a controlled experiment (identical inputs and output name, so the predecessor node is byte-for-byte identical; the only variable is the alignment value):

NativeDebugDirectoryEntryNode @ 0x6D440, size 0x22 (34 ≡ 2 mod 4) -> ends 0x6D462
  alignment:1 (before):  MVID @ 0x6D462   &3 = 2  -> UNALIGNED -> SIGBUS
  alignment:4 (after):   MVID @ 0x6D464   &3 = 0  -> ALIGNED (2 bytes padding)

This matches the structure of a real failing ARM32 image, whose MVID table sat at RVA 0x28f49 (&3 = 1), consistent with the fault's si_addr in the kernel core.

Note

This pull request was authored with assistance from GitHub Copilot.

ManifestAssemblyMvidHeaderNode emitted the assembly MVID table (a packed
array of 16-byte GUIDs) with alignment 1. The CoreCLR runtime reads each
entry as a GUID by value, and GUID has a natural alignment of 4. When the
table landed on a non-4-aligned RVA, 32-bit ARM faulted with BUS_ADRALN
(SIGBUS) because it does not permit unaligned multi-word loads. Other
architectures tolerated the unaligned access, so the crash only manifested
on ARM32.

The table's RVA depends on the size of the preceding Ordered ReadOnlyData
node. In composites built with debug directory entries (e.g. --pdb), an
odd-sized NativeDebugDirectoryEntryNode can precede the MVID table and push
it off a 4-byte boundary. Setting the alignment to 4 pads the table to a
valid boundary regardless of predecessor size.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 4, 2026 22:10
@github-actions github-actions Bot added the area-crossgen2-coreclr only use for closed issues label Jun 4, 2026
@jtschuster
Copy link
Copy Markdown
Member Author

/azp run runtime-coreclr crossgen2-composite

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the ReadyToRun (crossgen2) emitter for composite images so the manifest assembly MVID table is emitted with 4-byte alignment, preventing potential unaligned GUID loads by the CoreCLR runtime on alignment-sensitive architectures (notably 32-bit ARM).

Changes:

  • Change ManifestAssemblyMvidHeaderNode output alignment from 1 to 4 bytes.
  • Add an explanatory comment documenting the runtime read pattern and the alignment requirement.

Comment on lines +60 to +65
// The runtime reads each entry of this table as a GUID by value (see
// ReadyToRunInfo::ReadyToRunInfo in readytoruninfo.cpp). GUID has a natural
// alignment of 4, so the table must be at least 4-byte aligned. Without this,
// a misaligned base causes an alignment fault (SIGBUS) on architectures that
// do not permit unaligned multi-word loads, such as 32-bit ARM.
return new ObjectData(manifestAssemblyMvidTable, Array.Empty<Relocation>(), alignment: 4, new ISymbolDefinitionNode[] { this });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-crossgen2-coreclr only use for closed issues

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants