0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

告别 “栈溢出”!用 RT-Trace 工具精准定位嵌入式系统内存隐患 | 技术集结

RT-Thread官方账号 ? 2025-08-31 09:34 ? 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

前言


相信无论大佬还是小白,都在开发中遇到过栈溢出的问题,而且因为没有明确日志,难以定位问题的根源。Stack Overflow 社区的命名也由此而生,而到现在虽然Stack Overflow因为大模型已经几乎要凉凉了,但是栈溢出的问题仍然困扰着许多开发者

正好RT-Trace发布了他们的内测新功能——栈保护,与此同时,采集时长也有了大幅提升,在我的板子上甚至可以稳定采集 三分钟。那我们就来看看他的效果和实用性吧。

测试环境


星火一号开发板

rt-trace工具

使用方法和效果


90adc286-860a-11f0-9080-92fbcf53809c.png

可以看到使用方法顺延了先前trace功能的配置界面,加上了两个框,来选择需要保护的线程和需要被保护的栈底空间大小,使用起来还是很简单的

90bf1766-860a-11f0-9080-92fbcf53809c.png

配置成功后就可以去trace_view界面测试了,这里我星火一号上跑了一个递归爆栈测试程序,没有优化

#include#include#include#ifndefRT_USING_NANO#include#include#include#include#endif/* RT_USING_NANO */rt_thread_tstack_thread =NULL;#defineTHREAD_PRIORITY 25#defineTHREAD_STACK_SIZE 512#defineTHREAD_TIMESLICE 5intmain(void){ while(1) { rt_thread_mdelay(500); }}#defineMAX_RECURSION_DEFAULT 5 // 默认最大递归次数staticintmax_recursion = MAX_RECURSION_DEFAULT;// 可控制的最大递归次数void*get_stack_top_addr(){ return(void*)((uint32_t)stack_thread->stack_addr + stack_thread->stack_size);}void*get_stack_bottom_addr(){ return(void*)((uint32_t)stack_thread->stack_addr);}/*** 递归栈溢出测试函数* 每次递归仅创建一个32位变量* @param depth 当前递归深度*/voidrecursive_stack_overflow(intdepth){ volatileuint32_ta =0x12345678;// 创建一个32位变量并赋值 staticvoid*last_a_addr =NULL; // 获取栈边界地址 void*stack_bottom_addr =get_stack_bottom_addr(); void*stack_top_addr =get_stack_top_addr(); if(depth !=1) { uint32_tstack_used = (uint32_t)last_a_addr - (uint32_t)&a; rt_kprintf("[Depth:%2d] var_a addr:0x%08X,stack_used: %d\n ", depth, &a, stack_used); } else { rt_kprintf("[Depth:%2d] var_a addr:0x%08X\n ", depth, &a); } // 终止条件:达到最大递归次数 if(depth >= max_recursion) { rt_kprintf("[Depth:%2d] 已达到最大递归次数 %d,终止递归\n", depth, max_recursion); return; } last_a_addr = (void*)&a; // 短暂延迟,便于观察输出 rt_thread_mdelay(10); // 递归调用 recursive_stack_overflow(depth +1);}/*** 栈保护线程入口函数* @param p 线程参数*/voidstack_protect_thread(void*p){ // 获取栈信息 void*stack_bottom_addr =get_stack_bottom_addr(); void*stack_top_addr =get_stack_top_addr(); uint32_tstack_size = stack_thread->stack_size; // 打印线程启动信息 rt_kprintf("线程启动:\n"); rt_kprintf(" 栈底地址: 0x%08X\n", stack_bottom_addr); rt_kprintf(" 栈顶地址: 0x%08X\n", stack_top_addr); rt_kprintf(" 栈大小: %d 字节\n", stack_size); rt_kprintf(" 最大递归次数: %d\n", max_recursion); rt_kprintf("----------------------------------------\n"); rt_thread_mdelay(20); // 开始递归测试 recursive_stack_overflow(1); rt_kprintf("----------------------------------------\n"); rt_kprintf("递归测试结束\n");}/*** 设置最大递归次数(外部可调用)* @param count 最大递归次数,<=0 则使用默认值?*/void?set_max_recursion(int?argc,?char?**argv){? ? int?count =?atoi(argv[1]);? ? if?(count <=?0)? ? {? ? ? ? max_recursion = MAX_RECURSION_DEFAULT;? ? ? ? rt_kprintf("已设置最大递归次数为默认值: %d\n", MAX_RECURSION_DEFAULT);? ? }? ? else? ? {? ? ? ? max_recursion = count;? ? ? ? rt_kprintf("已设置最大递归次数为: %d\n", max_recursion);? ? }}MSH_CMD_EXPORT(set_max_recursion, 设置最大递归次数(参数为次数));/**?* 创建栈保护测试线程?*/void?create_stack_protect_thread(void){? ? // 创建线程(栈大小2048字节)? ? stack_thread =?rt_thread_create(? ? ? ? "stack_thread", ? ? ? // 线程名称? ? ? ? stack_protect_thread,?// 入口函数? ? ? ? RT_NULL, ? ? ? ? ? ? ?// 参数? ? ? ? 512, ? ? ? ? ? ? ? ? ?// 栈大小? ? ? ? 20, ? ? ? ? ? ? ? ? ? // 优先级? ? ? ? 10? ? ? ? ? ? ? ? ? ? // 时间片? ? );? ? if?(stack_thread != RT_NULL)? ? {? ? ? ? rt_thread_startup(stack_thread);? ? ? ? rt_kprintf("栈保护线程创建成功\n");? ? }? ? else? ? {? ? ? ? rt_kprintf("栈保护线程创建失败\n");? ? }}MSH_CMD_EXPORT(create_stack_protect_thread, 创建栈保护测试线程);

