歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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++對象模型》(下載見 http://www.linuxidc.com/Linux/2012-03/56159.htm)書中有講解: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!

更多Android相關信息見Android 專題頁面 http://www.linuxidc.com/topicnews.aspx?tid=11

Copyright © Linux教程網 All Rights Reserved