dlfree jni 程序崩潰


 

http://nick.luckygarden.org/?p=454

 

 

 

 

 

 

 

 

這幾天一直在忙着調試 crash 的問題。周末兩天都在加班。 周日更是從早上8:00 到晚上 12:50 一直沒離開過辦公室. 加上這個項目對我們整個開發組以及 EM 都很重要,不容有失,這不禁讓我想起了微軟 NT 開發組開發 NT 的情形,所以有了這個標題.

這次是在 android 上,但不是 arm,而是 x86 atom。我們的程序是從 windows 上移植到 android 上的, 一個 C++ 寫的底層庫作為 service,UI 是 java 寫的。 因為是在 android 2.2 上,java 也是唯一的寫 UI 的選擇。 java 通過 aidl/jni 與底層 service/c++ 代碼交互。這樣的架構讓調試很悲劇。

之前一直抱怨 xcode 調試多么不給力,而現在在 android 上的調試已經原始到通過 log 分析程序的執行。arm 上的調試還能用 gdb 勉強為之,而 x86 下那簡直就是坑爹。好不容易把符號神馬的搞定,gdb 遠程調試到設備上,卻發現程序不 crash 了。

logcat 和 tombstone 顯示的 crash 調用棧是這樣的:

06370 INF/DEBUG   ( 1670): signal 11 (SIGSEGV), fault addr deadbaad 06371 INF/DEBUG   ( 1670):  eax 00000000  ebx 801614f4  ecx 00000004  edx 00001000 06372 INF/DEBUG   ( 1670):  esi b3afa000  edi bfca7b18 06373 INF/DEBUG   ( 1670):  xcs 00000073  xds 0000007b  xes 0000007b  xfs 00000000 xss 0000007b 06374 INF/DEBUG   ( 1670):  eip 8011c768  ebp bfca7b28  esp bfca7af0  flags 00010286 06375 INF/DEBUG   ( 1670): #00 06376 INF/DEBUG   ( 1670):     eip: 8011c768  /system/lib/libc.so (abort) 06377 INF/DEBUG   ( 1670): #01 06378 INF/DEBUG   ( 1670):     eip: 8010ed4b  /system/lib/libc.so (dlfree) 06379 INF/DEBUG   ( 1670): #02 06380 INF/DEBUG   ( 1670):     eip: 80111503  /system/lib/libc.so (free) 06381 INF/DEBUG   ( 1670): #03 06382 INF/DEBUG   ( 1670):     eip: 80200a1d  /system/lib/libstdc++.so (_ZdlPv) 06383 INF/DEBUG   ( 1670): #04 06384 INF/DEBUG   ( 1670):     eip: 86138519  /data/data/cip.impservice/lib/libimpjni2.so (_ZSt12__stl_deletePv) 06385 INF/DEBUG   ( 1670): #05 06386 INF/DEBUG   ( 1670):     eip: 8613853d  /data/data/cip.impservice/lib/libimpjni2.so (_ZNSt11__new_alloc10deallocateEPvj) 06387 INF/DEBUG   ( 1670): #06 06388 INF/DEBUG   ( 1670):     eip: 8613856e  /data/data/cip.impservice/lib/libimpjni2.so (_ZNSaIcE10deallocateEPcj) 06389 INF/DEBUG   ( 1670): #07 06390 INF/DEBUG   ( 1670):     eip: 861385b1  /data/data/cip.impservice/lib/libimpjni2.so (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06391 INF/DEBUG   ( 1670): stack: 06392 INF/DEBUG   ( 1670): #00 06393 INF/DEBUG   ( 1670):     bfca7af0  00000002   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06394 INF/DEBUG   ( 1670):     bfca7af4  bfca7b18  [stack] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06395 INF/DEBUG   ( 1670):     bfca7af8  00000000   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06396 INF/DEBUG   ( 1670):     bfca7afc  00000000   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06397 INF/DEBUG   ( 1670):     bfca7b00  00000000   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06398 INF/DEBUG   ( 1670):     bfca7b04  00000000   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06399 INF/DEBUG   ( 1670):     bfca7b08  84a60900  /system/lib/libstlport.so (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06400 INF/DEBUG   ( 1670):     bfca7b0c  00000010   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06401 INF/DEBUG   ( 1670):     bfca7b10  0a1f8300  [heap] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06402 INF/DEBUG   ( 1670):     bfca7b14  00000001   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06403 INF/DEBUG   ( 1670):     bfca7b18  fffffbdf   (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06404 INF/DEBUG   ( 1670):     bfca7b1c  801614f4  /system/lib/libc.so (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06405 INF/DEBUG   ( 1670):     bfca7b20  0a1f6c98  [heap] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06406 INF/DEBUG   ( 1670):     bfca7b24  bfca8410  [stack] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06407 INF/DEBUG   ( 1670):     bfca7b28  bfca7b68  [stack] (_ZNSt4priv17_STLP_alloc_proxyIPccSaIcEE10deallocateES1_j) 06408 INF/DEBUG   ( 1670): #01 06409 INF/DEBUG   ( 1670):     bfca7b2c  8010ed4b  /system/lib/libc.so (dlfree) 06410 INF/DEBUG   ( 1670):     bfca7b30  80163118   (dlfree) 06411 INF/DEBUG   ( 1670):     bfca7b34  00000000   (dlfree) 06412 INF/DEBUG   ( 1670):     bfca7b38  8010f3ab  /system/lib/libc.so (dlmalloc) 06413 INF/DEBUG   ( 1670):     bfca7b3c  801614f4  /system/lib/libc.so (dlmalloc) 06414 INF/DEBUG   ( 1670):     bfca7b40  00000066   (dlmalloc) 06415 INF/DEBUG   ( 1670):     bfca7b44  bfca8410  [stack] (dlmalloc) 06416 INF/DEBUG   ( 1670):     bfca7b48  0a1f6c90  [heap] (dlmalloc) 06417 INF/DEBUG   ( 1670):     bfca7b4c  801114d2  /system/lib/libc.so (malloc) 06418 INF/DEBUG   ( 1670):     bfca7b50  0000002f   (malloc) 06419 INF/DEBUG   ( 1670):     bfca7b54  80201d98  /system/lib/libstdc++.so 06420 INF/DEBUG   ( 1670):     bfca7b58  bfca7b68  [stack] 06421 INF/DEBUG   ( 1670):     bfca7b5c  801614f4  /system/lib/libc.so 06422 INF/DEBUG   ( 1670):     bfca7b60  0a1f6caf  [heap] 06423 INF/DEBUG   ( 1670):     bfca7b64  bfca8410  [stack] 06424 INF/DEBUG   ( 1670):     bfca7b68  bfca7b78  [stack] 06425 INF/DEBUG   ( 1670):     ......  ......

