前两天遇到一个灵异现象,记录下来。

cchFullHeaderLen += strlen("Request-Line: ") +
    strlen(pSessionData->HttpOpenReq.lpszVerb) +
    strlen(" ") +
    strlen(pSessionData->HttpOpenReq.lpszObjectName) +
    (NULL != pSessionData->HttpOpenReq.lpszVersion) ? (strlen(" ") + strlen(pSessionData->HttpOpenReq.lpszVersion)) : 0 +
    strlen("\r\n");

调试的过程中发现,pSessionData->HttpOpenReq.lpszVersion为NULL,但是依然会执行“(strlen(" “) + strlen(pSessionData->HttpOpenReq.lpszVersion))”。

确认不是编码错误后,反汇编调试:

Boxr!MyFunction+0x2b2
6a515742  xor     edx,edx
6a515744  cmp     dword ptr [ecx+23Ch],0
6a51574b  setne   dl
6a51574e  add     esi,edx
6a515750  je      Boxr!MyFunction+0x2ed (6a51577d)
6a515752  push    offset Boxr!std::_Arithmetic_traits::_Rank+0xc88 (6a5fc0f8)
6a515757  call    Boxr!strlen (6a5b5bd0)
6a51575c  add     esp,4

其中ecx+23Ch就是pSessionData->HttpOpenReq.lpszVersion,查看如下:

0:005> dd ecx+23c
0a27b18c  00000000 

确认pSessionData->HttpOpenReq.lpszVersion确实为NULL。
理论上6a515750处的跳转会执行的,但是没有。单步跟踪:

0:005> p
eax=00000014 ebx=00cc000c ecx=0a27af50 edx=00000000 esi=00000027 edi=0485d5ec
eip=6a515744 esp=0485d518 ebp=0485d5f8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
Boxr!MyFunction+0x2b4:
6a515744  cmp     dword ptr [ecx+23Ch],0 ds:0023:0a27b18c=00000000

0:005> p
eax=00000014 ebx=00cc000c ecx=0a27af50 edx=00000000 esi=00000027 edi=0485d5ec
eip=6a51574b esp=0485d518 ebp=0485d5f8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
Boxr!MyFunction+0x2bb:
6a51574b  setne   dl

0:005> r zf
zf=1

0:005> p
eax=00000014 ebx=00cc000c ecx=0a27af50 edx=00000000 esi=00000027 edi=0485d5ec
eip=6a51574e esp=0485d518 ebp=0485d5f8 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
Boxr!MyFunction+0x2be:
6a51574e  add     esi,edx

0:005> r zf
zf=1

0:005> p
eax=00000014 ebx=00cc000c ecx=0a27af50 edx=00000000 esi=00000027 edi=0485d5ec
eip=6a515750 esp=0485d518 ebp=0485d5f8 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
Boxr!MyFunction+0x2c0:
6a515750  je      Boxr!MyFunction+0x2ed (6a51577d) [br=0]

0:005> r zf
zf=0

可以看出,原本是准备要跳转的,但是

6a51574e  add     esi,edx

这条指令改变了zf寄存器,于是没有跳转。

那这条指令是干什么的呢?怎么会有这么一条指令?
最开始怀疑是编译器优化出问题了。
于是准备以发现编译器优化错误为主体写一篇BLOG。

但是在整理本文的过程中,仔细分析了一遍汇编代码,发现,丫是个低级错误 - 运算符优先级错误……
实际上,C代码真正的执行逻辑是这样的:

cchFullHeaderLen += (strlen("Request-Line: ") + strlen(pSessionData->HttpOpenReq.lpszVerb) + strlen(" ") + strlen(pSessionData->HttpOpenReq.lpszObjectName) + (NULL != pSessionData->HttpOpenReq.lpszVersion) ) 
   ? (strlen(" ") + strlen(pSessionData->HttpOpenReq.lpszVersion)) : ( 0 + strlen("\r\n") );

我的编码风格PPT又多了一条素材……