【问题标题】:Access violation inside LoadLibrary() callLoadLibrary() 调用中的访问冲突
【发布时间】:2010-11-02 19:28:32
【问题描述】:

在 LabVIEW 中调用 DLL 时遇到访问冲突。我们将 DLL 称为“extcode.dll”。我没有它的代码,它来自外部制造商。

在 Windbg 中运行它,它停止并显示消息:

(724.1200): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
ntdll!RtlNewSecurityObjectWithMultipleInheritance+0x12a:

调用栈是:

ntdll!RtlNewSecurityObjectWithMultipleInheritance+0x12a
ntdll!MD5Final+0xedfc
ntdll!RtlFindClearBitsAndSet+0xdf4
ntdll!RtlFindClearBitsAndSet+0x3a8
ntdll!RtlFindClearBitsAndSet+0x4b9
ntdll!RtlCreateProcessParametersEx+0x829
ntdll!LdrLoadDll+0x9e
KERNELBASE!LoadLibraryExW+0x19c
KERNELBASE!LoadLibraryExA+0x51
LabVIEW!ChangeVINameWrapper+0x36f5
LabVIEW!ChangeVINameWrapper+0x3970
LabVIEW!ExtFuncDynLibWrapper+0x211

请注意,extcode.dll 的依赖项是在访问冲突之前加载的。

情况是随机的,但当它发生时,所有后续尝试都会导致它。

代码是一个简单的LabVIEW函数调用DLL中的函数,原型非常简单(int function(void)),所以它不会是调用参数的错误配置,也不是指针算法。我检查了调用约定和错误检查级别的所有组合。

在其他环境(.NET 和 C)中调用时,DLL 运行良好。

我发现RtlFindClearBitsAndSet与位数组操作有关

这让你想到了什么?您认为这是 extcode.dll、LabVIEW 还是 Windows 中的问题?

PS:我在 Windows 7 64 位上使用 LabVIEW 2010 64 位(而 extcode.dll 是 64 位)。我没能在 32 位系统上重现它。

11/18 编辑

我最终制作了一个包装 DLL 的独立 exe; LabVIEW通过管道与其通信。它运行良好,但我仍然不明白为什么将 DLL 加载到 LabVIEW 中会崩溃。

【问题讨论】:

    标签: winapi dll labview loadlibrary


    【解决方案1】:

    如果从 C 调用时运行正常,您可以退出使用 Windbg,因为 DLL 可能正常。 DLL 的调用方式出现了问题,一旦 DLL 覆盖了 LabView 的一些内存,一切就结束了,尽管它可能需要 1000 次迭代才能真正实现 kablooey。

    首先检查您的调用约定,C 或 StdCall。 C 调用约定是默认设置,几乎可以肯定 StdCall 是您想要的。 (检查 DLL 头文件。) LabView 2009 显然对调用约定进行了一些自动检查和修复,但是在 LV 2010 中切换到 LLVM 使这变得不可能;现在它只是坦克。

    如果更改后它仍然无法使用,请再次检查您的调用参数。你在传递什么,标量或指针数据?尽管您可以在 LabView 中分配内存(即字节数组)并将指向它的指针传递给 DLL 以供其修改,但您无法从 LabView 访问 DLL 分配的内存而不做一些偷偷摸摸的事情。

    此外,如果您从先前对 DLL 的调用中获取指针(例如引用句柄)并返回它,请检查您的指针大小。 LabView 的调用库函数现在有一个“指针大小整数”类型,它根据是在 32 位还是 64 位 LabView 中调用来生成适当大小的类型。 (在线上总是 64 位,因为必须在编译时定义。)您的 DLL 在 32 位下工作的事实表明这是一种可能性。

    还请记住,C 结构通常由 (C) 编译器对齐。如果您传递一个指向由 Uint8 和 UInt16 组成的结构的指针,C 编译器将为此分配 32 位(甚至可能是 64 位)。您必须在 LabView 中填充您的结构(集群)以使其匹配,或者编写一个包装 DLL 来组装该结构。

    -罗伯

    【讨论】:

    • 感谢您的回答:原型是int func(void),所以不可能是调用约定或参数指针问题。
    • 也许您应该向 NI 开一个支持案例。他们非常擅长帮助解决此类问题。
    【解决方案2】:

    如果您的计算机上启用了 DEP(数据执行保护)并且不同意您的二进制文件(EXE 或 DLL)尝试执行的操作,也会报告访问冲突 (0xc0000005)。 DEP 通常在 Windows XP 上默认关闭,但在 Windows Vista / Windows 7 上处于活动状态。

    DEP 是一种硬件支持的安全措施,旨在防止恶意代码执行一些以前被认为“只是一些数据”的字节;我遇到了一些问题,所有这些都需要使用最新版本的 Microsoft Visual Studio 重新编译有问题的二进制文件;这允许你设置一个标志来定义你的二进制文件是否支持DEP

    一些有用的资源:

    • 我找到了this MSDN blog entry 对获得一个非常有帮助 了解 DEP 是什么以及做什么
    • 您可能还想咨询 this technet article 了解如何转 在 Windows XP 上打开和关闭 DEP。

    【讨论】:

    • 谢谢爱德华;我无法测试是否是问题所在,因为我通过在单独的进程中加载​​ DLL 并进行 IPC 调用来解决它。
    【解决方案3】:

    这很难远程诊断,但这里有几个想法。

    您的函数不带参数的事实意味着该函数是真正微不足道的,或者 dll 中有一些存储状态考虑了以前的函数调用。也许这个函数的崩溃只是一个指标,你之前的函数调用有问题?有没有你没有调用的初始化程序?

    如果您只在使用 64 位 labview 时遇到问题,我的第一个猜测是 64 位版本的 dll 存在问题,但如果您确定在使用完全相同的调用时没有任何问题在其他环境中使用 dll,我很难过。一种可能性是您在 labview 中使用了错误的调用约定(stdcall 与 cdecl)。

    您是否尝试过使用 labview 导入向导导入 dll 和标头?这可能有助于避免原型的愚蠢错误。

    【讨论】:

    • 没有初始化例程,它可以与这个单一的函数调用一起工作。尝试了labview导入向导,不同的调用约定,没有成功。原型非常简单(int func(void)),所以它不是指针问题。我也被难住了。
    【解决方案4】:

    要尝试的另一件事:右键单击 DLL 调用,选择配置并确保您在 UI 线程而不是任何线程中运行。有时这会有所帮助。

    【讨论】:

      【解决方案5】:

      在 NTFS 下使用 git 和 cygwin 时,我发现有时可执行位未设置(或在结帐或某些文件操作期间未设置)- 在 cygwin cd 到文件夹中并执行

      chmod a+rwx *.dll
      

      并检查它是否改变了东西(并检查你是否想要这样!)。我在搜索 LoadLibrary() 时发现了这个问题,GetLastError() 返回 5(不是“0xc0000005”顺便说一句),并通过这个 chmod 调用解决了这个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-06-05
        • 1970-01-01
        • 1970-01-01
        • 2018-09-07
        • 1970-01-01
        • 2021-12-18
        • 2016-06-22
        相关资源
        最近更新 更多