为什么 .NET 程序能够在损坏的堆栈中幸存下来? (当使用错误的调用约定时)

2023-11-22

在VS2010中,托管调试助手会给你一个pInvokeStackImbalance异常(pInvokeStackImbalance MDA) 如果您使用错误的调用约定调用函数,通常是因为您在调用 C 库时没有指定 CallingConvention = Cdecl。例如。你写了

[DllImport("some_c_lib.dll")]
static extern void my_c_function(int arg1, int arg2);

代替

[DllImport("some_c_lib.dll", CallingConvention=CallingConvention.Cdecl)]
static extern void my_c_function(int arg1, int arg2);

因此得到了 StdCall 调用约定而不是 Cdelc。

如果您回答这个问题,您已经知道其中的区别,但对于该线程的其他访问者来说:StdCall 意味着被调用者从堆栈中清除参数,而 Cdecl 意味着调用者清除堆栈。

因此,如果您的 C 代码中的调用约定错误,您的堆栈不会被清理,并且您的程序会崩溃。

然而,.NET 程序似乎不会崩溃,即使它们使用 StdCall 来执行 Cdecl 函数。VS2008 默认情况下未启用堆栈不平衡检查,因此某些 VS2008 项目使用了作者不知道的错误调用约定。我刚刚尝试过GnuMpDotNet即使缺少 Cdelc 声明,示例也运行得很好。这同样适用于X-MPIR.

它们都在调试模式下抛出 pInvokeStackImbalance MDA 异常,但在发布模式下不会崩溃。为什么是这样? .NET VM 是否包装对本机代码的所有调用并随后恢复堆栈本身?如果是这样,为什么还要费心 CallingConvention 属性呢?


这是因为方法退出时堆栈指针的恢复方式。方法的标准序言,针对 x86 抖动显示;

00000000  push        ebp                 ; save old base pointer
00000001  mov         ebp,esp             ; setup base pointer to point to activation frame
00000003  sub         esp,34h             ; reserve space for local variables

以及它的结束方式:

0000014a  mov         esp,ebp             ; restore stack pointer
0000014c  pop         ebp                 ; restore base pointer
0000014d  ret 

使 esp 值不平衡在这里不是问题,它可以从 ebp 寄存器值恢复。然而,当抖动优化器可以将局部变量存储在 CPU 寄存器中时,它经常会优化这一点。当 RET 指令从堆栈中检索到错误的返回地址时,您将崩溃并烧毁。无论如何,希望当它偶然落在一大块机器代码上时真的很糟糕。

