Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Harden debug scope update logic #824

Merged
merged 2 commits into from
Jan 19, 2022
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
13 changes: 9 additions & 4 deletions Mono.Cecil.Cil/MethodBody.cs
Original file line number Diff line number Diff line change
Expand Up @@ -384,11 +384,16 @@ InstructionOffset ResolveInstructionOffset(InstructionOffset inputOffset, ref In
// resolve by walking the instructions from start and don't cache the result.
int size = 0;
for (int i = 0; i < items.Length; i++) {
// The array can be larger than the actual size, in which case its padded with nulls at the end
// so when we reach null, treat it as an end of the IL.
if (items [i] == null)
return new InstructionOffset (i == 0 ? items [0] : items [i - 1]);

if (size == offset)
return new InstructionOffset (items [i]);

if (size > offset)
return new InstructionOffset (items [i - 1]);
return new InstructionOffset (i == 0 ? items [0] : items [i - 1]);

size += items [i].GetSize ();
}
Expand All @@ -407,15 +412,15 @@ InstructionOffset ResolveInstructionOffset(InstructionOffset inputOffset, ref In
// Allow for trailing null values in the case of
// instructions.Size < instructions.Capacity
if (item == null)
return new InstructionOffset (items [i - 1]);
return new InstructionOffset (i == 0 ? items [0] : items [i - 1]);

cache.Instruction = item;

if (cache.Offset == offset)
return new InstructionOffset (cache.Instruction);

if (cache.Offset > offset)
return new InstructionOffset (items [i - 1]);
if (cache.Offset > offset)
return new InstructionOffset (i == 0 ? items [0] : items [i - 1]);

size += item.GetSize ();
}
Expand Down
85 changes: 48 additions & 37 deletions Test/Mono.Cecil.Tests/ILProcessorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,18 @@ public void Clear ()
AssertOpCodeSequence (new OpCode[] { }, method);
}

