经过数周的努力,我成功编写了使用LLVM进行JIT编译的F#程序。但是,每当我在附带调试器的Visual Studio 2010中运行我的程序时(即通过按F5),我会收到以下警告:
现在,在使用我的Windows 7上网本时,每次PInvoke调用都会收到此警告,但在使用Windows Vista桌面时,我只能接听一些电话。
其他遇到此问题的人似乎通过向请求ANSI字符串或CDecl
调用约定的PInvoke调用添加属性来解决此问题。我发现更改调用约定会修复Windows Vista桌面上的警告,但是没有可用的调用约定(或ANSI格式字符串)修复了我的Windows 7上网本上的警告。任何想法如何解决这个问题?
请注意,这两台计算机完全是32位x86。
修改
人们正在发表评论,要求提供重复报道。重现此问题的最简单方法是按照我记录的here的说明安装LLVM和llvm-fs,并运行给定的任何示例程序。他们都在我的上网本上对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);
答案 0 :(得分: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仍然始终在调试项目时使用它。 更糟糕的是,严格检查仅在x86版本的.NET 4.0中默认启用,而不是x64版本,因此在64位计算机上运行良好的程序集可能会在32位计算机上崩溃强>
MSDN有关于pInvokeStackImbalance MDA和this blog post的更多信息,还提供了有关在调试过程中问题突然出现的更多详细信息。
编辑:我刚刚注意到您编辑了您的问题以包含代码示例。这种情况证实了我对PInvoke签名轻微错误的怀疑。如果您将签名从extern void *moduleCreateWithNameNative(string ModuleID)
更改为extern LLVMModuleRef* moduleCreateWithNameNative(string ModuleID)
会怎样?
在这里看起来还有一个编译器错误--F#不应该允许你定义一个名为*moduleCreateWithNameNative
的方法。我猜它是允许的(无论出于何种原因),因此函数的返回类型编译为void
- 当本机方法尝试返回一个值(指向LLVMModuleRef结构的指针)时CLR被绊倒并崩溃。