Browse Source

Fix #890: Correctly handle calls with out-parameters in definite assignment analysis.

pull/1087/head
Daniel Grunwald 7 years ago
parent
commit
a86a0586bb
  1. 43
      ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs

43
ICSharpCode.Decompiler/FlowAnalysis/DefiniteAssignmentVisitor.cs

@ -184,16 +184,45 @@ namespace ICSharpCode.Decompiler.FlowAnalysis @@ -184,16 +184,45 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
protected internal override void VisitLdLoca(LdLoca inst)
{
// A variable needs to be initialized before we can take it by reference.
// The exception is if the variable is passed to an out parameter.
if (!IsOutArgument(inst)) {
EnsureInitialized(inst.Variable);
}
// The exception is if the variable is passed to an out parameter (handled in VisitCall).
EnsureInitialized(inst.Variable);
}
static bool IsOutArgument(ILInstruction inst)
protected internal override void VisitCall(Call inst)
{
return inst.Parent is CallInstruction call
&& call.GetParameter(inst.ChildIndex)?.IsOut == true;
HandleCall(inst);
}
protected internal override void VisitCallVirt(CallVirt inst)
{
HandleCall(inst);
}
protected internal override void VisitNewObj(NewObj inst)
{
HandleCall(inst);
}
void HandleCall(CallInstruction call)
{
bool hasOutArgs = false;
foreach (var arg in call.Arguments) {
if (arg.MatchLdLoca(out var v) && call.GetParameter(arg.ChildIndex)?.IsOut == true) {
// Visiting ldloca would require the variable to be initialized,
// but we don't need out arguments to be initialized.
hasOutArgs = true;
} else {
arg.AcceptVisitor(this);
}
}
// Mark out arguments as initialized, but only after the whole call:
if (hasOutArgs) {
foreach (var arg in call.Arguments) {
if (arg.MatchLdLoca(out var v) && call.GetParameter(arg.ChildIndex)?.IsOut == true) {
HandleStore(v);
}
}
}
}
}
}

Loading…
Cancel
Save