System.AccessViolationException 使用 Reflectio.emit 存储变量
我正在业余时间使用 Reflection.emit 构建一个编译器,但我遇到了一个我不理解的问题。
一点上下文,我有一个具有几种类型的运行时,其中之一是 Float2,这是一个具有两个浮点值(X 和 Y)的更简单的向量结构。我创建了几个属性,允许我调整值(la hlsl)。例如,如果我有一个新的 Float2(1.0f, 2.0f),如果我做了类似 (new Float2(1.0f, 2.0f)).YX 的东西,我将得到一个 Float2(2.0f, 1.0f) 我正在我的语言中使用这种类型,并且当前正在测试这种情况(省略了语言的次要细节):
float2 a = float2(1.0, 2.0).yx;
return a;
我正在新的调用中转换 float2(1.0, 2.0) 并访问 .yx 中我的 Float2 类型的属性 YX。
问题是我收到“System.AccessViolationException:尝试读取或写入受保护的内存。这通常表明其他内存已损坏。”。我不明白为什么,因为如果我做这样的事情:
float2 a = float2(1.0, 2.0);
return a;
一切都会顺利。
我生成的 IL 代码如下(我认为问题出现在“L_0014:stloc.0”中,但我不知道为什么会发生):
.method public virtual final instance valuetype
[Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 Main() cil managed
{
.maxstack 3
.locals init (
[0] valuetype [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 num)
L_0000: ldc.r4 1
L_0005: ldc.r4 2
L_000a: newobj instance void [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2::.ctor(float32, float32)
L_000f: call instance valuetype [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2::get_XY()
L_0014: stloc.0
L_0015: ldloc.0
L_0016: ret
}
peverify 的结果:
[IL]:错误:[offset 0x0000000F ] [发现值“Bifrost.Psl.Compiler.Runtime.Float2”][值“Bifrost.Psl.Compiler.Runtime.Float2”的预期地址]堆栈上的意外类型。
I'm building a compiler with reflection.emit in my spare time, and i've come to a problem that i'm not understanding.
A little context, I've a runtime with a couple of types and one of them is Float2, a simpler vector struct with two float values (X and Y). I've made a couple of properties that allow me to swizzle the values (a la hlsl). For example if i have a new Float2(1.0f, 2.0f), if i make something like (new Float2(1.0f, 2.0f)).YX i'm going to get a Float2(2.0f, 1.0f)
I'm using this type in my language and currently testing this case (minor details of the language omitted):
float2 a = float2(1.0, 2.0).yx;
return a;
I'm transforming float2(1.0, 2.0) in a new call and accessing the property YX of my Float2 type in .yx.
The problem is I'm getting a "System.AccessViolationException : Attempted to read or write protected memory. This is often an indication that other memory is corrupt.". I don't understand why because if I make something like this:
float2 a = float2(1.0, 2.0);
return a;
Everything goes well.
The IL code that i'm generating is the following (I think the problem occurs in "L_0014: stloc.0", I don't know why it happens though) :
.method public virtual final instance valuetype
[Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 Main() cil managed
{
.maxstack 3
.locals init (
[0] valuetype [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 num)
L_0000: ldc.r4 1
L_0005: ldc.r4 2
L_000a: newobj instance void [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2::.ctor(float32, float32)
L_000f: call instance valuetype [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2 [Bifrost.Psl]Bifrost.Psl.Compiler.Runtime.Float2::get_XY()
L_0014: stloc.0
L_0015: ldloc.0
L_0016: ret
}
Result of peverify:
[IL]: Error: [offset 0x0000000F]
[found value 'Bifrost.Psl.Compiler.Runtime.Float2'][expected address of value 'Bifrost.Psl.Compiler.Runtime.Float2'] Unexpected type on the stack.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
IL 看起来不错,尽管我不知道您的
Float2
是什么样的。我发现调试此问题的最佳方法是将程序集保存到磁盘,然后运行peverify。任何生成
AccessViolationException
的代码都会导致 peverify 中出现错误。编辑: MSDN 上的
newobj
文档 讨论了将对象引用推送到堆栈上,我将其视为指向值类型的指针。如果您从 peverify 收到此错误,那么我认为您需要newobj
stloc
到临时变量ldloca
获取存储在临时变量call
中的值类型的地址现在我想了一下,如果您直接调用像
4 这样的值类型,这就是 C# 编译器所做的事情.ToString();
。The IL looks OK, although I don't know what your
Float2
looks like.I found the best way to debug this is to save the assembly to disk, then run peverify. Any code that generates an
AccessViolationException
will cause an error in peverify.Edit: The
newobj
doc on MSDN talks about pushing an object reference onto the stack, which I took to be a pointer to a value type. If you're getting this error from peverify then I think you need tonewobj
stloc
to a temporary variableldloca
to get the address of the value type stored in the temporary variablecall
Now that I think about it, this is what the C# compiler does if you do a direct call on a value type like
4.ToString();
.