【厚积薄发系列】C++项目总结12—函数调用约定导致的崩溃问题分析

问题背景:

当时所在的项目集成准备发版的前几天,突然测试发现了一个崩溃问题。接到这个bug后,发现以前的版本是没有,可以确定这问题肯定是由于这几天开发提交的代码引起的。经过这几天版本二分法确定了首次出现这崩溃问题的版本,再经过分析svn的log,最终确定是由于有个回调函数被某开发加了一个__cdecl函数调用约定修饰导致的。

问题原因:

加了函数调用约定乍一看感觉没啥问题,后来经过深入学习函数调用约定有很大的学问。当时接口函数要求回调函数是__stdcall调用方式,后来回调函数被开发加了__cdecl来修饰,导致执行该语句的时候崩溃,下面来说说是啥原因导致的。

首先说说__stdcall和__cdecl有啥区别:

1、__stdcall是win32 api默认采用的调用方式,参数采用从右到左的压栈方式,由被调用者(自己)清理栈。

2、__cdecl是C语言的调用方式,参数也是采用从右到左的压栈方式,有调用者来清理。

为什么需要__cdecl,主要是因为有些函数的参数是不定长参数,被调用者自己都事先无法知道参数的长度,只有调用者才知道,所以函数调用完后只能由调用者来清理。调用方式不一样导致的崩溃,主要是由于接口要求回调函数是__stdcall(被调用者自己清理),而实际传入的函数是__cdecl调用方式,接口调用传入的回调函数执行完后,接口以为回调函数自己清理了栈,而实际回调函数由于是被__cdecl修饰了,所以回调函数自己没有清理,由于栈是先进后出,此时由于没清理栈导致栈指针还指向回调函数的某个栈位置,而此时回调函数已经执行完了,于是程序继续在往下执行其他代码就会报错。

猜你喜欢

转载自blog.csdn.net/lujiang0120/article/details/80643144
今日推荐