开启代码优化分析dump

背景

前面都是讲解程序未开启优化时的问题定位。当程序未开启优化时,通过‘local’,‘watch','kv' 的参数信息都是正确的,所以很容易可以通过变量的内容确定问题的原因。

但是如果开启了程序优化功能,那么编译器会优化代码的结构,windbg还是按照原来的方法来解析变量,那么大多情况会出现不正确的,比如最重要的this指针,未优化时都是固定在ecx寄存器中,但是开启了优化后就需要自己来查找对应的this地址。

dump信息

下载链接:链接:https://pan.baidu.com/s/1nQOksK2QLUZsQsl7PhgDCw
提取码:4c1o

c/c++的调用约定

C 语言: __cdecl、__stdcall、__fastcall、naked、__pascal。

C++ 语言: __cdecl、__stdcall、__fastcall、naked、__pascal、__thiscall,比 C 语言多出一种 __thiscall 调用方式。

thiscall 调用方式是唯一一种不能显示指定的修饰符。它是C++类成员函数缺省的调用方式。由于成员函数调用还有一个this指针,因此必须用这种特殊的调用方式。

thiscall调用方式意味着:

(1)参数从右向左压入栈。

(2)如果参数个数确定,this指针通过ecx传递给被调用者;如果参数个数不确定,this指针在所有参数压入栈后被压入栈。参数个数不定的,由调用者清理堆栈,否则由函数自己清理堆栈。

可以看到,对于参数个数固定的情况,它类似于stdcall,不定时则类似于cdecl。

分析dump

下载指定的dump,并使用windbg打开,加载好符号文件。
输入命令:".ecxr" ,显示异常上下文:

0:043> .ecxr
eax=0000ffff ebx=00435a18 ecx=04921dc4 edx=060de888 esi=0d7ed468 edi=00000001
eip=00b9d4e7 esp=070efde8 ebp=070efdf4 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
xzmoSvr!CCommonBaseServer::DealApplyBaseWelfare+0x37:
00b9d4e7 ff30            push    dword ptr [eax]      ds:002b:0000ffff=????????
0:043> kv
  *** Stack trace for last set context - .thread/.cxr resets it
ChildEBP RetAddr  Args to Child              
070efdf4 00bf54dc 00435f8c 070efe74 0c8bc458 xzmoSvr!CCommonBaseServer::DealApplyBaseWelfare+0x37 (FPO: [Non-Fpo]) (CONV: thiscall) [d:\jenkins\workspace\publish_xzmosvr\gamesvr\commonbase\commonbaseserver.cpp @ 218]
070efe88 733dc01d 00000000 76fc49d0 00000000 xzmoSvr!CMainServer::SoapThreadProc+0x29c (FPO: [Non-Fpo]) (CONV: thiscall) [d:\jenkins\workspace\publish_gametplserver2.0\tcgame2.0\trunk\tcgsvr.cpp @ 9565]
070efec0 733dc001 00000000 070efed8 75ad338a msvcr120!_callthreadstartex+0x1b (FPO: [Non-Fpo]) (CONV: cdecl) [f:\dd\vctools\crt\crtw32\startup\threadex.c @ 376]
070efecc 75ad338a 04981c78 070eff18 77b89f72 msvcr120!_threadstartex+0x7c (FPO: [Non-Fpo]) (CONV: stdcall) [f:\dd\vctools\crt\crtw32\startup\threadex.c @ 354]
070efed8 77b89f72 04981c78 75257f9b 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
070eff18 77b89f45 733dbfb4 04981c78 ffffffff ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
070eff30 00000000 733dbfb4 04981c78 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

大致可以猜测是访问非法指针导致的异常。
然后查看代码:

BOOL CCommonBaseServer::DealApplyBaseWelfareEx(LPSOAP_SERVICE pSoapService, IXYSoapClientPtr& pSoapClient, LPCONTEXT_HEAD lpContext, LPREQUEST lpRequest)
{
    BOOL bResult = __super::DealApplyBaseWelfare(pSoapService, pSoapClient, lpContext, lpRequest);
    LPAPPLY_BASEWELFARE_EX lpApplyWelfare = (LPAPPLY_BASEWELFARE_EX)lpRequest->pDataPtr;

    if (bResult && lpApplyWelfare && 0 <= lpApplyWelfare->nSoapReturn)
    {
        if (m_pDataStats)
        {
            m_pDataStats->datastats_onapplywelfare(lpApplyWelfare->nRoomID, lpApplyWelfare->nUserID); ---------> 这行出现问题
        }
    }

    return bResult;
}

