在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Linux程序內存越界定位分析

科技綠洲 ? 來源:Linux開發架構之路 ? 作者:Linux開發架構之路 ? 2023-11-13 11:30 ? 次閱讀

問題描述:最近在工作中遇到這樣一個奇葩問題,程序里需使用一個.so庫,同份源碼用我電腦編譯的庫放到程序使用出現各種異常問題,其他同事編譯出來的沒問題。剛開始以為是編譯方式有問題,思來想去發現并不是。經分析發現是庫源代碼里一全局數組內存地址大面積越界到其他全局數組了。

問題現象:現象為觸發某個業務條件,將導致程序邏輯運行不正常,異常log如下圖,可看出“g_s32MaxFd”變量的值(文件句柄)被置0,正常情況應該是大于0,所以此時導致整個業務運行異常。

圖片

初步分析肯定是其他地方對變量“g_s32MaxFd”有賦值才會導致值為0。那么到底是代碼正常邏輯語句操作還是代碼內存越界引起“g_s32MaxFd”值為0呢?這個倒好定位,只需要搜索下“g_s32MaxFd”變量在代碼哪些地方有使用就知道了,得出結論是代碼內存越界這種情況導致。

一:開始定位內存越界處

【1】定位內存越界處,因程序并沒有因為內存越界而引發segment fault退出,所以準備使用Linux中mprotect()函數來設置指定內存區域的保護屬性為只讀,故意使程序引發segment fault退出從而產生core dumped文件來定位問題點。

分析下面問題前最好先熟悉下mprotect()函數

思路:使用mprotect()函數對被踩變量“g_s32MaxFd”內存地址設為只讀屬性,由于mprotect()函數的局限性(保護屬性區域的起始地址必須為操作系統一個頁大小的整數倍),結合實際情況多樣性,分析情況如下表述:

1、當“g_s32MaxFd”數組起始地址剛好是頁大小整數倍時,此時只需要將數組起始地址設置為mprotect()函數保護屬性為只讀的起始地址即可,但需要注意一點,當被保護地址區域被程序正常數據結構進行訪問時,也會引發segment fault退出(簡而言之就是當數組“g_s32MaxFd”內存地址被設置為只讀后,如果是程序正常使用時也會引發段錯誤退出),這種情況就無法辨別是程序正常使用還是內存越界處使用,會影響分析真正的問題點。

解決方法:可利用GNU編譯器對.bss地址分配特性(具體特性自行查閱其他資料),在“g_s32MaxFd”數組地址處定義一個為頁大小整數倍大小的“g_debug_place”數組,這就相當于新增的“g_debug_place”數組占用之前“g_s32MaxFd”數組的地址。如下圖所示在“Var5”和“g_s32MaxFd”之間定義一個動態數組“g_debug_place”,大小最好是頁大小整數倍(如果小于一個頁大小會導致鎖定的區域越界到“g_s32MaxFd”地址,問題得不到解決),這樣既可以保證新增的“g_debug_place”數組變量只在內存越界的地方才會被訪問而且數組大小也滿足mprotect()函數參數長度的取值要求(頁大小整數倍)。

圖片

2、 當“g_s32MaxFd”數組起始地址不是頁大小整數倍時,要結合上面第1種方法后還需要計算出大于且最靠近“g_debug_place”數組起始地址的頁大小整數倍地址。可套用公式:

設置保護屬性起始地址=被踩內存變量起始地址+(頁大小-(被踩內存變量起始地址%頁大小)) 注意:(被踩內存變量起始地址%頁大小)等于0時不適用以上公式,也就是被踩內存變量起始地址是頁大小整數倍情況下

假設“g_debug_place”數組起始地址為0x7fd8985bf8c0代入公式可得設置保護屬性起始地址為0x7fd8985c0000 ,理論上只需要將地址0x7fd8985c0000設置為mprotect()函數保護屬性為只讀的起始地址即可,但需要注意的是此時的0x7fd8985c0000地址并不是“g_debug_place”數組起始地址,由上面公式可知這個地址是為了滿足mprotect()函數的局限性而計算出來的地址。

解決方法:可通過在.bss段(之所以強調.bss段是因為我實際出現問題的變量就是未初始化的全局數組變量)首個變量地址前增加動態數組來改變內存分配解決。舉個例子,就好比是排隊,本來小明是排第六個,突然在隊伍最前面插一個小紅進來,小明就排在第七了,而小明前面之前那五個人的順序還是不變。而這個第七就是我們程序里要的那個0x7fd8985c0000地址。

