fix(core): keep an import named like an ordinal from becoming one - #261
Open
r0ny123 wants to merge 1 commit into
Open
fix(core): keep an import named like an ordinal from becoming one#261r0ny123 wants to merge 1 commit into
r0ny123 wants to merge 1 commit into
Conversation
A PE imports by name or by ordinal, and the report keeps only the string, so "#5" in a report is ambiguous: it is what the import parsers write for an ordinal nothing resolves, and it is also a legal import name. The synthesizer read every "#N" as an ordinal, so an import really named that way was written as an ordinal thunk and came back under a different name. Two facts settle it without the report having to carry more. An ordinal is a WORD, so a larger number never came from an import table at all - and writing it as one truncated it into a different import. And the parsers write "#N" only for an ordinal no table resolves, so a name that does resolve cannot have come from them. On ws2_32.dll, "#1" is a real name, because an ordinal 1 there would have been written as accept. Both ends now key the decision on the same DLL name rather than deriving it twice, so the hint table and the thunks cannot disagree about which entries are ordinals.
r0ny123
force-pushed
the
fix/pe-synthesis-ordinal-collision
branch
from
August 18, 2026 10:54
947a469 to
b0c3d19
Compare
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.
A PE imports either by name or by ordinal — that is a bit in the thunk, not a property of the string. The report keeps only the string, so
"#5"is ambiguous by the time synthesis reads it back: it is what the import parsers write for an ordinal nothing resolves, and it is also a legal PE import name.PeSynthesizer._parseOrdinalread every#Nas an ordinal. An import really named that way was therefore written as an ordinal thunk, and came back from the synthesized binary under a different name entirely.This is the fourth and last hit from the sweep behind #260, which I had triaged there as needing a report-schema change. It does not — the information to settle it is already on both sides.
What settles it
An ordinal is a
WORD. A number above0xFFFFnever came from an import table, so#99999can only be a name. Writing it as an ordinal did not merely mislabel it, it truncated the value into a different import.The parsers only write
#Nwhen no table resolves it.OrdinalHelper.resolveOrdinal("ws2_32.dll", 1)returnsaccept, so the parsers would never have written#1for that DLL — a report holding it must mean a real import spelled that way. The synthesizer now applies the parsers' own test as its inverse.What remains ambiguous is a real import named
#Nwhere that ordinal resolves nowhere for its DLL. That one still synthesizes as an ordinal — and re-analysing the result yields#Nagain, so the report round-trips unchanged. The divergence is invisible in the report's own terms, which is the property worth having here.One structural change
The hint table and the thunk writer each decided independently which entries were ordinals, and each derived the DLL key separately (
dll_namein one,dll or "unknown.dll"in the other). Now that the decision depends on the DLL, disagreeing would mean aKeyErroron the hint lookup rather than a wrong byte. Both ends key on the same value, so they cannot drift.Validation
The new test fails on the pre-fix tree and passes after it. Two existing robustness tests stubbed
_parseOrdinalwith a one-argument lambda and are updated — worth noting as the reason a private-method signature is not as private as it looks.