合并表达式导致 Fody 中的 return 语句出现问题
Coalesce expression causing an issue in return statements in 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 中应用 'fix the returns',我会得到以下 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
在 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;
}
}
到目前为止它在一个体面大小的程序中工作。我会继续关注它,如果有任何变化,我会更新。如果我能在 'return fixer'.
中找到问题的根源就更好了
我认为您到达 IL_000b
时的堆栈大小不一致,具体取决于来自 IL0004
或 IL0009
。
这是我的分析,右边的值是执行相应行后的堆栈大小。
[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 并查看那里的输出。
考虑以下代码片段:
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 中应用 'fix the returns',我会得到以下 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
在 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;
}
}
到目前为止它在一个体面大小的程序中工作。我会继续关注它,如果有任何变化,我会更新。如果我能在 'return fixer'.
中找到问题的根源就更好了我认为您到达 IL_000b
时的堆栈大小不一致,具体取决于来自 IL0004
或 IL0009
。
这是我的分析,右边的值是执行相应行后的堆栈大小。
[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 并查看那里的输出。