Browse Source

Validate uses of display-class variable copies before removing them

pull/2005/head
Siegfried Pammer 5 years ago
parent
commit
101aba3362
  1. 68
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

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

@ -170,18 +170,42 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -170,18 +170,42 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
}
}
bool ValidateDisplayClassUses(ILVariable v, DisplayClass displayClass, bool readOnly = false)
{
foreach (var ldloc in v.LoadInstructions) {
if (!ValidateUse(displayClass, ldloc))
return false;
}
foreach (var ldloca in v.AddressInstructions) {
if (!ValidateUse(displayClass, ldloca))
return false;
}
return true;
bool ValidateDisplayClassUses(ILVariable v, DisplayClass displayClass)
bool ValidateUse(DisplayClass container, ILInstruction use)
{
foreach (var ldloc in v.LoadInstructions) {
if (!ValidateUse(displayClass, ldloc))
return false;
}
foreach (var ldloca in v.AddressInstructions) {
if (!ValidateUse(displayClass, ldloca))
IField field;
switch (use.Parent) {
case LdFlda ldflda when ldflda.MatchLdFlda(out _, out field):
var keyField = (IField)field.MemberDefinition;
if (!container.VariablesToDeclare.TryGetValue(keyField, out VariableToDeclare variable) || variable == null) {
if (readOnly)
return false;
variable = AddVariable(container, null, field);
}
container.VariablesToDeclare[keyField] = variable;
return variable != null;
case StObj stobj when stobj.MatchStObj(out var target, out ILInstruction value, out _) && value == use:
if (target.MatchLdFlda(out var load, out field) && load.MatchLdLocRef(out var otherVariable) && displayClasses.TryGetValue(otherVariable, out var otherDisplayClass)) {
if (otherDisplayClass.VariablesToDeclare.TryGetValue((IField)field.MemberDefinition, out var declaredVar))
return declaredVar.CanPropagate;
}
return true;
default:
return false;
}
return true;
}
}
@ -285,8 +309,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -285,8 +309,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
private Block FindDisplayStructInitBlock(ILVariable v)
{
var root = v.Function.Body;
var block = Visit(root)?.Ancestors.OfType<Block>().FirstOrDefault();
return block;
return Visit(root)?.Ancestors.OfType<Block>().FirstOrDefault();
ILInstruction Visit(ILInstruction inst)
{
@ -417,28 +440,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -417,28 +440,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return variable;
}
bool ValidateUse(DisplayClass container, ILInstruction use)
{
IField field;
switch (use.Parent) {
case LdFlda ldflda when ldflda.MatchLdFlda(out _, out field):
var keyField = (IField)field.MemberDefinition;
if (!container.VariablesToDeclare.TryGetValue(keyField, out VariableToDeclare variable) || variable == null) {
variable = AddVariable(container, null, field);
}
container.VariablesToDeclare[keyField] = variable;
return variable != null;
case StObj stobj when stobj.MatchStObj(out var target, out ILInstruction value, out _) && value == use:
if (target.MatchLdFlda(out var load, out field) && load.MatchLdLocRef(out var otherVariable) && displayClasses.TryGetValue(otherVariable, out var displayClass)) {
if (displayClass.VariablesToDeclare.TryGetValue((IField)field.MemberDefinition, out var declaredVar))
return declaredVar.CanPropagate;
}
return true;
default:
return false;
}
}
private void Transform(ILFunction function)
{
VisitILFunction(function);
@ -630,8 +631,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -630,8 +631,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
return;
}
// TODO : this is dangerous!
if (inst.Value.MatchLdLocRef(out var otherVariable) && displayClasses.TryGetValue(otherVariable, out displayClass)) {
if (inst.Value.MatchLdLocRef(out var otherVariable) && displayClasses.TryGetValue(otherVariable, out displayClass) && ValidateDisplayClassUses(inst.Variable, displayClass)) {
instructionsToRemove.Add(inst);
displayClasses.Add(inst.Variable, displayClass);
}

Loading…
Cancel
Save