3

经过数周的努力,我设法编写了使用 LLVM 进行 JIT 编译的 F# 程序。但是,每当我在带有调试器的 Visual Studio 2010 中运行我的程序时(即按 F5),我都会收到以下警告:

在此处输入图像描述

现在,在使用我的 Windows 7 上网本时,每次 PInvoke 调用都会收到此警告,但在使用 Windows Vista 桌面时,我只会在某些调用中收到此警告。

其他遇到这个问题的人似乎已经通过向请求 ANSI 字符串或CDecl调用约定的 PInvoke 调用添加属性来解决它。我发现更改调用约定修复了我的 Windows Vista 桌面上的警告,但没有可用的调用约定(或 ANSI 格式字符串)修复我的 Windows 7 上网本上的警告。任何想法如何解决这一问题?

请注意,两台机器都是 32 位 x86。

编辑

人们正在发表评论,要求重新进行。重现此问题的最简单方法是按照我在此处记录的说明安装 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);
4

1 回答 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 在调试项目时仍将始终使用它。更糟糕的是,严格检查仅在 x86 版本的 .NET 4.0 中默认启用,而不是 x64 版本,因此在 64 位机器上运行良好的程序集可能在 32 位机器上崩溃。

MSDN 提供了有关pInvokeStackImbalance MDA的更多信息,并且这篇博文还提供了有关为什么在调试过程中出现问题的更多详细信息。

编辑:我刚刚注意到您编辑了您的问题以包含一个代码示例。这证实了我对 PInvoke 签名略有错误的怀疑。如果将签名从 更改为 会发生extern void *moduleCreateWithNameNative(string ModuleID)什么extern LLVMModuleRef* moduleCreateWithNameNative(string ModuleID)

看起来这里还有一个编译器错误在起作用——F# 不应该允许你定义一个名为*moduleCreateWithNameNative. 我猜它允许它(无论出于何种原因),所以你的函数的返回类型被编译为void- 当本机方法试图返回一个值(一个指向 LLVMModuleRef 结构的指针)时,CLR 被绊倒了并且崩溃。

于 2012-03-04T17:26:06.573 回答