下圖藍色區域為新增動態數組(插隊小紅),大小為0x740字節。增加后可使“g_debug_place”數組起始地址為0x7fd8985c0000(小明第七的位置),這時將0x7fd8985c0000地址作為mprotect()函數保護屬性為只讀的起始地址就可以了,接下來就可以復現問題等著程序內存越界產生段錯誤退出吧。

注意:如果增加動態數組后并沒有直觀發現內存越界時,這可能是由于內存越界的字節數太小(可能只踩到一個字節或幾個字節),導致調整過后的內存地址剛好踩到一個未使用的地址,這時需要微調動態數組大小來保證地址間隔及分配順序不變,具體問題具體分析。我是沒有出現這種情況,只是覺得通過這種方法分析可能會存在此風險,如果有小伙伴遇到可以留言探討。

圖片

bss段變量地址結構分布簡要展示如下圖(展示的是測試代碼,非實際工程代碼):

圖片

【2】gdb分析core文件,編譯可執行程序時編譯選項需加-g參數,不要strip優化,否則可能會導致調試信息不是很完整。

檢查core dumped是否打開

/home # ulimit -c
0
/home # ulimit -c unlimited
/home # ulimit -c
unlimited

如果找不到ulimit命令,可以用busybox sh -c 'ulimit -a’指令測試ulimit是否存在,(ulimit是busybox的內置命令,往往我們想使用tab鍵快捷調用ulimit時可能不會彈出)有如下log輸出證明命令存在,后續直接執行ulimit -c unlimited,不要再執行busybox sh -c ‘ulimit -c unlimited’,這樣是打不開core的,我就這么傻的操作過,當時還以為內核沒有打開這個功能。

/home # busybox sh -c 'ulimit -a'
-f: file size (blocks)             unlimited
-t: cpu time (seconds)             unlimited
-d: data seg size (kb)             unlimited
-s: stack size (kb)                8192
-c: core file size (blocks)        unlimited
-m: resident set size (kb)         unlimited
-l: locked memory (kb)             64
-p: processes                      1982
-n: file descriptors               1024
-v: address space (kb)             unlimited
-w: locks                          unlimited
-e: scheduling priority            0
-r: real-time priority             0

分析core文件過程,如下圖所示。當輸出log信息不完整時,需要檢查下源碼和相關庫文件路徑是否設置好,可根據圖片中標注處進行設置。(展示的是測試代碼,非實際工程代碼)

圖片

實際代碼gdb分析log如下

