Split ELF NT_FILE mappings of the same file into separate modules#1496
Open
leculver wants to merge 3 commits into
Open
Split ELF NT_FILE mappings of the same file into separate modules#1496leculver wants to merge 3 commits into
leculver wants to merge 3 commits into
Conversation
R2R managed assemblies are mapped twice on Linux/macOS: a raw flat file layout and a runtime-laid-out loaded PE layout, both file-backed by the same path but at disjoint (often multi-GB apart) addresses. LoadFileTable grouped NT_FILE entries purely by path, collapsing the two mappings into a single ElfLoadedImage whose Size spanned the entire gap (observed up to hundreds of GB), producing bogus, mutually-overlapping module ranges and breaking exact-base module correlation for consumers. Split each path's entries into contiguity clusters and emit one ElfLoadedImage per cluster. Gaps <=1MB stay in the same image; gaps >=256MB start a new one; borderline gaps consult the PE header's SizeOfImage at the cluster base, falling back to the previous merge behavior when the header is unreadable or the image is not a PE (native ELF .so). Entries are still added to each image in original file order to preserve base-address selection.
Address deep-review findings on the same-path NT_FILE contiguity split: - Probe the PE header at the cluster's first PageOffset==0 entry (the address ElfLoadedImage actually uses as its base), not the lowest-address entry. When a header entry joins a cluster mid-way, retarget the probe and re-read SizeOfImage, so the split decision reads the real MZ header. - Make the declared PE SizeOfImage the primary bound for any gap size, and use the address-gap threshold only as a fallback for header-less native ELF images. This stops the 256 MB threshold from ever hard-splitting a PE image and narrows the heuristic to genuinely non-PE mappings. - Compute the in-image test as (nextStart - headerBase) < SizeOfImage instead of nextStart < headerBase + SizeOfImage, avoiding a near-2^64 addition overflow. - Assert on duplicate base addresses in debug builds while keeping the last-wins indexer (no throw on crafted dumps). - Remove the now-unused SmallGapThreshold. Validated: repro R2R dump still splits MyLib.dll into two small modules, and the raw ElfLoadedImage output across 9 real ELF coredumps is byte-identical to the prior fix. Elf/Module/PEImage unit tests pass (24 passed, 0 failed). Co-authored-by: Copilot <[email protected]>
max-charlamb
approved these changes
Jul 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
R2R managed assemblies are mapped twice on Linux/macOS: a raw flat file layout and a runtime-laid-out loaded PE layout, both file-backed by the same path but at disjoint (often multi-GB apart) addresses. LoadFileTable grouped NT_FILE entries purely by path, collapsing the two mappings into a single ElfLoadedImage whose Size spanned the entire gap (observed up to hundreds of GB), producing bogus, mutually-overlapping module ranges and breaking exact-base module correlation for consumers.
Split each path's entries into contiguity clusters and emit one ElfLoadedImage per cluster. Gaps <=1MB stay in the same image; gaps >=256MB start a new one; borderline gaps consult the PE header's SizeOfImage at the cluster base, falling back to the previous merge behavior when the header is unreadable or the image is not a PE (native ELF .so). Entries are still added to each image in original file order to preserve base-address selection.