当您在没有调试器的情况下运行发布版本时,很可能会发生这种情况,如果没有 MDA 来帮助您,则很难排除故障。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 .NET 程序能够在损坏的堆栈中幸存下来? (当使用错误的调用约定时) 的相关文章

  • 如何制作.Net或JVM语言?

    我看到了 NET 和 JVM 的所有这些新语言 一个人如何开始制作一个 我找不到关于 JVM 或 MSIL 规范的任何好的文档 Edit 我已经知道如何解析 我更感兴趣的是如何有这么多人基于这些平台创建新语言 你有点幸运 为 NET 开发的
  • Azure 应用服务 - 自定义身份验证 - 不允许 HTTP 动词

    我按照本教程在我的 Xamarin Forms 应用程序中启用身份验证 https adrianhall github io develop mobile apps with csharp and azure chapter2 custom
  • 将包含驱动器号的相对路径转换为 ​​.NET 文件函数的绝对路径

    如何转换驱动器相对路径 例如D test xml进入绝对路径 例如函数XDocument Load 会接受 D盘可能有D data作为其当前工作目录 例如 soD test xml意思是D data test xml 我已经尝试过这样的混合
  • 窗口服务中的全局处理异常

    我有一个 Windows 服务作为服务器运行 但是 服务器有时会因未处理的错误而立即停止 请帮助我如何处理全局异常 谢谢 在我看来 你似乎试图以错误的方式解决问题 当您的程序 或服务 由于未处理的错误而崩溃时 解决方案不是弄清楚在哪里以及如
  • 你如何组织你的命名空间?

    所以我有逻辑实体 人 国家等 GUI 元素 控件 数据和导航控制器 管理器 然后是四叉树和计时器之类的东西 我总是努力将这些东西干净地分离到逻辑名称空间中 我通常有这样的事情 利维坦 GUI 控件 Leviathan GUI 视图 利维坦实
  • 并行何时会提高性能

    我试图理解何时使用parallel会提高性能 我用一个简单的代码对其进行了测试 该代码运行了超过 100 000 个项目List
  • 选择 Enum 类型的默认值而无需更改值

    在 C 中 是否可以用属性修饰 Enum 类型或执行其他操作来指定默认值 而不更改值 无论出于何种原因 所需的数字可能是一成不变的 并且仍然可以控制默认值会很方便 enum Orientation None 1 North 0 East 1
  • 通过 Active Directory 搜索进行有效分页

    在 NET 中使用 Active Directory 搜索进行分页的有效方法是什么 在 AD 中进行搜索的方法有很多 但到目前为止我找不到如何有效地进行搜索 我希望能够表明Skip and Take参数并能够检索结果中与我的搜索条件匹配的记
  • 异步回调到BackgroundWorker

    我想使用 NET FTP 库 http netftp codeplex com http netftp codeplex com 该库提供 BeginOpenRead string AsyncCallback object 使用异步编程模型
  • 使用 C# 在 Windows 窗体应用程序中正确使用 OnClick 与 MouseClick 事件

    我目前正在开发一个自定义控件 并意识到我的代码正在运行两次 这实际上并不是一个大问题 它只是 Focus 方法调用 不过 我想了解一下 从阅读点击 MSDN说明单击事件 http msdn microsoft com en us libra
  • 创建动态对象

    如何动态创建对象 string columnNames EmpName EmpID PhoneNo List
  • Microsoft.Web.Administration 内存泄漏

    拥有一个 Windows 服务 除其他外 还可以监视 IIS 应用程序池 如果任何池已配置应用程序但未运行 则该池 池 将启动 这已经运行良好一段时间了 最近发现该服务存在内存泄漏 查看内存转储 罪魁祸首是用于检查应用程序池的 Micros
  • 如何从 nuget 包中排除子目录和内容

    所以我有一个网站正在尝试打包用于 Octopus Deploy 我有以下文件夹结构 Web Views WantThis Dontwantthis WantThis1 WantThis2 lots more Scripts 我试图排除 Do
  • 如何将 Activator.CreateInstance 与字符串一起使用?

    在我的反射代码中 我的通用代码部分遇到了问题 特别是当我使用字符串时 var oVal object Test var oType oVal GetType var sz Activator CreateInstance oType oVa
  • 无法从程序集“mscorlib”加载类型“System.Runtime.CompilerServices.ExtensionAttribute”

    第一次启动我的网站时 我收到此错误 Could not load type System Runtime CompilerServices ExtensionAttribute from assembly mscorlib Version
  • 如何使用反应式扩展同时读取交错文件

    我是反应式扩展的新手 我想使用它 在 c 中 来读取包含多个交错流的文件 基本上文件的格式是ABCDABCDABCD 我更喜欢按顺序读取文件并分离流 即AAA BBB 等 并并行处理每个流 为每个流使用单独的线程 必须有某种形式的缓冲来确保
  • MVVM ViewModel 很多属性

    我是 MVVM 新手 正在开发一个应用程序 我有一个包含很多属性的表单视图 大约 50 个 我不能将它们分离到用户控件中 因为这会破坏 mvvm 原则 我无法将它们分成模型 因为它们包含逻辑 属性更改 错误更改这些都不是 poco 类 并且
  • 将浮点型转换为双精度型

    我正在尝试转换Single to Double同时保持原来的价值 我找到了以下方法 Single f 5 2F Double d1 f 5 19999980926514 Double d2 Double Parse f ToString 5
  • C#生成的csv文件通过电子邮件发送嵌入到Lotus Note中电子邮件的底部

    我遇到了一个奇怪的问题 即使用 NET SmtpClient 通过电子邮件发送的 CSV 附件出现在电子邮件底部 而不是 Lotus Note 中的附件 我只是不知道如何解决这个问题 而且我无法访问客户端计算机 这使得调试非常困难 我可以采
  • 检测笔记本电脑盖子的关闭和打开

    是否可以检测笔记本电脑的盖子何时打开或关闭 从我读到的内容来看 这是不可能的 但 SO 之前已经帮助我完成了不可能的任务 我发现唯一可能朝着正确方向的事情是关于报告电源按钮所需的 IOCTL 的 MSDN 博客文章 https learn

随机推荐