[TestCase (RoundtripType.None, false, false)]
[TestCase (RoundtripType.Pdb, false, false)]
[TestCase (RoundtripType.Pdb, true, false)]
[TestCase (RoundtripType.Pdb, true, true)]
[TestCase (RoundtripType.PortablePdb, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false)]
[TestCase (RoundtripType.PortablePdb, true, true)]
public void InsertAfterWithSymbolRoundtrip (RoundtripType roundtripType, bool forceUnresolved, bool reverseScopes)
[TestCase (RoundtripType.None, false, false, false)]
[TestCase (RoundtripType.Pdb, false, false, false)]
[TestCase (RoundtripType.Pdb, true, false, false)]
[TestCase (RoundtripType.Pdb, true, false, true)]
[TestCase (RoundtripType.Pdb, true, true, false)]
[TestCase (RoundtripType.PortablePdb, false, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false, true)]
[TestCase (RoundtripType.PortablePdb, true, true, false)]
public void InsertAfterWithSymbolRoundtrip (RoundtripType roundtripType, bool forceUnresolved, bool reverseScopes, bool padIL)
{
var methodBody = CreateTestMethodWithLocalScopes ();
var methodBody = CreateTestMethodWithLocalScopes (padIL);
methodBody = RoundtripMethodBody (methodBody, roundtripType, forceUnresolved, reverseScopes);

var il = methodBody.GetILProcessor ();
Expand All @@ -176,16 +178,18 @@ public void InsertAfterWithSymbolRoundtrip (RoundtripType roundtripType, bool fo
methodBody.Method.Module.Dispose ();
}

[TestCase (RoundtripType.None, false, false)]
[TestCase (RoundtripType.Pdb, false, false)]
[TestCase (RoundtripType.Pdb, true, false)]
[TestCase (RoundtripType.Pdb, true, true)]
[TestCase (RoundtripType.PortablePdb, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false)]
[TestCase (RoundtripType.PortablePdb, true, true)]
public void RemoveWithSymbolRoundtrip (RoundtripType roundtripType, bool forceUnresolved, bool reverseScopes)
[TestCase (RoundtripType.None, false, false, false)]
[TestCase (RoundtripType.Pdb, false, false, false)]
[TestCase (RoundtripType.Pdb, true, false, false)]
[TestCase (RoundtripType.Pdb, true, false, true)]
[TestCase (RoundtripType.Pdb, true, true, false)]
[TestCase (RoundtripType.PortablePdb, false, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false, true)]
[TestCase (RoundtripType.PortablePdb, true, true, false)]
public void RemoveWithSymbolRoundtrip (RoundtripType roundtripType, bool forceUnresolved, bool reverseScopes, bool padIL)
{
var methodBody = CreateTestMethodWithLocalScopes ();
var methodBody = CreateTestMethodWithLocalScopes (padIL);
methodBody = RoundtripMethodBody (methodBody, roundtripType, forceUnresolved, reverseScopes);

var il = methodBody.GetILProcessor ();
Expand All @@ -200,16 +204,18 @@ public void RemoveWithSymbolRoundtrip (RoundtripType roundtripType, bool forceUn
methodBody.Method.Module.Dispose ();
}

[TestCase (RoundtripType.None, false, false)]
[TestCase (RoundtripType.Pdb, false, false)]
[TestCase (RoundtripType.Pdb, true, false)]
[TestCase (RoundtripType.Pdb, true, true)]
[TestCase (RoundtripType.PortablePdb, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false)]
[TestCase (RoundtripType.PortablePdb, true, true)]
public void ReplaceWithSymbolRoundtrip (RoundtripType roundtripType, bool forceUnresolved, bool reverseScopes)
[TestCase (RoundtripType.None, false, false, false)]
[TestCase (RoundtripType.Pdb, false, false, false)]
[TestCase (RoundtripType.Pdb, true, false, false)]
[TestCase (RoundtripType.Pdb, true, false, true)]
[TestCase (RoundtripType.Pdb, true, true, false)]
[TestCase (RoundtripType.PortablePdb, false, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false, true)]
[TestCase (RoundtripType.PortablePdb, true, true, false)]
public void ReplaceWithSymbolRoundtrip (RoundtripType roundtripType, bool forceUnresolved, bool reverseScopes, bool padIL)
{
var methodBody = CreateTestMethodWithLocalScopes ();
var methodBody = CreateTestMethodWithLocalScopes (padIL);
methodBody = RoundtripMethodBody (methodBody, roundtripType, forceUnresolved, reverseScopes);

var il = methodBody.GetILProcessor ();
Expand All @@ -224,16 +230,18 @@ public void ReplaceWithSymbolRoundtrip (RoundtripType roundtripType, bool forceU
methodBody.Method.Module.Dispose ();
}

[TestCase (RoundtripType.None, false, false)]
[TestCase (RoundtripType.Pdb, false, false)]
[TestCase (RoundtripType.Pdb, true, false)]
[TestCase (RoundtripType.Pdb, true, true)]
[TestCase (RoundtripType.PortablePdb, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false)]
[TestCase (RoundtripType.PortablePdb, true, true)]
public void EditBodyWithScopesAndSymbolRoundtrip (RoundtripType roundtripType, bool forceUnresolved, bool reverseScopes)
[TestCase (RoundtripType.None, false, false, false)]
[TestCase (RoundtripType.Pdb, false, false, false)]
[TestCase (RoundtripType.Pdb, true, false, false)]
[TestCase (RoundtripType.Pdb, true, false, true)]
[TestCase (RoundtripType.Pdb, true, true, false)]
[TestCase (RoundtripType.PortablePdb, false, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false, false)]
[TestCase (RoundtripType.PortablePdb, true, false, true)]
[TestCase (RoundtripType.PortablePdb, true, true, false)]
public void EditBodyWithScopesAndSymbolRoundtrip (RoundtripType roundtripType, bool forceUnresolved, bool reverseScopes, bool padIL)
{
var methodBody = CreateTestMethodWithLocalScopes ();
var methodBody = CreateTestMethodWithLocalScopes (padIL);
methodBody = RoundtripMethodBody (methodBody, roundtripType, forceUnresolved, reverseScopes);

var il = methodBody.GetILProcessor ();
Expand Down Expand Up @@ -320,13 +328,16 @@ static void AssertLocalScope (MethodBody methodBody, ScopeDebugInformation scope
Assert.IsTrue (scope.End.IsEndOfMethod);
}

static MethodBody CreateTestMethodWithLocalScopes ()
static MethodBody CreateTestMethodWithLocalScopes (bool padILWithNulls)
{
var module = ModuleDefinition.CreateModule ("TestILProcessor", ModuleKind.Dll);
var type = new TypeDefinition ("NS", "TestType", TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.Sealed, module.ImportReference (typeof (object)));
module.Types.Add (type);

var methodBody = CreateTestMethod (OpCodes.Nop, OpCodes.Ldloc_0, OpCodes.Nop, OpCodes.Ldloc_1, OpCodes.Nop, OpCodes.Ldloc_2, OpCodes.Nop);
if (padILWithNulls)
methodBody.Instructions.Capacity += 10;

var method = methodBody.Method;
method.ReturnType = module.ImportReference (typeof (void));
type.Methods.Add (method);
Expand Down