/home/outapp/app # …/…/gdb xxx_capture core
GNU gdb (GDB) 7.6
Copyright ? 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type “show copying”
and “show warranty” for details.
This GDB was configured as “arm-hisiv300-linux”.
For bug reporting instructions, please see:
http://www.gnu.org/software/gdb/bugs/…
Reading symbols from /home/outapp/app/xxx_capture…(no debugging symbols found)…done.
[New LWP 803]
[New LWP 789]
[New LWP 798]
[New LWP 807]
[New LWP 799]
[New LWP 791]
[New LWP 832]
[New LWP 797]
[New LWP 795]
[New LWP 802]
[New LWP 809]
[New LWP 790]
[New LWP 805]
[New LWP 804]
[New LWP 808]
[New LWP 796]
[New LWP 806]
[New LWP 810]
[New LWP 831]
[New LWP 833]
[Thread debugging using libthread_db enabled]
Using host libthread_db library “/lib/libthread_db.so.1”.
Core was generated by `xxx_capture capture 660’.
Program terminated with signal 11, Segmentation fault.
#0 0xb5e63b54 in memset () from /lib/libc.so.0
(gdb) bt
#0 0xb5e63b54 in memset () from /lib/libc.so.0
#1 0xb6e63064 in xxx3520D_Sample_OsdRegShowUpdata (ps8Contenx=0xb1dc2a70 " 000KM/H ", pstRegAttr=0x32f9e9c)
at SdkLogic/xxx3520dSample/xxx3520dOsd.c:436
#2 0xb6e63930 in xxx3520D_Sample_OsdShowGpsSpeed (pstRegAttr=0x32f9e9c, u8Speed=0000’) at SdkLogic/xxx3520dSample/xxx3520dOsd.c:621
#3 0xb6e4dc14 in xxxSdkAl_OsdShowGpsSpeed (pstRegAttr=0x32f9e9c, u8Speed=0000’) at SdkAppInt/xxxAHDSdkAL.c:474
#4 0xb6cb7b50 in OsdServiec::Osd_Reg_Show() () from /hi3520/lib/libxxxxxx_hi3520_AHDOsd.so
#5 0xb6cb726c in xxx_Osd_Display(void*) () from /hi3520/lib/libxxxxxx_hi3520_AHDOsd.so
#6 0xb6fc0f6c in start_thread () from /lib/libpthread.so.0
#7 0xb5e82134 in clone () from /lib/libc.so.0
#8 0xb5e82134 in clone () from /lib/libc.so.0
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)

小結:以上定位內存越界只是一個大體思路,實際情況多樣性,具體問題還需要具體分析,個人認為如果只需要定位程序異常退出的話,用backtrace相關函數來代替gdb分析問題要輕量化很多。上述之所以使用gdb去分析問題是由于使用的交叉編譯是uclibc環境(uclibc環境下backtrace函數是沒實現的),就只能使用sdk提供的gdb工具了

二:為什么我電腦編譯出來的庫就暴露這個問題呢?

通過上面的方法已經定位到是哪行代碼有bug,所以想再分析下我編譯出來的庫為啥就暴露這個問題了呢?分析得知是在生成.so庫時由于鏈接.o的順序不同導致庫里面全局變量數組的地址分布也有所不同。下面分析下log文件里具體不同點,截圖貼上:

qiuhui@ubuntu:/mnt/hgfs/qh/work/app/SVN/?????$ arm-hisiv300-linux-objdump -t ???/lib?????.so > log

【圖一為我電腦編譯的】

圖片

【圖二為同事電腦編譯的】

圖片

由上圖可以觀察到兩個全局數組變量“gs_s8Contenx”與“g_s32MaxFd”它們的地址有前后順序差異,圖一:“gs_s8Contenx地址0xfd9e4”小于“g_s32MaxFd地址0xfed34”,圖二:“gs_s8Contenx地址0xfdfd4”大于“g_s32MaxFd地址0xfdbd4”。正是由于這兩個地址的前后順序才導致我編的庫暴露了問題,因為我編的gs_s8Contenx地址小于g_s32MaxFd,代碼里剛好使用gs_s8Contenx數組時以超過數組元素最大值做賦值操作,從而引發大面積內存越界,導致越界地址直接就踩到g_s32MaxFd變量地址了(踩到很多全局變量了),所以g_s32MaxFd數組的值被莫名修改,從而產生各種異常。當然同事編譯的同樣也會使gs_s8Contenx越界,但由于gs_s8Contenx地址大于g_s32MaxFd,所以gs_s8Contenx剛好踩到的是一段不常用的地址,導致問題沒有及時暴露出來。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • Linux
    +關注

    關注

    87

    文章

    11327

    瀏覽量

    209966
  • 內存
    +關注

    關注

    8

    文章

    3041

    瀏覽量

    74177
  • 程序
    +關注

    關注

    117

    文章

    3793

    瀏覽量

    81221
  • 源碼
    +關注

    關注

    8

    文章

    649

    瀏覽量

    29312
收藏 人收藏

    評論

    相關推薦

    深度分析Linux內存使用方法

    一提到內存管理,我們頭腦中閃出的兩個概念,就是虛擬內存,與物理內存。這兩個概念主要來自于linux內核的支持。
    的頭像 發表于 08-20 09:00 ?7250次閱讀

    Linux kernel內存管理模塊結構分析

    基于上面章節的需求,Linux kernel從虛擬內存(VM)、DMA mapping以及DMA buffer sharing三個角度,對內存進行管理.
    發表于 09-19 11:55 ?1799次閱讀
    <b class='flag-5'>Linux</b> kernel<b class='flag-5'>內存</b>管理模塊結構<b class='flag-5'>分析</b>

    Linux內存管理是什么,Linux內存管理詳解

    Linux內存管理 Linux內存管理是一個非常復雜的過程,主要分成兩個大的部分:內核的內存管理和進程虛擬
    的頭像 發表于 05-11 17:54 ?6112次閱讀
    <b class='flag-5'>Linux</b>的<b class='flag-5'>內存</b>管理是什么,<b class='flag-5'>Linux</b>的<b class='flag-5'>內存</b>管理詳解

    想問下大家有沒有遇到過 時間消息沒又響應 便執行的 不是不是程序內存管理越界了?

    想問下大家有沒有遇到過 時間消息沒又響應 便執行的 不是不是程序內存管理越界了??
    發表于 05-25 16:29

    Linux上對進程進行內存分析內存泄漏定位

    Linux產品開發過程中,通常需要注意系統內存使用量,和評估單一進程的內存使用情況,便于我們選取合適的機器配置,來部署我們的產品。Linux本身提供了一些工具方便我們達成這些需求,查
    發表于 07-09 08:15

    Linux ARM中斷向量重定位硬件平臺分析

    Linux ARM 中斷向量重定位分析
    發表于 07-19 12:34

    嵌入式linux內存越界定位和解決的相關資料分享

    [url=https://blog.csdn.net/meejoy/article/details/41729585https://blog.csdn.net/killmice/article/details/38443343]https://blog.csdn.net/meejoy/article/details/41729585https://blog.csdn.net/killmice/article/details/38443343[/url]轉載于:https://www.cnblogs.com/erhu-67786482/p/10289256.html
    發表于 12-20 07:33

    Java程序內存低效使用問題的分析

    Java程序內存的低效使用是導致其性能問題的主要因素。該文分析了泄漏對象、蚍蜉對象和空閑對象3類導致內存低效使用的情況,探討解決上述問題的方法,并提出構造對象行為模式
    發表于 04-09 09:39 ?12次下載

    數組越界的故障模型及其檢測方法研究

    數組越界是C 程序中的常見故障,該類故障可能造成系統的崩潰。首先針對常見的數組越界故障進行了分析,提出了檢測數組越界的判定準則,建立了故障模
    發表于 09-24 10:49 ?16次下載

    一種改進的虹膜邊界定位算法_汪良會

    一種改進的虹膜邊界定位算法_汪良會
    發表于 03-14 17:38 ?5次下載

    基于SLUB的DEBUG功能,如何幫忙檢測內存越界和訪問已經釋放的內存

    SLAB內存分配器-SLUB的DEBUG功能,如何幫忙檢測內存越界(out-of-bounds)和訪問已經釋放的內存(use-after-free)。
    的頭像 發表于 02-08 14:11 ?9872次閱讀
    基于SLUB的DEBUG功能,如何幫忙檢測<b class='flag-5'>內存</b><b class='flag-5'>越界</b>和訪問已經釋放的<b class='flag-5'>內存</b>

    分析Linux操作系統的內存

    前言:在Linux上不像在Windows上看內存那樣方便,而且還有Swap這個新的概念,所以知道如何來看Linux內存還是有一定意義的
    的頭像 發表于 03-31 16:43 ?1389次閱讀

    Linux內核源碼分析-進程的哪些內存類型容易引起內存泄漏?

    Linux內核主要學習內容可以分為三大塊:進程、內存及協議棧。今天就說說內存泄露的問題。相信你在平時的工作中,應該遇到過下面這些場景: 伴隨著服務器中的后臺任務持續地運行,系統中可用內存
    發表于 01-14 13:02 ?6次下載
    <b class='flag-5'>Linux</b>內核源碼<b class='flag-5'>分析</b>-進程的哪些<b class='flag-5'>內存</b>類型容易引起<b class='flag-5'>內存</b>泄漏?

    Linux 內存管理總結

    一、Linux內存管理概述 Linux內存管理是指對系統內存的分配、釋放、映射、管理、交換、壓縮等一系列操作的管理。在
    的頭像 發表于 11-10 14:58 ?557次閱讀
    <b class='flag-5'>Linux</b> <b class='flag-5'>內存</b>管理總結

    jvm內存溢出該如何定位解決

    超出限制和堆空間不足。 定位JVM內存溢出問題是一個比較復雜的任務,需要結合工具和技術來進行分析和解決。本文將介紹一些常用的調試和解決內存溢出問題的工具和技術。 一、理解JVM
    的頭像 發表于 12-05 11:05 ?1355次閱讀
    主站蜘蛛池模板: 欧美午夜激情影院| 欧美整片第一页| 91福利视频网站| 国产激烈床戏无遮挡观看| 模特精品视频一区| 五夜婷婷| 亚洲第一看片| 色婷婷六月丁香七月婷婷| 日韩xx00| 美女艹逼视频| 韩国免费人成在线观看网站| 第四色激情| 美女张开腿让男人桶爽| 激情五月综合网| 91成人免费在线视频| 国产国产人免费人成成免视频| 成人a级特黄毛片| 国模视频一区二区| bt天堂资源种子在线| 天天干在线影院| 国产亚洲美女精品久久久久狼| 欧美激情一欧美吧| 高清不卡一区二区三区| 色在线免费| 很色视频| 国语自产自拍秒拍在线视频| 4hu影院在线观看| 久久天天躁狠狠躁夜夜免费观看| 在线观看黄的网站| 国产区亚洲区| 日本久本草精品| 99免费观看视频| 国产中文99视频在线观看| 中文字幕亚洲一区| 中文字幕亚洲一区二区v@在线| 道区二区三区四区| 日本人的色道www免费一区| 国产经典一区| 黄黄网址| 国产中文字幕一区| 日本黄色a级|