并查看异常期间的参数信息:


image

刚开始主程序分析就以为是m_pDataStats = NULL 导致崩溃,原因可能是多线程导致,接着就开始review代码。 但是reivew之后发现m_pDataStats是不能为NULL的(除非进程关闭),然后又是一阵思考、联想、分析........ 无果。
接着猜测是否是踩内存导致(这个review代码难度就有点大了).........

但实际这个dump发生异常的原因不是因为m_pDataStats = NULL导致,而是某个指针的值=0x0000ffff导致,这个在dump中有明确说明:

xzmoSvr!CCommonBaseServer::DealApplyBaseWelfare+0x37:
00b9d4e7 ff30            push    dword ptr [eax]      ds:002b:0000ffff=????????

ds:002b::0000ffff 在访问0000ffff地址时发生异常!!!!!!

但为何看this指针中的m_pDataStats 明明是 NULL啊? 这就是代码开启优化的原因导致this指针不正确。

如何找到正确的this指针地址呢?通过汇编代码,看优化后的入参方式.使用命令“alt+7”可以打开汇编代码:
函数原型:

BOOL CCommonBaseServer::DealApplyBaseWelfareEx(LPSOAP_SERVICE pSoapService, IXYSoapClientPtr& pSoapClient, LPCONTEXT_HEAD lpContext, LPREQUEST lpRequest)

汇编代码:

xzmoSvr!CCommonBaseServer::DealApplyBaseWelfare:
00b9d4b0 55              push    ebp
00b9d4b1 8bec            mov     ebp,esp
00b9d4b3 53              push    ebx
00b9d4b4 56              push    esi
00b9d4b5 8b7514          mov     esi,dword ptr [ebp+14h]
00b9d4b8 8bd9            mov     ebx,ecx
00b9d4ba 57              push    edi
00b9d4bb 56              push    esi
00b9d4bc ff7510          push    dword ptr [ebp+10h]
00b9d4bf ff750c          push    dword ptr [ebp+0Ch]
00b9d4c2 ff7508          push    dword ptr [ebp+8]

可以看到ecx的地址被移到了ebx中,通过之前异常的寄存器信息可以看到ebx的值

0:043> .ecxr
eax=0000ffff ebx=00435a18 ecx=04921dc4 edx=060de888 esi=0d7ed468 edi=00000001
eip=00b9d4e7 esp=070efde8 ebp=070efdf4 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
xzmoSvr!CCommonBaseServer::DealApplyBaseWelfare+0x37:
00b9d4e7 ff30            push    dword ptr [eax]      ds:002b:0000ffff=????????

ebx=00435a18, 使用'watch'查看内容:

image

可以确定m_pDataStats 不仅指针有效,而且里面的内容也是正确的。所以异常并不是m_pDataStats异常导致。

那么问题就是lpApplyWelfare 这个指针导致。 这时候查看入参lpRequest 内容

image

pDataPtr=0x0000ffff和dump提示的异常指针内容相符,所以可以确定是这个指针导致的。

所以重新对lpRequest进行代码review,发现问题的本质原因:
__super::DealApplyBaseWelfare(pSoapService, pSoapClient, lpContext, lpRequest);
在执行过程中,会将lpRequest 指针post到B线程中执行,而B线程是会释放lpRequest指针的。

所以在低概率情况下,会出现多线程崩溃问题。

修改方式:先copy内存到局部变量,再执行super逻辑。

结论

因为开启了代码优化,导致一开始在分析dump时走向了错误的道路,浪费了时间。在碰到开启代码优化时,查找正确的指针就变的有点困难。

所以我不是很建议新上线的服务开启代码优化,反而增加了问题定位的难度。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • Lua 5.1 参考手册 by Roberto Ierusalimschy, Luiz Henrique de F...
    苏黎九歌阅读 13,793评论 0 38
  • 原文地址:C语言函数调用栈(一)C语言函数调用栈(二) 0 引言 程序的执行过程可看作连续的函数调用。当一个函数执...
    小猪啊呜阅读 4,610评论 1 19
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,101评论 1 32
  • 此时,在路上,正好可以写点东西。 公司安排的春游活动,去一个农庄休闲娱乐一天。农庄在公司的东北方向,我坐在右边靠窗...
    零七五阅读 106评论 0 1
  • 20160531 @思贤-004期打虎笔记 【四个收获】 影响力哪里来?让作品发声,对我而言最简单的是发布自己文字...
    思贤在写字阅读 149评论 0 0