经过递归三次,五次,八次(第八次溢出)的测试后,捕获到的trace图像是这样的

90d20b1e-860a-11f0-9080-92fbcf53809c.png90e0c55a-860a-11f0-9080-92fbcf53809c.png90e989ba-860a-11f0-9080-92fbcf53809c.png

0-4s 和 0-8s 递归三次以及递归五次,都没有踩到我们的报警阈值

8-12s 递归八次时,在第6次踩到我们的64字节报警线

msh />create_stack_protect_thread栈保护线程创建成功msh />线程启动: 栈底地址:0x20004160 栈顶地址:0x20004360 栈大小: 512字节 最大递归次数:10----------------------------------------[Depth: 1] var_a addr:0x20004330[Depth: 2] var_a addr:0x20004310,stack_used:32[Depth: 3] var_a addr:0x200042F0,stack_used:32[Depth: 4] var_a addr:0x200042D0,stack_used:32[Depth: 5] var_a addr:0x200042B0,stack_used:32[Depth: 6] var_a addr:0x20004290,stack_used:32[Depth: 7] var_a addr:0x20004270,stack_used:32[Depth: 8] var_a addr:0x20004250,stack_used:32[E/kernel.sched] thread:stack_tstack overflow

从上面的调试日志可以看到,栈溢出前64字节,正好是第六次递归的时候,这说明这个栈溢出报警起码准确度没问题。

但是细心的小伙伴可能发现了另一个问题,距离栈底似乎还有很大的空间,但是栈溢出“提前发生了”,我们的报警也提前了。这是因为我们的递归函数中调用了其他的函数,经过调试发现,造成栈溢出的直接原因是rt_thread_mdelay,最后栈溢出时,第八次递归进入后,sp位置在0x20004240,而调用rt_thread_mdelay最大深度能到0x2000412c,此时已经远远超过了我们的栈底,所以溢出和警报都是正常的。

总结


体验下来,rt-trace的栈保护功能确实能很好的提示我线程栈的使用情况,可调的阈值也给了用户比较大的自由度,这次的升级trace的采集时间也大大加长了,之前只能采12秒,现在可以以分钟为单位进行采集。

