Browse Source

#1349: Fix assertions triggered by incorrect local function decompilation.

pull/1633/head
Siegfried Pammer 6 years ago
parent
commit
0ca5ace524
  1. 24
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  2. 25
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs
  3. 5
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

24
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs

@ -25,6 +25,30 @@ namespace LocalFunctions @@ -25,6 +25,30 @@ namespace LocalFunctions
{
private int field;
private Lazy<object> nonCapturinglocalFunctionInLambda = new Lazy<object>(delegate {
return CreateValue();
object CreateValue()
{
return null;
}
});
private Lazy<object> capturinglocalFunctionInLambda = new Lazy<object>(delegate {
int x = 42;
return Do();
object Do()
{
return CreateValue();
int CreateValue()
{
return x;
}
}
});
private static void Test(int x)
{
}

25
ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

@ -91,6 +91,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -91,6 +91,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
DetermineCaptureAndDeclarationScope(localFunction, useSite);
TransformToLocalFunctionInvocation(localFunction.ReducedMethod, useSite);
}
if (function.Method.IsConstructor && localFunction.DeclarationScope == null) {
localFunction.DeclarationScope = BlockContainer.FindClosestContainer(useSite);
}
}
if (localFunction.DeclarationScope == null) {
@ -236,20 +240,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -236,20 +240,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
void DetermineCaptureAndDeclarationScope(ILFunction function, CallInstruction useSite)
{
int firstArgumentIndex = function.Method.IsStatic ? 0 : 1;
for (int i = useSite.Arguments.Count - 1; i >= 0; i--) {
var arg = useSite.Arguments[i];
if (firstArgumentIndex > 0) {
HandleArgument(0, useSite.Arguments[0]);
}
for (int i = useSite.Arguments.Count - 1; i >= firstArgumentIndex; i--) {
if (!HandleArgument(i, useSite.Arguments[i]))
break;
}
bool HandleArgument(int i, ILInstruction arg)
{
ILVariable closureVar;
if (!(arg.MatchLdLoc(out closureVar) || arg.MatchLdLoca(out closureVar)))
break;
return false;
if (closureVar.Kind == VariableKind.NamedArgument)
break;
return false;
if (!TransformDisplayClassUsage.IsPotentialClosure(context, UnwrapByRef(closureVar.Type).GetDefinition()))
break;
return false;
if (i - firstArgumentIndex >= 0) {
Debug.Assert(i - firstArgumentIndex < function.Method.Parameters.Count && IsClosureParameter(function.Method.Parameters[i - firstArgumentIndex], resolveContext));
}
if (closureVar.AddressCount == 0 && closureVar.StoreInstructions.Count == 0)
continue;
return true;
// determine the capture scope of closureVar and the declaration scope of the function
var instructions = closureVar.StoreInstructions.OfType<ILInstruction>()
.Concat(closureVar.AddressInstructions).OrderBy(inst => inst.StartILOffset);
@ -262,6 +274,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -262,6 +274,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
function.DeclarationScope = closureVar.CaptureScope;
else
function.DeclarationScope = FindCommonAncestorInstruction<BlockContainer>(function.DeclarationScope, closureVar.CaptureScope);
return true;
}
}

5
ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

@ -113,6 +113,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -113,6 +113,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else {
if (displayClass.CaptureScope == null && !localFunctionClosureParameter)
displayClass.CaptureScope = isMono && IsMonoNestedCaptureScope(closureType) ? null : v.CaptureScope;
if (displayClass.CaptureScope != null && !localFunctionClosureParameter) {
displayClass.DeclaringFunction = displayClass.CaptureScope.Ancestors.OfType<ILFunction>().First();
}
displayClass.Variable = v;
displayClass.Initializer = inst;
displayClasses.Add(v, displayClass);
@ -297,6 +300,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -297,6 +300,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
instructionsToRemove.Add(inst);
value = inst.Value;
} else {
context.Step($"Introduce captured variable for {field.FullName}", inst);
Debug.Assert(displayClass.Definition == field.DeclaringTypeDefinition);
// Introduce a fresh variable for the display class field.
if (displayClass.IsMono && displayClass.CaptureScope == null && !IsOuterClosureReference(field)) {
@ -348,6 +352,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -348,6 +352,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return;
var field = (IField)inst.Field.MemberDefinition;
if (!displayClass.Variables.TryGetValue(field, out DisplayClassVariable info)) {
context.Step($"Introduce captured variable for {field.FullName}", inst);
// Introduce a fresh variable for the display class field.
Debug.Assert(displayClass.Definition == field.DeclaringTypeDefinition);
var v = displayClass.DeclaringFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name);

Loading…
Cancel
Save