Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@
<ItemGroup>
<None Include="TestCases\PdbGen\*.cs" />
<None Include="TestCases\PdbGen\PinnedRegionWarning.il" />
<None Include="TestCases\PdbGen\PinnedLocalSlot.il" />
</ItemGroup>

<ItemGroup>
Expand Down
23 changes: 23 additions & 0 deletions ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,29 @@ public async Task PinnedRegionWarning()
Assert.DoesNotThrow(() => decompiler.CreateSequencePoints(syntaxTree));
}

[Test]
public async Task PinnedLocalSlot()
{
// The decompiler models a pinned-region local as a pointer (int*), which never matches the
// metadata local signature type (int& pinned). The slot index is still faithful to the IL,
// and the type is never written to the PDB, so generating debug info must not assert on the
// type difference.
string ilFile = Path.Combine(TestCasePath, nameof(PinnedLocalSlot) + ".il");
string peFileName = await Tester.AssembleIL(ilFile, AssemblerOptions.Library);

var module = new PEFile(peFileName);
var resolver = new UniversalAssemblyResolver(peFileName, false,
module.Metadata.DetectTargetFrameworkId(), null, PEStreamOptions.PrefetchEntireImage);
var decompiler = new CSharpDecompiler(module, resolver, new DecompilerSettings());

var syntaxTree = decompiler.DecompileType(new Decompiler.TypeSystem.FullTypeName("C"));

Assert.DoesNotThrow(() => {
var debugInfo = new Decompiler.DebugInfo.DebugInfoGenerator(decompiler.TypeSystem);
syntaxTree.AcceptVisitor(debugInfo);
});
}

private class TestProgressReporter : IProgress<DecompilationProgress>
{
private Action<DecompilationProgress> reportFunc;
Expand Down
34 changes: 34 additions & 0 deletions ICSharpCode.Decompiler.Tests/TestCases/PdbGen/PinnedLocalSlot.il
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// A simple pinned pointer (fixed statement). The metadata local signature types the slot as
// `int32& pinned`, but the decompiler models a pinned-region local as a pointer (`int*`). The two
// never match, yet the slot index is faithful to the IL ldloc/stloc operand, so PDB generation
// must not assert on the type difference. Regression fixture for that assertion.
.assembly extern System.Runtime { }
.assembly PinnedLocalSlot { }
.module PinnedLocalSlot.dll

.class public auto ansi beforefieldinit C extends [System.Runtime]System.Object
{
.method public hidebysig instance int32 M(int32[] a) cil managed
{
.maxstack 2
.locals ( [0] int32& pinned p )
ldarg.1
ldc.i4.0
ldelema [System.Runtime]System.Int32
stloc.0
ldloc.0
ldind.i4
ldc.i4.0
conv.u
stloc.0
ret
}

.method public hidebysig specialname rtspecialname instance void .ctor() cil managed
{
.maxstack 1
ldarg.0
call instance void [System.Runtime]System.Object::.ctor()
ret
}
}
9 changes: 8 additions & 1 deletion ICSharpCode.Decompiler/DebugInfo/DebugInfoGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,14 @@ void HandleMethodBody(ILFunction function, MethodBodyBlock methodBody)
if (v.Index != null && v.Kind.IsLocal())
{
#if DEBUG
Debug.Assert(v.Index < types.Length && NormalizeTypeVisitor.TypeErasure.EquivalentTypes(v.Type, types[v.Index.Value]));
// The index is the IL ldloc/stloc operand, which indexes the local signature
// directly: ILReader creates one variable per signature slot, and SplitVariables
// copies that index. It is therefore correct by construction. The variable type
// is intentionally not checked against the signature - it is never written to the
// PDB (only the slot index and name are), and it legitimately diverges after
// variable splitting (one slot, several typed variables), for pinned-region locals
// modeled as pointers, and through generic-context type-parameter identity.
Debug.Assert(v.Index < types.Length);
#endif
localVariables.Add(v);
}
Expand Down
Loading