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