每次都幾乎看不到我們的代碼,好不容易看到一個用戶代碼的地址,通過 addr2line, 也是 STL 里的 _alloc.h 之類。這其實是一個提示,但一開始我們並沒有在意。我們還是堅忍的打着 log,試圖逐一的排查 crash, 好不容易向前推進了一些讓程序跑得更遠一點,再跑一次卻發現又回到了起點, crash 又在前面的代碼中出現鳥,我勒個去~

不穩定的 crash 讓我有些沮喪,同時也讓我產生了懷疑,這到底是不是我們的代碼的問題? 看看每次 crash 的調用棧,都有 STL 牽涉其中,又聯想起我們用的 stlport 不是線程安全的 (編譯時使用了 _NOTHREADS 宏),  是不是應該去掉 _NOTHREADS 編譯試試? 但遇到的新問題是,我們使用的動態鏈接的系統自帶的 STL,雖然可以替換掉系統的,但勢必影響其他的程序。這是不能接受的。 馬上想到我們可以編譯一個靜態庫,連接到我們的程序中。說干就干,拿到 stlport 的代碼,折騰一番,也就編譯好了。這里還有一個小插曲, android 的頭文件說它對 #include_next 支持的並不好,但最終我們還是用了 gcc 的這個 feature 才讓代碼編譯通過。

但測試的結果卻讓人沮喪,我再次確認了的確是鏈接到了自己編譯的靜態版本,悲催的發現這次嘗試可恥的失敗鳥~ 這時已是周一凌晨 0:50 了,而我已經在辦公室呆了 16個小時沒有離開。

周一早上9:40到達公司。一計不成,又生一計,這次我注意到調用棧頂端的 lib 的 free 函數,既然每次都 crash 在這里,那我能不能讓它不調用這個函數。聯想起之前看過的 stlport 文檔 (可 以讓 stlport 使用 new/delete 而不是 malloc/free 來分配/釋放內存, 無獨有偶,目前我們做的這個項目的前身(另一個項目組開發的)編譯的時候就加了 stlport 的這個宏(我們在移植代碼的時候由於匆忙,急於讓代碼通過編譯,沒能加上這個宏),這更堅定了我做這個嘗試的決心。於是給十幾個模塊的 mk 文件都加上了這幾個 stlport 相關的宏(看 stlport 文檔關於分配內存的宏),rebuild all。 哈利露亞~ 幸福來得那么突然, 程序真的跑起來了,不再 crash!

http://www.stlport.com/doc/configure.html),的確有一個宏  _ STLP_USE_NEWALLOC   (
-D_STLP_USE_NEWALLOC)

總結這次調試的經驗教訓:

1. 開始時調試進展緩慢,問題出在編譯/調試環境很不給力。

我們需要把代碼放到另一個 site 的唯一的 build machine 上讓同事幫忙編譯,這個過程讓調試過程變得很漫長。 所以我讓同事給我在 build machine 上單獨弄了一個環境,這樣我就可以隨意的修改/調試代碼了

2. 對問題不敏感,雖然每次都看到 stl/free 出現在調用棧中,直到在錯誤的方向上迷失才意識到我們可能走錯路了

3. 對項目本身不夠了解,我沒能意識到我們其實有一個能用的版本(雖然我們重構了很多),的確應該早些查看別人是怎么做到的。 這里有一個客觀原因是我之前一直不在這個項目。

4. Android 的調試環境太坑爹了。既然符號神馬的都齊活了,在調研棧里卻只顯示地址和莫名其妙的函數名(還是 decorated), 尼瑪就不能把代碼行也加進去啊!有木有!Android 開發小組在忙於追趕/超越蘋果的時候,明顯對開發者照顧不夠。 當然,也有可能是我被微軟給慣壞了.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM