【问题标题】:What is a stack imbalance?什么是堆栈不平衡?
【发布时间】:2011-10-10 09:46:51
【问题描述】:

阅读这篇文章F# Versus Mathematics: Part One - Getting Started with BLAS and LAPACK后,我在A Warning, Perhaps an Omen段落中偶然发现了stack imbalance这个词。

googled 并在SO 上进行了搜索,但只能找到因堆栈不平衡而苦苦挣扎的人,而没有一般性的解释。

额外问题: 它只影响 f# 还是 C、C++、Python、Java 等中的普遍问题?

附言如有必要,请更改问题的标签

【问题讨论】:

  • 简而言之,这意味着您正在调用具有错误签名的非托管函数。
  • 它会影响任何带有FFI 的语言到非托管代码。

标签: memory-management f# stack terminology


【解决方案1】:

当用于跟踪调用函数、参数和返回值的数据结构损坏或未对齐时,就会发生堆栈不平衡。

大多数时候,堆栈是一个内存指针,它存储当当前函数调用退出回调用者时控制将恢复的地址。对此有不同的变体,有时函数的参数以及返回值也附加到堆栈中。这里最重要的是调用者和被调用者应该就如何在被调用者退出时将其恢复到之前的状态达成一致。该协议通常称为调用约定

在 .NET 中,堆栈不平衡是纯托管代码中罕见甚至不存在的问题。但是,在调用非托管代码时,这可能是一个常见问题,因为您需要告诉编译器应该如何调用该方法,这意味着应该如何按照调用约定清理堆栈。

在 Windows 上,有一些标准调用约定涵盖了大部分调用情况。

stdcall - 被调用者将在退出时修复堆栈。
fastcall - 除了返回地址之外,可能不需要修复堆栈,而是使用 CPU 寄存器传递参数。
cdecl - 调用者将在被调用函数返回后修复堆栈。

此处提供正式参考:Argument Passing and Naming Conventions @ MSDN

这也很有趣:X86 calling convention list @ Wikipedia

在给定的开发领域内,这往往不是问题。每种语言通常都有一个对所有方法调用都隐含的约定。 C/C++ 使用相同的约定来调用 C/C++ 调用,Python 用于其他 Python 调用等。跨域时,如果一个域与另一个域不使用相同的域,则可能会成为问题。也许在 Windows 中最常见的是,使用“C”样式声明 (cdecl) 导出的函数在调用时可能会导致堆栈不平衡(或更糟),就好像它具有 stdcall 约定一样,这是 WINAPI(Windows 系统)调用识别的方法。

【讨论】:

  • +1 用于非常通用且与语言无关的描述以及具体示例。
【解决方案2】:

我们前几天才看到这个(用 c# 和 c++ 编组)

我请您参考MSDN 页面上的文字:

pInvokeStackImbalance 托管调试助手 (MDA) 是 当 CLR 检测到平台后的堆栈深度时激活 调用调用与预期的堆栈深度不匹配,给定调用 DllImportAttribute 属性中指定的约定以及 托管签名中的参数声明。

我意识到这是针对特定的编译器警告,但该页面提供了一些信息,说明堆栈不平衡是什么、导致它的原因、症状是什么以及如何解决它。正如丹尼尔所说,这通常是由于托管和非托管的签名不匹配。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 2016-05-06
    • 1970-01-01
    • 2011-05-22
    • 1970-01-01
    • 2014-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-13
    相关资源
    最近更新 更多