VC内存溢出一例 –- 调用约定不一致 (_CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE)
VC (_CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE) 问题记录
VC内存溢出一例 –- 调用约定不一致 (_CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE)
最近在写一个程序,调用了多个DLL,每个DLL代码都支持多线程,Debug的模式下基本调通了,但是在Release模式下,程序因为内存溢出而崩溃,中断在gs_report.c文件的298行位置(_CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE),
由于问题是出自某个DLL模块中,并且是多线程的,并且出现中断的断点无法回溯,很难直接定位到是哪个DLL模块的问题。在将一个一个模块被调用的代码注释后,大概确定了可能出问题的模块,以及可能的函数。由于是Release版本的问题,无法设置断点,只好用输出到Output窗口的方式调试,想进一步确定出现内存溢出的代码段。折腾了很长时间,一直没找到问题根源。
网上搜索了一下,有人是Debug版本有这样的内存溢出错误,Release版本没有,是因为字符串填充的时候超过的申请的长度,和本例的情况不一样。开始我也觉得可能是哪个DLL库字符串操作问题,仔细检查了一些,没有发现问题。
后来在测试一个作为参数传输到某个DLL中函数的字符串的时候,发现此字符串在被调用函数之后内容被改变了,而理论上被调用的函数是不改变此字符串的内容。调试了一下,发现此字符串在被调用的函数最后返回之前还是正常的,函数返回之后就不对了,也就是说函数退出之后的出栈操作有问题,不是按入栈完全相反的动作操作的。产生这个问题的原因有可能是函数的声明不对,也就是在DLL中的声明和在主程序中的声明不一致。检查了一下参数和返回值类型,是完全一致的。那会是哪不一样呢?
DLL中的声明: EXPORTDLL unsigned int MyFunction(char * appname);
主函数中的声明: typedef unsigned int (WINAPI *lpMyFunction)(char* appname);
在VC中,EXPORTDLL定义为: #define EXPORTDLL extern “C” __declspec (dlexport); WINAPI定义为:#define WINAPI __stdcall ;回想起以前解决过的一些问题,在给回调函数传函数指针时,就为是用__stdcall还是__cdcall折腾过,所以估计这里可能是函数约定调用不一致导致的,正好和前面函数参数值被非法改变有关系。WINAPI这个调用约定是没法改的,那就修改DLL的函数。将DLL项目 Configuration Properties --> C/C++ --> Advanced --> Calling Convention设置从默认的__cdecl(/Gd)改为 __stdcall(/Gz),重新编译,重新运行,一切正常。
C++函数调用方式(_stdcall, _pascal, _cdecl...)总结
http://blog.sina.com.cn/s/blog_57065b99010006mo.html
__stdcall:
_stdcall 调用约定相当于16位动态库中经常使用的PASCAL调用约定。在32位的VC++5.0中PASCAL调用约定不再被支持(实际上它已被定义为__stdcall。除了__pascal外,__fortran和__syscall也不被支持),取而代之的是__stdcall调用约定。两者实质上是一致的,即函数的参数自右向左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。
_stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上"@"和参数的字节数。
_cdecl:
_cdecl c调用约定, 按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。
_cdecl是C和C++程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用约定。
__fastcall:
__fastcall调用约定是"人"如其名,它的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。
_fastcall方式的函数采用寄存器传递参数,VC将函数编译后会在函数名前面加上"@"前缀,在函数名后加上"@"和参数的字节数。
thiscall:
thiscall仅仅应用于"C++"成员函数。this指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。
naked call:
采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。
naked call不产生这样的代码。naked call不是类型修饰符,故必须和_declspec共同使用。
另附:
关键字 __stdcall、__cdecl和__fastcall可以直接加在要输出的函数前,也可以在编译环境的Setting...\C/C++ \Code Generation项选择。当加在输出函数前的关键字与编译环境中的选择不同时,直接加在输出函数前的关键字有效。它们对应的命令行参数分别为/Gz、/Gd和/Gr。缺省状态为/Gd,即__cdecl。
要完全模仿PASCAL调用约定首先必须使用__stdcall调用约定,至于函数名修饰约定,可以通过其它方法模仿。还有一个值得一提的是WINAPI宏,Windows.h支持该宏,它可以将出函数翻译成适当的调用约定,在WIN32中,它被定义为__stdcall。使用WINAPI宏可以创建自己的APIs。
http://blog.csdn.net/jiangxinyu/article/details/7844414
VC内存溢出一例 –- 调用约定不一致 (_CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_GSFAILURE)的更多相关文章
- VC内存溢出一例 –- 调用约定不一致
这个是网查的跟我在做图像分割realse相反的情况: 最近在写一个程序,调用了多个DLL,每个DLL代码都支持多线程,Debug的模式下基本调通了,但是在Release模式下,程序因为内存溢出而崩溃, ...
- JSP页面导致tomcat内存溢出一例
今天发现一个奇怪的问题,一个tomcat应用,里面只有一个单纯的jsp页面,而且这个jsp页面没有任何java代码——想用这个jsp页面配合tomcat完成一个性能验证.但是用jmeter压测了几分钟 ...
- Visual Studio (VC) Win32 程序由于数据大,内存溢出怎么办?
Visual Studio (VC) 内编写的Win32 程序由于数据大,内存溢出,即使转移到64位系统也不行.在国外网站上找到了答案. 原来,只需在project->property中的Lin ...
- Hibernate内存溢出分析一例
公司业务系统在进行压力测试时,压测24小时后系统发生内存溢出.经过分析读dump文件,发现org.hibernate.stat.StatisticsImpl类的hashmap类型的变量存储了大量数据( ...
- X86调用约定 calling convention
http://zh.wikipedia.org/wiki/X86%E8%B0%83%E7%94%A8%E7%BA%A6%E5%AE%9A 这里描述了在x86芯片架构上的调用约定(calling con ...
- CPP-基础:有关调用约定
在C语言中,假设咱们有这样的一个函数:int function(int a,int b) 调历时只有用result = function(1,2)的方法就能利用这个函数.然而,当高档语言被编译成计算机 ...
- OutOfMemory相关问题(内存溢出异常OOM)
OutOfMemory(内存溢出异常OOM) java.lang.OutOfMemoryError :Thrown when the Java Virtual Machine cannot alloc ...
- C++调用约定和名字约定
C++调用约定和名字约定 转自http://www.cppblog.com/mzty/archive/2007/04/20/22349.html 调用约定:__cdecl __fastcall与 __ ...
- PHP内存溢出解决方案
一.内存溢出解决方案 在做数据统计分析时,经常会遇到大数组,可能会发生内存溢出,这里分享一下我的解决方案.还是用例子来说明这个问题,如下: 假定日志中存放的记录数为500000条,那么解决方案如下: ...
随机推荐
- Extjs Tooltip属性的使用
要想让 tooltip生效必须:Ext.QuickTips.init();
- Linux的环境变量配置
以下都是环境变量相关的配置文件 1)/etc/enviroment 是系统的环境变量. (2)/etc/profile: 是所有用户的环境变量.当用户第一次登录时,该文件被执行. 并从/etc/pro ...
- md5sum.c, md5.c, md5.h
md5sum.c #include <stdio.h> #include <stdlib.h> #include "md5.h" #pragma warni ...
- C语言的本质(35)——共享库
库用于将相似函数打包在一个单元中.然后这些单元就可为其他开发人员所共享,并因此有了模块化编程这种说法- 即,从模块中构建程序.Linux支持两种类型的库,每一种库都有各自的优缺点.静态库包含在编译时静 ...
- Struts2(五)——核心拦截器
Struts框架一共为我们提供了35个拦截器,其中默认的拦截器有18个,框架访问action的异常处理,配置信息处理,转发重定向选择,上传等等等等,都是这18个拦截器中设置的,起着非比寻常的作用.而这 ...
- iOS https认证 && SSL/TLS证书申请
1.下面列出截止2016年底市面上常见的免费CA证书: 腾讯云SSL证书管理(赛门铁克TrustAsia DV SSL证书)阿里云云盾证书服务(赛门铁克DV SSL证书)百度云SSL证书服务Let's ...
- Ubuntu+Eclipse+ADT+Genymotion+VirtualBox开发环境搭建
1.Eclispe安装就不说了 2.以下说说怎样安装ADT插件.有两种途径: (1)在线安装: 地址:https://dl-ssl.google.com/android/eclipse/(只是近期天朝 ...
- ZOJ Monthly, June 2014 月赛BCDEFGH题题解
比赛链接:点击打开链接 上来先搞了f.c,,然后发现状态不正确,一下午都是脑洞大开,, 无脑wa,无脑ce...一样的错犯2次.. 硬着头皮搞了几发,最后20分钟码了一下G,不知道为什么把1直接当成不 ...
- 关于JavaScript 原型的理解
原型的含义是指:如果构造器有个原型对象A,则由该构造器创建的实例(Object Instance)都必然复制于A.““在JavaScript中,对象实例(Object Instance)并没有原型,而 ...
- WPF学习记录1:ListView的一个模板
在网上找的一个模板,放在这里,作为笔记,收集 <ListView Grid.Column=" Name="ListmuLu" > <ListView.I ...