Android NDK空指针导致CRASH的问题


1. APP启动时隔三差五地随机性地CRASH,捕捉到的日志:

----------------
2013-06-03 10:26:52
----------------
#00  pc 0002e9b4  /data/data/com.XXXX.map/lib/libmapengine.so
#01  lr 8082dc97  /data/data/com.XXXX.map/lib/libmapengine.so

2. CRASH在汇编码2e9b4位置,通过objdump工具生成so包对应的汇编文件,查找定位crash位置:

0002e9b4 <_ZN12TextureCache15ensureCacheSizeEi>:
  2e9b4: 6803       ldr r3, [r0, #0]
  2e9b6: 428b       cmp r3, r1
  2e9b8: da00       bge.n 2e9bc <_ZN12TextureCache15ensureCacheSizeEi+0x8>
  2e9ba: 6001       str r1, [r0, #0]
  2e9bc: 4770       bx lr

第一行 2e9b4位置。
 
3. 对应ensureCacheSize函数源码:

void TextureCache::ensureCacheSize(int size){
 if(limit < size){
  limit = size;
 }
}

看到函数源码以后,一时有点丈二摸不着头脑了,函数内部就一个if判断,何来的crash?2e9b4位置而且是一个ldr寻址操作,根据汇编源码得知是取limit成员变量值。

4. 跟一位经验丰富地同事讨论,他说这是典型地空指针导致的CRASH问题,原因如下:

这个函数如此调用:tileTexCache->ensureCacheSize(blkNum + 1); 当tileTexCache指针为空时,并不是在函数调用这行CRASH,而是在成员函数内部。

原理《C++对象模型》(下载见 )书中有讲解:C++中类的成员函数和成员变量不太一样,成员变量定义在对象内部,跟对象一个级别,与this指针有关;而成员函数则定义在类内部,跟类一个级别,与this指针无关。换个角度理解这句话,即使对象指针为空,通过空对象指针访问成员函数也是可以,只有当成员函数内部需要访问成员变量时才会CRASH,因为成员变量定义在对象内部。这个道理我懂,但怎么也跟空指针联系起来!

5. 测试DEMO

class EmptyPointerApp
{
public:
 void safeFunc()
 {
  cout << "World Peace" << endl;
 }

 void badFunc()
 {
  cout << "Will Crash" << endl;
  mData = 1;
 }

private:
 int mData;
};

int main(int argc, char** argv)
{
 EmptyPointerApp* pSample = NULL;
 pSample->safeFunc();
 pSample->badFunc();
}

vs2008,CRASH在mData=1语句,此时输出:

World Peace
Will Crash

调试中断后打开反汇编窗口:

 


第一个mov将this指针内容放到eax寄存器中,dword ptr指明了指令访问内存的单元是一个dword,即四个字节长度。

第二个mov通过eax访问mData成员时CRASH!

相关内容