Fix crash decompiling reference assemblies with stripped method bodies - #3958
Merged
Merged
Conversation
The accessor forwarding-stub matcher bounded the IL body from above but not from below. Reference assemblies keep the method RVA while stripping the body to zero bytes, so an explicit interface accessor there sailed past the size check and the first opcode read ran off the end of the blob, aborting the whole type with a BadImageFormatException. The sibling matcher in TransformDisplayClassUsage already guards its lower bound; this one did not. Found by fuzzing nuget.org: every package resolving to the Microsoft.NETFramework.ReferenceAssemblies packs was affected. Assisted-by: Claude:claude-opus-5[1m]:Claude Code
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.
Problem
CSharpDecompiler.IsAccessorInterfaceImplementationRuntimeHelperbounds the IL body of a candidate accessor from above, but never from below. Reference assemblies keep the method RVA while stripping the body to zero bytes, so an explicit interface accessor there passes the size check and the very first opcode read runs off the end of the blob. TheBadImageFormatExceptionescapesMemberIsHiddenand aborts decompilation of the entire type.Repro with any
Microsoft.NETFramework.ReferenceAssembliespack:Fix
A
minimumMethodSizecounterpart to the existingmaximumMethodSize, plus three guards the bound cannot cover on its own:minimumMethodSizeassumes the one-byteldarg.Nencoding, butldargencodes as four bytes, so a body that passes the bound can still be consumed by the argument loop before the trailingcall/ret.The sibling fixed-sequence matcher,
TransformDisplayClassUsage.IsCallToObjectCtor, already guards its lower bound (reader.Length < 7) and catchesBadImageFormatException; this one did not. I audited everyDecodeOpCodecall site: all others arewhile (blob.RemainingBytes > 0)scanners whose opcode read is guarded by the loop condition, so no change is needed there and no bounds-checking overhead is added to normal IL blobs.Testing
TruncatedAccessorBody, red before the fix with the same stack trace, green after. ilasm cannot emit a zero-byte body, so the fixture uses the truncated-tail variant of the same defect.System.Web,System.Web.Extensions,mscorlib,SystemandSystem.Corefrom the net48 reference pack now decompile in full with zero errors.ILSpy.XPlat.slnfsuite: 3367 tests, 0 failed, 44 skipped (Windows-only).How it was found
Fuzzing the nuget.org catalog through the decompiler. Every package whose dependency closure resolved to the
Microsoft.NETFramework.ReferenceAssembliespacks hit this.Written by an AI agent (Claude) on Siegfried's behalf.