不过还是有些可以继续提升的部分,比如现在的栈保护只能保护一个线程,如果能实时自动保护所有的线程,可能使用的体验和带来的帮助会更好。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式系统
    +关注

    关注

    41

    文章

    3696

    浏览量

    131899
  • 内存
    +关注

    关注

    8

    文章

    3137

    浏览量

    75527
  • 堆栈溢出
    +关注

    关注

    0

    文章

    10

    浏览量

    8064
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    嵌入式RTOS的 任务系统

    简介明了带你了解嵌入式RTOS的 任务系统
    的头像 发表于 05-16 09:57 ?4241次阅读
    <b class='flag-5'>嵌入式</b>RTOS的 任务<b class='flag-5'>栈</b> 和 <b class='flag-5'>系统</b><b class='flag-5'>栈</b>

    RT-Trace】功能再升级!GDB?Server功能?+?Flash一键烧录,嵌入式开发更加便捷!|?技术集结

    RT-Trace持续进化,推出两大开发者期待的核心功能:GDBServer功能与Flash程序烧录!本次升级旨在为嵌入式开发者提供更强大、更便捷、更高效的开发调试体验,显著提升开发效率,降低门槛
    的头像 发表于 07-25 15:40 ?4277次阅读
    【<b class='flag-5'>RT-Trace</b>】功能再升级!GDB?Server功能?+?Flash一键烧录,<b class='flag-5'>嵌入式</b>开发更加便捷!|?<b class='flag-5'>技术</b><b class='flag-5'>集结</b>

    揭秘!基于RT-Thread探究“优先级反转”下的任务调度究竟是什么样的?| 技术集结

    本文将基于RT-Thread,结合RT-Trace调试器细化到实际任务调度的粒度,来调试并逐步讲解“优先级反转”的调度和运行逻辑。如果对RT-Trace感兴趣的可以看这篇文章:国产嵌入式
    的头像 发表于 08-17 10:07 ?2266次阅读
    揭秘!基于<b class='flag-5'>RT</b>-Thread探究“优先级反转”下的任务调度究竟是什么样的?| <b class='flag-5'>技术</b><b class='flag-5'>集结</b>

    基于“互联网+”与北斗的精准定位智慧停车系统

    停车系统进行集中管理,相信应该会好很多。精准定位智慧停车系统目前,太原市已经开始着手建设“互联网+”与北斗精准定位智慧停车系统,结合车位传感
    发表于 08-08 17:07

    如何使用嵌入式内存分配管理技术

    嵌入式---内存分配管理嵌入式内存一般都非常的小,最进在学习LWIP协议的移植,在正点原子的学习资料中找到了许多关于怎么移植协议
    发表于 12-17 06:41

    求一种嵌入式软件中的溢出检查方案

    嵌入式软件中溢出产生的原因是什么?嵌入式软件中的溢出是怎样产生的呢?
    发表于 01-19 06:48

    我国5G北斗精准定位技术已成熟

    5G北斗精准定位联盟以推动5G定位系统与北斗卫星定位系统发展为目标,构建精准定位产业链合作、交流
    发表于 04-08 10:21 ?2692次阅读

    trace32 for rt-thread support的基本使用及系统插件原理

    的生产商,自1979年以来,在制造世界一流的调试器和实时跟踪方面拥有丰富经验。其中产品线中的TRACE32为大众广为所知,是众多手机厂商、芯片厂商的必备工具。 在嵌入式底层开发来说,不使用一下
    的头像 发表于 01-07 10:34 ?7246次阅读

    UWB技术是如何做到室内精准定位的?

    UWB技术是如何做到室内精准定位的? ? ? ? ?作为当下室内定位技术的新贵,UWB定位技术
    发表于 10-18 09:22 ?1157次阅读

    jvm内存溢出该如何定位解决

    超出限制和堆空间不足。 定位JVM内存溢出问题是一个比较复杂的任务,需要结合工具技术来进行分析和解决。本文将介绍一些常用的调试和解决
    的头像 发表于 12-05 11:05 ?1780次阅读

    如何实现室内精准定位?分享室内精准定位技术及方法

    室内精准定位技术和方法。 一、室内定位技术的背景 在室内进行定位比在室外复杂得多。室外使用全球定位系统
    的头像 发表于 09-24 11:21 ?1890次阅读
    如何实现室内<b class='flag-5'>精准定位</b>?分享室内<b class='flag-5'>精准定位</b><b class='flag-5'>技术</b>及方法

    顶坚国产芯单北斗执法仪:精准定位铁路隐患,保障行车安全

    顶坚国产芯单北斗执法仪,是一款集成了北斗卫星导航系统和先进技术的执法设备,依托北斗卫星导航系统的高精度定位技术
    的头像 发表于 01-09 15:25 ?519次阅读
    顶坚国产芯单北斗执法仪:<b class='flag-5'>精准定位</b>铁路<b class='flag-5'>隐患</b>,保障行车安全

    重磅预售!RT-Trace调试工具

    嵌入式开发者注意!调试神器RT-Trace即将登陆淘宝!嵌入式开发从业者们:您是否常被调试效率低下、线程分析不清、故障定位困难所困扰?别愁!专为嵌入
    的头像 发表于 05-20 18:15 ?710次阅读
    重磅预售!<b class='flag-5'>RT-Trace</b>调试<b class='flag-5'>工具</b>

    RT-Trace调试工具正式发布!

    嵌入式开发者打造的高性能调试工具RT-Trace支持SWD/JTAG高速连接,搭载板载显示屏离线交互系统与WebUI实时监控平台,助力代码调试、性能分析、故障排查全流程
    的头像 发表于 06-18 12:02 ?762次阅读
    <b class='flag-5'>RT-Trace</b>调试<b class='flag-5'>工具</b>正式发布!

    RT-Trace初体验一之使用Trace功能调试Cortex-M4 | 技术集结

    随着嵌入式系统规模和复杂度不断提升,传统的调试手段已难以满足对系统运行状态的精细化分析需求。为提升开发效率、优化系统性能,RT-Thread
    的头像 发表于 07-06 10:03 ?738次阅读
    <b class='flag-5'>RT-Trace</b>初体验一之使用<b class='flag-5'>Trace</b>功能调试Cortex-M4 | <b class='flag-5'>技术</b><b class='flag-5'>集结</b>