zoukankan      html  css  js  c++  java
  • [原]PInvoke导致栈破坏

    项目中遇到一个诡异的问题,程序在升级到.net4.6.1后会崩溃,提示访问只读内存区。大概现象如下:

    1. debug版不崩溃,release版稳定崩溃。
    2. 只有x64位的程序崩溃,32位及anycpu编译出来的程序运行不会崩溃。
    3. 出问题的代码范围很小

    以上信息,各位有什么想法呢?

    由于release版可以稳定重现,而且范围不大,故通过二分排除法很快定位到了导致问题的代码。

    最后发现并不是由于升级.net版本导致的,而是程序本身的问题: x64下MemoryStatus结构体中的成员有些不是4字节大小,而是8字节大小了。而我们的代码依然按4字节定义的。

    我写了一个模拟程序来模拟出问题的代码。 参见后面的代码。

    总结: 如果不是那么稳定的崩溃,恐怕解决这个问题还会花些时间的吧,how lucky I am!!!

    BTW: 启用托管调试助手(MDA)有时候会对调试问题有极大的帮助,虽然我这次调试没有借助MDA,但我第一个想到的就是MDA

    完整的测试代码如下(如想重现问题,请编译x64版本)

    1. using System.Runtime.InteropServices; 
    2. namespace ConsoleApplication1 
    3. class Program 
    4. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance""CA1815:OverrideEqualsAndOperatorEqualsOnValueTypes"),StructLayout(LayoutKind.Sequential)] 
    5. public struct MemoryStatus 
    6. /// --- 
    7. [MarshalAs(UnmanagedType.U4)] 
    8. public uint dwLength; 
    9. /// --- 
    10. [MarshalAs(UnmanagedType.U4)] 
    11. public uint dwMemoryLoad; 
    12. /// --- 
    13. [MarshalAs(UnmanagedType.U4)] 
    14. public uint dwTotalPhys; 
    15. /// --- 
    16. [MarshalAs(UnmanagedType.U4)] 
    17. public uint dwAvailPhys; 
    18. /// --- 
    19. [MarshalAs(UnmanagedType.U4)] 
    20. public uint dwTotalPageFile; 
    21. /// --- 
    22. [MarshalAs(UnmanagedType.U4)] 
    23. public uint dwAvailPageFile; 
    24. /// --- 
    25. [MarshalAs(UnmanagedType.U4)] 
    26. public uint dwTotalVirtual; 
    27. /// --- 
    28. [MarshalAs(UnmanagedType.U4)] 
    29. public uint dwAvailVirtual; 
    30. [DllImport("kernel32.dll")] 
    31. public static extern void GlobalMemoryStatus(ref MemoryStatus memoryStatus)
    32. class CMyClass 
    33. public int n1 = 0
    34. struct CMyStruct 
    35. public CMyClass data; 
    36. static void Main(string[] args) 
    37. CMyStruct myObj = new CMyStruct(); myObj.data = new CMyClass(); 
    38. MemoryStatus memoryStatus = new MemoryStatus(); 
    39. // this line will corrupt the stack if we run in x64, because memoryStatus is defined on the stack 
    40. GlobalMemoryStatus(ref memoryStatus); 
    41. // myObj.data is corrupted 
    42. System.Console.WriteLine("{0}", myObj.data); 
  • 相关阅读:
    修改host指定域名指向ip,Windows脚本与Linux脚本
    Linux磁盘分区/格式化/挂载目录
    给普通用户赋予sudo权限后报错,提示/etc/sudoers文件权限拒绝
    SUSE12-SP2安装教程(虚拟机)
    ios键盘弹起 body的高度拉长,页面底部空白问题。ios软键盘将页面抵到上面后,关闭软键盘页面不回弹的问题。
    Visual Studio动态生成版权信息
    微信发支付宝红包(花呗)
    纯CSS打造淘宝导航菜单栏
    用bat批处理程序通过DOS命令行删除所有的空文件夹
    从0开始用U盘制作启动盘装Windows10系统(联想R720笔记本)并永久激活方法
  • 原文地址:https://www.cnblogs.com/bianchengnan/p/9458130.html
Copyright © 2011-2022 走看看