[英]Why is this code failing to verify?
I have a compiler that builds and runs correctly, but PEVerify is calling it unverifiable at a certain point. 我有一个正确构建和运行的编译器,但PEVerify在某个时刻称其无法验证。 After looking carefully at the error, the corresponding source code, and the ILDasm output for the point in question, I can't find the problem, to the point where I would suspect a bug in PEVerify, except that the .NET and Mono versions report the same error in the same place.
仔细查看错误,相应的源代码和相关点的ILDasm输出后,我找不到问题,我怀疑PEVerify中存在错误,除了.NET和Mono版本在同一个地方报告相同的错误。
The problematic method reads as follows: 有问题的方法如下:
internal static bool InAsyncMethod(Expression value)
{
INodeWithBody ancestor = value.GetAncestor<BlockExpression>() ?? (INodeWithBody) value.GetAncestor<Method>();
return ContextAnnotations.IsAsync(ancestor);
}
The error is reported as: 该错误报告为:
[IL]: Error: [D:\\SDL-1.3.0-4423\\boo\\build\\Boo.Lang.Compiler.dll : Boo.Lang.Compiler.TypeSystem.AsyncHelper::InAsyncMethod][offset 0x00000011][found ref 'Boo.Lang.Compiler.Ast.Node'][expected ref Boo.Lang.Compiler.Ast.INodeWithBody'] Unexpected type on the stack.
[IL]:错误:[D:\\ SDL-1.3.0-4423 \\ boo \\ build \\ Boo.Lang.Compiler.dll:Boo.Lang.Compiler.TypeSystem.AsyncHelper :: InAsyncMethod] [offset 0x00000011] [找到参考'Boo.Lang.Compiler.Ast.Node'] [预期ref Boo.Lang.Compiler.Ast.INodeWithBody']堆栈上的意外类型。
Offsest 0x11
corresponds to the second half of the ??
Offsest
0x11
对应于??
后半部分。 expression. 表达。 From ILDasm:
来自ILDasm:
.method assembly hidebysig static bool InAsyncMethod(class Boo.Lang.Compiler.Ast.Expression 'value') cil managed
{
// Code size 29 (0x1d)
.maxstack 2
.locals init ([0] class Boo.Lang.Compiler.Ast.INodeWithBody ancestor,
[1] bool CS$1$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance !!0 Boo.Lang.Compiler.Ast.Node::GetAncestor<class Boo.Lang.Compiler.Ast.BlockExpression>()
IL_0007: dup
IL_0008: brtrue.s IL_0011
IL_000a: pop
IL_000b: ldarg.0
IL_000c: callvirt instance !!0 Boo.Lang.Compiler.Ast.Node::GetAncestor<class Boo.Lang.Compiler.Ast.Method>()
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: call bool Boo.Lang.Compiler.Steps.ContextAnnotations::IsAsync(class Boo.Lang.Compiler.Ast.INodeWithBody)
IL_0018: stloc.1
IL_0019: br.s IL_001b
IL_001b: ldloc.1
IL_001c: ret
} // end of method AsyncHelper::InAsyncMethod
The Boo.Lang.Compiler.Ast.Node
class is the base class for all AST nodes. Boo.Lang.Compiler.Ast.Node
类是所有AST节点的基类。 BlockExpression
and Method
are the node classes for lambdas and methods, respectively, both of which implement the INodeWithBody
interface. BlockExpression
和Method
分别是lambda和方法的节点类,它们都实现了INodeWithBody
接口。 Everything appears correct, both in the C# (which would not build if there were type problems) and in the IL (where it says at 000c
that the return type of the GetAncestor<Method>
call is !!0
, the first type parameter on the method call.) 一切看起来都是正确的,无论是在C#中(如果存在类型问题都不会构建)和IL中(在
000c
处它表示GetAncestor<Method>
调用的返回类型是!!0
,第一个类型参数on方法调用。)
What is causing PEVerify to think it's dealing with a value of type Node
here when it clearly has a value of type Method
? 是什么导致PEVerify认为它处理类型为
Node
的值,当它显然具有Method
类型的值时? And is there any way to fix it? 有没有办法解决它?
What is causing PEVerify to think it's dealing with a value of type
Node
here when it clearly has a value of typeMethod
?是什么导致PEVerify认为它处理类型为
Node
的值,当它显然具有Method
类型的值时?
As pointed out by Stephane Delcroix as well, there are two code paths reaching to IL_0011
, as it is the target of a branch. 正如Stephane Delcroix所指出的那样,有两条代码路径可以达到
IL_0011
,因为它是分支的目标。 It clearly does not necessarily have a value of type Method
. 它显然不一定具有
Method
类型的值。
GetAncestor<TAncestor>
returns TAncestor
. GetAncestor<TAncestor>
返回TAncestor
。 You've got either GetAncestor<BlockExpression>
's result, or GetAncestor<Method>
's result, so either BlockExpression
or Method
. 你有
GetAncestor<BlockExpression>
的结果,或者GetAncestor<Method>
的结果,所以要么是BlockExpression
,要么是Method
。 Both implement INodeWithBody
, so logically, the code is still fine. 两者都实现了
INodeWithBody
,从逻辑INodeWithBody
,代码仍然很好。
Unfortunately, "either BlockExpression
or Method
" is too much for verification. 不幸的是,“
BlockExpression
或Method
”对于验证来说太过分了。 This gets simplified to Node
(the common base), which does not implement INodeWithBody
. 这被简化为
Node
(共用基),它不实现INodeWithBody
。 See ECMA-335 §III.1.8.1.3: 见ECMA-335§III.1.8.1.3:
The merged type,
U
, shall be computed as follows (recall thatS := T
is the compatibility function defined in §III.1.8.1.2.2):合并类型
U
应按如下方式计算(回想S := T
是§III.1.8.1.2.2中定义的兼容性函数):
if
S := T
thenU=S
如果
S := T
则U=S
Otherwise, if
T := S
thenU=T
否则,如果
T := S
则U=T
Otherwise, if
S
andT
are both object types, then letV
be the closest common supertype ofS
andT
thenU=V
.否则,如果
S
和T
都是对象类型,那么让V
成为S
和T
最接近的公共超类型,然后U=V
Otherwise, the merge shall fail.
否则,合并将失败。
If you check what the C# compiler does, you'll see that it emits a stloc.0
/ ldloc.0
combination into a local of type INodeWithBody
prior to the dup
. 如果你检查C#编译器的作用,你会看到它在
dup
之前将一个stloc.0
/ ldloc.0
组合发送到一个INodeWithBody
类型的本地。 This makes everything work, because the common type of INodeWithBody
and Method
is then INodeWithBody
. 这使一切正常,因为
INodeWithBody
和Method
的常见类型是INodeWithBody
。
It's unclear if it fails on 0x11
due to the first or the right part of the ??
目前还不清楚它是否因为第一部分或右部分而在
0x11
失败??
as 0x08
is branching to there. 因为
0x08
正在分支到那里。
I'm leaning toward thinking GetAncestor<>
returns a Node
and the left part of the ??
我倾向于认为
GetAncestor<>
返回一个Node
和左侧部分??
is missing an explicit cast. 缺少一个明确的演员。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.