作者tanted (為何世界會那麼不單純)
看板C_and_CPP
標題[問題] 如何追查可能因MutilThtread下stackover
時間Sun Jul 23 14:45:15 2023
開發平台(Platform): (Ex: Win10, Linux, ...)
linux openwrt
編譯器(Ex: GCC, clang, VC++...)+目標環境(跟開發平台不同的話需列出)
gcc
額外使用到的函數庫(Library Used): (Ex: OpenGL, ...)
問題(Question):
傳入參數被莫名的修改
某個API 如下
CfaIfmNotifyInterfacStat (u4IfIndex, u1AdminStatus,
&u1OperStatus, u1IsFromMib,
u1IsRegToIp,
&IfInfo)) != CFA_SUCCESS)
傳入時的值:
u4IfIndex=43 , u1AdminStatus=1, &u1OperStatus=(UINT1 *) 0xb1e0256f
進入API後值卻變成
https://upload.cc/i1/2023/07/23/ZnvhDF.jpg
u4IfIndex=0, u1AdminStatus=0 , pu1InOperStatus=0x0,
前面4個參數都被變成0
請問各位網友其會被修改到的原因
是不是因為Mutil thread 所造成 其值被其他thread StackOverflow 修改
但由於thread 眾多 各位網友是不是有甚麼的方式或tool
能介紹給我 去debug 找出是哪個thread 哪段code 所造成
謝謝
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 106.1.107.225 (臺灣)
※ 文章網址: https://webptt.com/m.aspx?n=bbs/C_and_CPP/M.1690094718.A.61A.html
※ tanted:轉錄至看板 Soft_Job 07/23 14:55
1F:推 stupid0319: thread很固定的改到別的thread的stack,見鬼了 07/23 15:39
2F:推 LPH66: 你有取消最佳化參數後再去嘗試除錯過嗎? 07/23 17:23
3F:推 seanwu: 只錯前四個的話,我感覺比較像gdb抓參數抓錯,自己照calli 07/23 22:41
4F:→ seanwu: ng convention對一下參數值有沒有變 07/23 22:42
5F:→ seanwu: 然後沒記錯的話,gdb預設應該是all-stop mode, 07/23 22:51
6F:→ seanwu: 所有thread都會停下來才對 07/23 22:51
7F:→ seanwu: 真的要抓,如果支援的話可以試試看watchpoints 07/23 22:54
其實這不是及時gdb的抓取的,這是因為程式crash後,產生了core dump,用gdb去看
的,而程式為什麼crash,最主要原因pu1InOperStatus=0x0 ,因為這是個pointer,而code
對它做指向操作造成segment fault。
只錯前四個是因為我發現到前四個的參數的存放記憶位置是連續,但第5個的記憶體位置
和前4個不是連續的。
目前 其實是這樣認為的
"原本thread 在進入 API,cpu 因context switch 換到其他的thread
而這個thread buff 沒有處理好 Overflow 蓋掉原本thread 的 stack buff"
※ 編輯: tanted (106.1.107.225 臺灣), 07/23/2023 23:40:33
8F:推 LPH66: 那我覺得最佳化等級的影響可能會更大 07/24 01:41
9F:→ LPH66: 或者是上面說的 gdb 沒使用對的呼叫慣例去找參數 07/24 01:41
10F:→ LPH66: 每個 thread 會有他自己的 stack, 如果因為堆疊溢位寫到了 07/24 01:43
11F:→ LPH66: 其他 thread 的 stack, 那它其實已經蓋掉更多東西了 07/24 01:43
12F:→ LPH66: 幾乎不可能到了切過去時才會當掉 07/24 01:44
13F:→ LPH66: (如果真蓋掉更多東西, 很高機會會在蓋掉後不久當掉) 07/24 01:44
14F:→ LPH66: 你還是把最佳化選項 (-O3 等) 拔掉後再跑跑看 07/24 01:45
15F:推 descent: pthread_attr_setstackaddr 用這個設定不同的 stack addr 07/24 09:09
16F:→ descent: 看看是不是一樣有這問題 07/24 09:09
感謝LPH66 給提示的
後來我開始推測可能是進入API後
前面4個變數給記憶體位置可能是不可寫入
也就說從頭到位 變數的值未被修改過
也沒有被其他thread 修改
從一開始進入這個API 就產生segment fault
https://upload.cc/i1/2023/07/24/oJ6wfn.jpg
u4IfIndex 的記憶體位置 是 0xaa303f9c
查看 thread map
https://upload.cc/i1/2023/07/24/2bNjEW.jpg
https://upload.cc/i1/2023/07/24/Bf2Mkn.jpg
右上圖圈選 得知 0xaa303f9 的確在不可存取記憶空間
目前推測會造成這樣原因
因為我們code 分成三個部分 在build
可能帶的最佳化選項 -O 後面數字都不一樣所造成
※ 編輯: tanted (106.1.107.225 臺灣), 07/24/2023 21:58:16
17F:→ leolarrel: 用gdb , or gcc 編譯加上-fsanitize=address,or 用 07/28 14:29
18F:→ leolarrel: Valgrind等工具探查記憶體 07/28 14:30
19F:→ Lipraxde: 加 compile option 前要先對好環境,不然會很痛苦喔XDD 07/28 23:02
其實目前這個issue 尚未解掉 但可以避掉 因為那是讓user telnet 進來執行
才creat 出來thread ,如果一次只執行一個thread 就是只讓一個user進來
就不會有這種情形,如果此時再讓第二個user 進來 ,此時creat 出來thread
就會有這種情形。
※ 編輯: tanted (106.1.107.225 臺灣), 07/29/2023 13:37:44
20F:推 stupid0319: create 07/29 17:03
22F:→ stupid0319: trace 看看 07/29 17:17
我想目前這跟 gdb 或如何trace無關了
為何local stack variable 會被賦一個
"不可存取的記憶位置"
是toolchain 出了問題造成的嗎
toolchain 為 toolchain-arm_cortex-a9+vfpv3-d16_gcc-8.4.0_glibc_eabi
或是編譯時gcc設定參數有關嗎
※ 編輯: tanted (106.1.107.225 臺灣), 07/29/2023 18:23:17
23F:→ stupid0319: 寫code寫到懷疑toolchain還是gcc有問題的 07/29 18:40
24F:→ stupid0319: 9成9都是低級bug造成 07/29 18:40
25F:推 b0920075: 不能直接watch那個地址嗎 07/29 19:05
26F:推 b0920075: 怎麼看你描述只是未初始化變數 07/29 19:10
這四個變數是API的參數,所以一進去API 他就會被賦予上層傳給他引數值,
所以不可能是未初始化變數,但觀察上層引數卻跟傳下來
前四個參數值不一樣,但後面兩個參數跟上層引數是一樣的。
前四個參數值都變成0,一開始我以為可能被其他thread 類似做memset()
可能使用長度過長導致越界去修改到這個thread 堆疊記憶體導致變成0。
後來經過LPH66 提示,他認為不可能是stackoverflow 造成。
加上我使用GDB trace 使用step 進入這個API 就出現segment fault的訊息出來
讓我開始懷疑可能是被給了不可寫入memory address
我上面貼圖 已經很明顯 看到第一個參數的memory address 是在不可存取區間
而第5個參數是在可寫入memory address,所以他和上層傳來引數是相同
但為什麼會前四個參數的memory address會被賦予在不可存取區間
我目前不得而知
※ 編輯: tanted (106.1.107.225 臺灣), 07/29/2023 20:29:13
27F:推 lc85301: 我覺得這個問題沒那麼簡單,看你能不能丟完整 code 出來 07/29 20:31
28F:推 lc85301: 不能的話大家只能給你一點想法,剩下的靠通靈 07/29 20:32
29F:→ lc85301: 另外這個函數我去查也只有你的文章,不是通用的函式 07/29 20:33
30F:→ tanted: 因為這不是opensource Code 不能隨意放出來 07/29 20:34
31F:→ lc85301: 看你的 toolchain 跟 openwrt 應該是在開發嵌入式系統 07/29 20:35
32F:→ Lipraxde: 如果是自己刻的話,有沒有可能是 thread 的實作有問題 07/29 20:37
33F:→ Lipraxde: ,傳 stack 的時候沒對好 ABI? 07/29 20:37
34F:→ lc85301: 我個人通靈的話,我會在進去函數的引數的位址設 watch 07/29 20:39
35F:→ lc85301: 另外你描述方法讓我聯想到這篇古早的文章: 07/29 20:41
37F:推 b0920075: 如果你很確定是multithread在搞何不用 set scheduler-l 07/30 12:08
38F:→ b0920075: ocking on 之類看看不讓thread切換會不會出問題?雖然 07/30 12:08
39F:→ b0920075: 不知道用不同優化選項有沒有差但能用sanitizer 或是rr 07/30 12:08
40F:→ b0920075: 應該有幫助 07/30 12:08
41F:→ descent: 如果確定是在 stack 的變數, 那和編譯器無關 07/31 14:17
42F:→ descent: 這是在程式載入時, sp 被設定了這個位址 07/31 14:18
43F:→ descent: gcc 產生的 code 只是在當時 sp 指到的地方存取這些變數 07/31 14:19
44F:→ descent: 你還是可以試試 pthread_attr_setstackaddr, 07/31 14:20
45F:→ descent: 把 thread stack 換成 malloc 出來的, 應該就不會在 07/31 14:21
46F:→ descent: aa3 開頭的區域, 可能可以避開這問題。 07/31 14:21
47F:→ leolarrel: 認同stupid0319.會懷疑toolchain,我認為是還沒抓到自己 08/16 18:51
48F:→ leolarrel: 的問題 08/16 18:51
49F:→ sunneo: 也有可能是pthread_create傳入的closure的生命週期結束 08/19 18:07