作者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/cn.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