什么是堆栈不平衡?

3
阅读了这篇文章F#与数学:第一部分 - 使用BLAS和LAPACK入门,我在A Warning, Perhaps an Omen段落中发现了术语stack imbalance
我在谷歌上搜索了stack imbalance并在SO上搜索,但只找到了人们在处理栈不平衡的问题,没有一般性的解释。
附加问题: 这只影响f#还是C、C++、Python、Java等通用问题? p.s. 如有必要,请更改问题的标签。

2
简而言之,这意味着您正在使用错误的签名调用未受管控的函数。 - Daniel
1
它会影响任何具备FFI与非托管代码的语言。 - Daniel
2个回答

9
堆栈不平衡是指用于跟踪已调用函数、参数和返回值的数据结构变得损坏或不对齐的情况。
大多数情况下,堆栈是存储当前函数调用退出返回到调用者时控制将恢复的地址的内存指针。有不同的变体,有时也会将函数的参数附加到堆栈上,以及返回值。最重要的是,调用者和被调用者应该就如何在被调用者退出时将其恢复回先前状态达成一致。这种协议通常称为“调用约定”。
在.NET中,在纯托管代码中,堆栈不平衡很少或不存在问题。但是,在调用非托管代码时,这可能是一个频繁的问题,因为您需要告诉编译器应该如何调用方法,这意味着如何根据调用约定清除堆栈。
在Windows上,有几个标准的调用约定涵盖了大部分调用情况。
stdcall - 被调用者将在退出时修复堆栈。 fastcall - 除了返回地址之外,可能没有必要修复堆栈,而是使用CPU寄存器传递参数。 cdecl - 调用者将在调用的函数返回后修复堆栈。

这里提供了正式的参考资料:MSDN上的参数传递和命名惯例

这也很有意思:维基百科上的X86调用约定列表

在特定的开发领域中,这通常不是一个问题。每种语言通常都有一个对所有方法调用隐含的约定。C/C++使用相同的约定来调用C/C++调用,Python用于其他Python调用等等。当跨越领域时,如果一个领域不使用另一个领域相同的约定,可能会成为一个问题。在Windows中最常见的情况是,使用“C”风格声明(cdecl)导出的函数可能会在被视为stdcall约定的方式调用时导致堆栈不平衡(或更糟),而stdcall约定是WINAPI(Windows系统)调用所识别的方法。


只提供内容翻译:这段内容是关于编程的,带有非常普遍和语言无关的描述,并提供具体例子。 - Bedasso

5
我们最近看到了这个问题(使用C#和C++进行编组)。
我提供给你一段来自MSDN页面的文本:
“当CLR检测到平台调用后堆栈深度与DllImportAttribute属性中指定的调用约定以及托管签名中参数的声明所期望的堆栈深度不匹配时,将激活pInvokeStackImbalance托管调试助手(MDA)。 ”
我知道这是针对特定编译器警告的信息,但该页面提供了有关堆栈不平衡的信息、导致其出现的原因、症状以及如何解决它。正如Daniel所说,这通常是由于托管和非托管的签名不匹配造成的。
希望这可以帮到你。

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