2017-08-15 58 views
0

在return语句引起的问题考虑下面的代码片段:联合表达Fody

private string GetFieldValueAsString(string nonAliasedEntityName = null, string nonAliasedName = null) 
{ 
    return nonAliasedEntityName ?? nonAliasedName; // simplified code of course! 
} 

它被编译到下面的IL代码:

.method private hidebysig 
    instance string GetFieldValueAsString (
     [opt] string nonAliasedEntityName, 
     [opt] string nonAliasedName 
    ) cil managed 
{ 
    .param [1] = nullref 
    .param [2] = nullref 
    // Method begins at RVA 0x2cb6f 
    // Code size 7 (0x7) 
    .maxstack 8 

    IL_0000: ldarg.1 
    IL_0001: dup 
    IL_0002: brtrue.s IL_0006 

    IL_0004: pop 
    IL_0005: ldarg.2 

    IL_0006: ret 
} // end of method MessageBuilder::GetFieldValueAsString 

如果我申请“修复的回报'在Fody,我得到以下的IL代码:

.method private hidebysig 
    instance string GetFieldValueAsString (
     [opt] string nonAliasedEntityName, 
     [opt] string nonAliasedName 
    ) cil managed 
{ 
    .param [1] = nullref 
    .param [2] = nullref 
    // Method begins at RVA 0x2cb70 
    // Code size 15 (0xf) 
    .maxstack 3 
    .locals (
     [0] string $returnVariable 
    ) 

    IL_0000: ldarg.1 
    IL_0001: dup 
    IL_0002: dup 
    IL_0003: stloc.0 
    IL_0004: brtrue.s IL_000b 

    IL_0006: pop 
    IL_0007: ldarg.2 
    IL_0008: stloc.0 
    IL_0009: br.s IL_000b 

    IL_000b: nop 
    IL_000c: nop 
    IL_000d: ldloc.0 
    IL_000e: ret 
} // end of method MessageBuilder::GetFieldValueAsString 

它给我下面的错误时,反编译我n ILSpy,并且无法运行:

ICSharpCode.Decompiler.DecompilerException: Error decompiling System.String LinkDev.Notifications.Steps.MessageBuilder::GetFieldValueAsString(System.String,System.String) 
---> System.Exception: Inconsistent stack size at IL_09 
    at ICSharpCode.Decompiler.ILAst.ILAstBuilder.StackAnalysis(MethodDefinition methodDef) 
    at ICSharpCode.Decompiler.ILAst.ILAstBuilder.Build(MethodDefinition methodDef, Boolean optimize, DecompilerContext context) 
    at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(IEnumerable`1 parameters) 
    at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDefinition methodDef, DecompilerContext context, IEnumerable`1 parameters) 
    --- End of inner exception stack trace --- 
    at ICSharpCode.Decompiler.Ast.AstMethodBodyBuilder.CreateMethodBody(MethodDefinition methodDef, DecompilerContext context, IEnumerable`1 parameters) 
    at ICSharpCode.Decompiler.Ast.AstBuilder.CreateMethod(MethodDefinition methodDef) 
    at ICSharpCode.Decompiler.Ast.AstBuilder.AddMethod(MethodDefinition method) 
    at ICSharpCode.ILSpy.CSharpLanguage.DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) 
    at ICSharpCode.ILSpy.TextView.DecompilerTextView.DecompileNodes(DecompilationContext context, ITextOutput textOutput) 
    at ICSharpCode.ILSpy.TextView.DecompilerTextView.<>c__DisplayClass31_0.<DecompileAsync>b__0() 

我追踪了堆栈大小,它似乎成立。任何想法可能导致这个问题?

更新1:

我添加了一个临时的快速修复问题:

Instruction doubleDupInstruction = null; 

for (var index = 0; index < instructions.Count; index++) 
{ 
    var instruction = instructions[index]; 

    if (instruction.OpCode == OpCodes.Dup && instructions[index + 1].OpCode == OpCodes.Dup) 
    { 
     doubleDupInstruction = instructions[index + 1]; 
    } 

    if (instruction.OpCode == OpCodes.Pop && doubleDupInstruction != null) 
    { 
     var extraPopInstruction = instructions[index]; 
     ilProcessor.Remove(extraPopInstruction); 
     ilProcessor.InsertAfter(doubleDupInstruction, extraPopInstruction); 
     doubleDupInstruction = null; 
    } 
} 

到目前为止,它工作在一个中型项目。我会继续监控它,并会在有任何更改时进行更新。如果我能在“回复​​定影剂”中找到问题的根源,那将会好得多。

回答

2

我认为你在到达IL_000b时有不一致的堆栈大小,这取决于来自IL0004IL0009

这是我的分析,右边的值是执行相应行后的堆栈大小。

      [0] 
IL_0000: ldarg.1   [1] 
IL_0001: dup    [2] 
IL_0002: dup    [3] 
IL_0003: stloc.0   [2] 
IL_0004: brtrue.s IL_000b [1]--- 
           | 
IL_0006: pop    [0] | 
IL_0007: ldarg.2   [1] | 
IL_0008: stloc.0   [0] | 
IL_0009: br.s IL_000b  [0] | 
           v 
IL_000b: nop    [?] arriving here is inconsistent 
IL_000c: nop 
IL_000d: ldloc.0 
IL_000e: ret 

也许你可以针对这种方法运行PEVerify,看看那里有什么输出。

+0

我检查了一些编译的代码示例,并且在所有这些示例中,我发现'stloc'后面跟'br'是非常常见的。所以,我不认为'br'使用堆栈中的任何东西来评估。 – os008

+0

是的你是对的。这是一个无条件的分支。没有下溢,但仍然不一致 – thehennyy

+0

请您详细说明在这种情况下它是如何不一致的?我能做些什么来解决它? – os008