LLVM绑定中的不平衡堆栈警告

3

经过几周的努力,我已成功编写了使用LLVM进行JIT编译的F#程序。然而,每当我在附加了调试器的Visual Studio 2010中运行我的程序(即按下F5键),都会收到以下警告:

enter image description here

现在,当我在我的Windows 7 netbook上使用每个PInvoke调用时,都会收到这个警告,但是当我在我的Windows Vista台式机上使用某些调用时,只会有一些警告。
其他人遇到这个问题似乎通过向PInvoke调用添加请求ANSI字符串或CDecl调用约定的属性来解决了它。我发现改变调用约定可以修复Windows Vista桌面上的警告,但是所有可用的调用约定(或ANSI格式字符串)都无法修复Windows 7 netbook上的警告。有什么想法如何解决这个问题?
请注意,两台计算机都是完全的32位x86。
编辑
人们发布评论要求重现。最简单的方法是按照我记录的说明here安装LLVM和llvm-fs,并运行任何给定的示例程序。它们在我的netbook上对LLVM的所有调用都表现出这个问题。
或者,以下代码(源自llvm-fs)应该能够重现问题,而不需要llvm-fs:
open System.Runtime.InteropServices

[<DllImport("LLVM-3.0.dll",
            EntryPoint="LLVMModuleCreateWithName",
            CharSet=CharSet.Ansi,
            CallingConvention=CallingConvention.Cdecl)>]
extern void *moduleCreateWithNameNative(string ModuleID)

let mdl = moduleCreateWithNameNative "foo"

请注意,原始的C头文件中对应的定义如下:
typedef struct LLVMOpaqueModule *LLVMModuleRef;
...
LLVMModuleRef LLVMModuleCreateWithName(const char *ModuleID);

1
发一个小例子来展示这个问题。 - Mark Tolonen
如果您不告诉我们您正在做什么,我们恐怕无法帮助您。请向我们展示(部分)展示问题的代码! - svick
你是用Mono还是MS构建F#代码? - Onorio Catenacci
你确定原生代码百分之百使用cdecl吗? - David Heffernan
当你说将其设置为cdecl时,你指的是在pinvoke中。我会期望C++库使用cdecl,所以这很合理。现在,pinvoke的返回类型看起来有点奇怪。我认为它应该是IntPtr。因此声明应该是extern IntPtr moduleCreateWithNameNative(string ModuleID) - David Heffernan
显示剩余3条评论
1个回答

4
你是针对.NET 4.0或早期版本进行开发吗?
我这么问的原因是,CLR有一个安全稳定性功能,对Pinvoke签名进行了额外严格的检查。这个功能自.NET 2.0以来就一直存在,但默认情况下在.NET 4.0之前都是关闭的。
行为上的变化导致许多开发人员报告了与你相同的问题;他们的绑定在.NET 2.0/3.5上运行良好,但在编译为.NET 4.0时开始抛出错误。实际上,问题在于先前版本的.NET允许略有瑕疵的PInvoke签名无影响地工作;现在默认情况下进行了严格检查,这些漏洞开始显露出来。
另一个需要注意的事情是,即使你更改了计算机上的配置以禁用.NET 4.0中的此行为,Visual Studio仍然在调试项目时始终使用它。更糟糕的是,严格检查默认只在.NET 4.0 x86版本中开启,而不是x64版本,因此在64位机器上正常工作的程序集在32位机器上可能会崩溃。

MSDN上有更多关于pInvokeStackImbalance MDA的信息,而this blog post则提供了更多关于为什么在调试过程中会出现问题的详细信息。

编辑:我刚注意到你编辑了你的问题,包括了一个代码示例。这证实了我的猜测,即PInvoke签名稍微有些错误。如果你将签名从extern void *moduleCreateWithNameNative(string ModuleID)改为extern LLVMModuleRef* moduleCreateWithNameNative(string ModuleID),会发生什么?

这看起来也像是编译器的一个bug——F#不应该允许你定义一个名为*moduleCreateWithNameNative的方法。我猜它允许这样做(出于某种原因),所以你的函数的返回类型被编译为void——当本机方法尝试返回一个值(指向LLVMModuleRef结构体的指针)时,CLR会被绊倒并崩溃。


两台机器都是.NET 4.0,但其中一台可以正常运行,而另一台在每次调用时都会出错。 - J D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接