5_vscode+valgrind+gdb调试程序

需求

  1. 项目程序, 读取串口数据, 出现程序崩溃问题
  2. valgrind 可以调试定位内存问题: 内存泄漏,非法地址访问,越界访问等内存问题
  3. vscode + gdb 可视化调试效果, 比命令行简单快捷很多
  4. 期望使用vscode + valgrind + gdb 调试程序内存异常, 崩溃退出的问题

环境准备
sudo apt install valgrind gdb

调试

1.valgrind + gdb 命令行调试程序

1.代码

51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c

#include <stdio.h>
#include <string.h>
#include <stdint.h>

// 1.内存泄漏
void memory_leak(void)
{
    char *p = (char *)malloc(1024);
    memset(p, 0, 1024);
}

// 2.非法地址访问
void invalid_address_access(void)
{
    // uint8_t *p = 0x12345678;
    uint8_t *p = NULL;
    uint8_t val = *p;
    printf("val = %d\n", val);
}

// 3.栈空间越界 读写
void corss_border_read_write(void)
{
    uint32_t a = 0x10;
    uint32_t *p = &a + 0x8;

    // 越界读 -- 导致逻辑错误
    printf("Invalid address read %x\n", *p);

    // 越界写 -- 程序错误
    *p = 0x12345678;
    printf("Invalid address write %x\n", *p);
}

// 4.堆空间越界访问, 属于2.非法地址访问

int main()
{
    memory_leak();
    corss_border_read_write();
    invalid_address_access();

    return 0;
}

2.编译

scons编译
SConstruct

env = Environment()
env["PROGSUFFIX"] = ".out"            # 可执行后缀.out
env["CCFLAGS"] = " -g3 -O0 -Wall"  # gdb 调试开关
env.Program("51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c")

scons

g++ -o 51_mem_valgrind调试_内存泄漏_非法地址访问_越界.o -c -g3 -O0 --std=c99 51_mem_valgrind调试_内存泄漏_非法地址访问_越界.c
g++ -o 51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out 51_mem_valgrind调试_内存泄漏_非法地址访问_越界.o

3.valgrind开启vgdb调试

valgrind --leak-check=full --show-leak-kinds=all --vgdb=yes --vgdb-error=0 51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out

3279 Memcheck, a memory error detector
3279 Copyright © 2002-2017, and GNU GPL’d, by Julian Seward et al.
3279 Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
3279 Command: ./51_mem_valgrind_____________________________________________.out
3279
3279 (action at startup) vgdb me …
3279
3279 TO DEBUG THIS PROCESS USING GDB: start GDB like this
3279 /path/to/gdb ./51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out
3279 and then give GDB the following command
3279 target remote | /usr/lib/x86_64-linux-gnu/valgrind/…/…/bin/vgdb --pid=3279
3279 --pid is optional if only one valgrind process is running

valgrind 参数说明:

  • –leak-check=full 内存泄漏检测
  • –show-leak-kinds=all 详细各种异常检测
  • –vgdb=yes --vgdb-error=0 开启vgdb
4.gdb 调试

gdb 51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out

Reading symbols from ./51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out…
(gdb) target remote|vgdb #远程到vgdb调试
Remote debugging using |vgdb
relaying data between gdb and process 3279
Reading symbols from /usr/lib/debug/.build-id/7a/e2aaae1a0e5b262df913ee0885582d2e327982.debug…
0x0000000004001100 in _start () from /lib64/ld-linux-x86-64.so.2
c 按c开始运行

命令行效果如图:
![[valgrind+gdb调试程序.jpg]]

2.vscode + valgrind + gdb调试

1.vscode launch.json配置

使用国内几个大模型, 都无法给出正确可用的配置
在外网github搜到一个可参考的配置方法
链接: https://github.com/microsoft/vscode-cpptools/issues/4531
william-r-dieter commented on Aug 28, 2020
Here is the launch.json that worked for me:
launch.json

           "customLaunchSetupCommands" : [
               {
                 "description": "Attach to valgrind",
                 "text": "target remote | /usr/lib64/valgrind/../../bin/vgdb",
                 "ignoreFailures": false  
               }
           ],

vscode开启valgrind调试核心配置 launch.json

            "setupCommands": [
                {
                    "description": "vgdb",
                    "text": "target remote | /usr/bin/vgdb ",
                    "ignoreFailures": true
                }
            ],

launch.json 完整配置
注意不能照抄, 我的默认编译构建工具是scons

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) 启动",
            "type": "cppdbg",
            "request": "launch",
            "program": "${fileDirname}/${fileBasenameNoExtension}.out",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${fileDirname}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "为 gdb 启用整齐打印",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                },
                {
                    "description": "vgdb",
                    "text": "target remote | /usr/bin/vgdb ",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "scons"
        }
    ]
}

2.valgrind 开启vgdb调试

valgrind --leak-check=full --show-leak-kinds=all --vgdb=yes --vgdb-error=0 51_mem_valgrind调试_内存泄漏_非法地址访问_越界.out

3.vscode 启动gdb远程

参考 1.vscode launch.json配置
F5 运行

效果如图
![[vscode+valgrind+gdb调试程序.jpg]]

总结

  1. valgrind + gdb 可以快速定位问题点
  2. 有概率gdb调试退出时, valgrind没有退出, 使用kill -9 强制退出kill -9 valgrind_pid
  3. 项目中使用cppcheck + valgrind, 找出潜在的问题5-6个问题点,其中一个映像深刻
    1. 字节缓冲区, data_len变量为异常值(默认128, 异常时为156023), 导致指针索引地址越界
  • 当通过C 指针索引地址时, 如果索引为异常值, 导致越界,或非法访问, 确实有风险.
  • python列表,索引值越界会报异常
  • c++ vector<uint8_t> 索引值越界会报异常

反思

  1. c++中尝试尽量将 bytes字节数据 转为vector<uint8_t> 处理
  2. 提交代码之前,进入安全稳定自测: valgrind, lsof, ss 排查内存,文件句柄,套接字资源是否有泄漏,漏洞,网络安全
  3. 尝试使用安全的语言, 如rust, 确认是否会有此问题

我是一名 嵌入式-系统-网络-机器人爱好者


  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 OpenWrt 上使用 Valgrind 需要注意以下几点: 1. 安装 Valgrind 可以通过 opkg 安装 Valgrind: ``` opkg update opkg install valgrind ``` 2. 配置 Valgrind 默认情况下,Valgrind 会使用 glibc 库,而 OpenWrt 中使用的是 uClibc 库,因此需要手动配置 Valgrind。 首先,需要创建一个文件 `/etc/valgrindrc`,并添加以下内容: ``` # Valgrind configuration file for uClibc libc-libraries: /lib/libuClibc-*.so.* ``` 然后,在运行 Valgrind 时,需要指定使用该配置文件: ``` valgrind --tool=memcheck --vgdb=no --trace-children=yes --num-callers=20 --suppressions=/usr/lib/valgrind/uClibc.supp --read-var-info=yes --malloc-fill=0xFE --free-fill=0xEF --leak-check=full --show-reachable=yes --track-origins=yes --log-file=/tmp/valgrind.log --error-limit=no --undef-value-errors=no --gen-suppressions=all --fair-sched=yes --quiet --trace-children=yes --trace-children-skip=*dhclient* --trace-children-skip=*udhcpc* --trace-children-skip=*pppd* --trace-children-skip=*klogd* --trace-children-skip=*syslogd* --trace-children-skip=*hotplug2* --trace-children-skip=*ntpd* --trace-children-skip=*odhcpd* --trace-children-skip=*dnsmasq* --trace-children-skip=*hostapd* --trace-children-skip=*wpa_supplicant* --trace-children-skip=*ubusd* --trace-children-skip=*logd* --trace-children-skip=*smbd* --trace-children-skip=*nmbd* --trace-children-skip=*irqbalance* --trace-children-skip=*procd* --trace-children-skip=*crond* --trace-children-skip=*ubus* --trace-children-skip=*ubusd* --trace-children-skip=*uhttpd* --trace-children-skip=*amule* --trace-children-skip=*transmission* --trace-children-skip=*minidlna* --trace-children-skip=*mjpg_streamer* --trace-children-skip=*sshd* --trace-children-skip=*swapon* --trace-children-skip=*swapoff* --trace-children-skip=*fstab* --trace-children-skip=*mount* --trace-children-skip=*umount* --trace-children-skip=*tar* --trace-children-skip=*rsync* --trace-children-skip=*scp* --trace-children-skip=*sftp* --trace-children-skip=*ftpd* --trace-children-skip=*ftp* --trace-children-skip=*telnetd* --trace-children-skip=*ssh* --trace-children-skip=*tftp* --trace-children-skip=*httpd* --trace-children-skip=*vnstatd* --trace-children-skip=*ntfs-3g* --trace-children-skip=*samba* --trace-children-skip=*proftpd* --trace-children-skip=*lighttpd* --trace-children-skip=*php* --trace-children-skip=*mysql* --trace-children-skip=*sqlite3* --trace-children-skip=*redis* --trace-children-skip=*memcached* --trace-children-skip=*mosquitto* --trace-children-skip=*influxd* --trace-children-skip=*grafana-server* --trace-children-skip=*postgresql* --trace-children-skip=*mongodb* --trace-children-skip=*cupsd* --trace-children-skip=*dovecot* --trace-children-skip=*nginx* --trace-children-skip=*php-fpm* --trace-children-skip=*thttpd* --trace-children-skip=*dnscrypt-proxy* --trace-children-skip=*tor* --trace-children-skip=*tinyproxy* --trace-children-skip=*privoxy* --trace-children-skip=*squid* --trace-children-skip=*polipo* --trace-children-skip=*darkhttpd* --trace-children-skip=*kamailio* --trace-children-skip=*opensips* --trace-children-skip=*asterisk* --trace-children-skip=*freeswitch* --trace-children-skip=*nagios* --trace-children-skip=*nrpe* --trace-children-skip=*collectd* --trace-children-skip=*snmpd* --trace-children-skip=*openvpn* --trace-children-skip=*pptpd* --trace-children-skip=*strongswan* --trace-children-skip=*xl2tpd* --trace-children-skip=*pppoe-server* --trace-children-skip=*pppoe-relay* --trace-children-skip=*pppoe* --trace-children-skip=*ppp* --trace-children-skip=*rtorrent* --trace-children-skip=*transmission-daemon* --trace-children-skip=*darkstat* --trace-children-skip=*vnstat* --trace-children-skip=*iptraf-ng* --trace-children-skip=*tcpdump* --trace-children-skip=*wireshark* --trace-children-skip=*snort* --trace-children-skip=*sflowtool* --trace-children-skip=*sflow-rt* --trace-children-skip=*ntopng* --trace-children-skip=*openvswitch* --trace-children-skip=*kmod* --trace-children-skip=*iptables* --trace-children-skip=*ip6tables* --trace-children-skip=*ipset* --trace-children-skip=*ulogd* --trace-children-skip=*dhcp6c* --trace-children-skip=*dhcp6s* --trace-children-skip=*wide-dhcpv6* --trace-children-skip=*radvd* --trace-children-skip=*6relayd* --trace-children-skip=*odhcp6c* --trace-children-skip=*odhcpd-dhcpv6* --trace-children-skip=*ip6tables-save* --trace-children-skip=*ip6tables-restore* --trace-children-skip=*iptables-save* --trace-children-skip=*iptables-restore* --trace-children-skip=*ip6tables-restore* --trace-children-skip=*iptables-restore* --trace-children-skip=*logrotate* --trace-children-skip=*sysupgrade* --trace-children-skip=*jffs2dump* --trace-children-skip=*ubiformat* --trace-children-skip=*ubiupdatevol* --trace-children-skip=*ubiattach* --trace-children-skip=*ubidetach* --trace-children-skip=*ubimkvol* --trace-children-skip=*ubirmvol* --trace-children-skip=*ubirename* --trace-children-skip=*ubiupdatevol* --trace-children-skip=*ubiblock* --trace-children-skip=*ubinize* --trace-children-skip=*ubi* --trace-children-skip=*mtd* --trace-children-skip=*dd* --trace-children-skip=*fdisk* --trace-children-skip=*parted* --trace-children-skip=*mkfs* --trace-children-skip=*mkswap* --trace-children-skip=*mkfs.ext3* --trace-children-skip=*mkfs.ntfs* --trace-children-skip=*mkfs.vfat* --trace-children-skip=*mkfs.xfs* --trace-children-skip=*mkfs.jffs2* --trace-children-skip=*mkfs.ubifs* --trace-children-skip=*mount* --trace-children-skip=*umount* --trace-children-skip=*mount* --trace-children-skip=*umount* --trace-children-skip=*fsck* --trace-children-skip=*fsck.ext3* --trace-children-skip=*fsck.ntfs* --trace-children-skip=*fsck.vfat* --trace-children-skip=*fsck.xfs* --trace-children-skip=*fsck.jffs2* --trace-children-skip=*fsck.ubifs* --trace-children-skip=*e2label* --trace-children-skip=*ntfslabel* --trace-children-skip=*dosfslabel* --trace-children-skip=*xfs_admin* --trace-children-skip=*jffs2* --trace-children-skip=*mke2fs* --trace-children-skip=*ntfs-3g.probe* --trace-children-skip=*ntfs-3g.secaudit* --trace-children-skip=*ntfs-3g.usermap* --trace-children-skip=*ntfs-3g* --trace-children-skip=*mount.ntfs-3g* --trace-children-skip=*mount.ntfs* --trace-children-skip=*udhcpc* --trace-children-skip=*dhclient* --trace-children-skip=*dhcpd* --trace-children-skip=*dnsmasq* --trace-children-skip=*hostapd_cli* --trace-children-skip=*wpa_cli* --trace-children-skip=*wpa_supplicant* --trace-children-skip=*pppd* --trace-children-skip=*pptp* --trace-children-skip=*l2tpd* --trace-children-skip=*openconnect* --trace-children-skip=*openvpn* --trace-children-skip=*strongswan* --trace-children-skip=*xl2tpd* --trace-children-skip=*pppoe-server* --trace-children-skip=*pppoe-relay* --trace-children-skip=*pppoe* --trace-children-skip=*ppp* --trace-children-skip=*smbd* --trace-children-skip=*nmbd* --trace-children-skip=*nmblookup* --trace-children-skip=*smbclient* --trace-children-skip=*smbpasswd* --trace-children-skip=*smbstatus* --trace-children-skip=*smbtree* --trace-children-skip=*wins* --trace-children-skip=*samba-tool* --trace-children-skip=*transmission* --trace-children-skip=*transmission-daemon* --trace-children-skip=*amule* --trace-children-skip=*aria2c* --trace-children-skip=*wget* --trace-children-skip=*curl* --trace-children-skip=*ftp* --trace-children-skip=*scp* --trace-children-skip=*sftp* --trace-children-skip=*rsync* --trace-children-skip=*tar* --trace-children-skip=*tftp* --trace-children-skip=*telnet* --trace-children-skip=*ssh* --trace-children-skip=*sftp-server* --trace-children-skip=*ftp-proxy* --trace-children-skip=*proxsmtp* --trace-children-skip=*spamassassin* --trace-children-skip=*fetchmail* --trace-children-skip=*dovecot* --trace-children-skip=*postfix* --trace-children-skip=*exim* --trace-children-skip=*sendmail* --trace-children-skip=*nginx* --trace-children-skip=*apache2* --trace-children-skip=*lighttpd* --trace-children-skip=*php* --trace-children-skip=*mysql* --trace-children-skip=*postgresql* --trace-children-skip=*mosquitto* --trace-children-skip=*influxd* --trace-children-skip=*grafana-server* --trace-children-skip=*memcached* --trace-children-skip=*redis* --trace-children-skip=*mongodb* --trace-children-skip=*cupsd* --trace-children-skip=*darkhttpd* --trace-children-skip=*dnscrypt-proxy* --trace-children-skip=*tor* --trace-children-skip=*tinyproxy* --trace-children-skip=*privoxy* --trace-children-skip=*squid* --trace-children-skip=*polipo* --trace-children-skip=*kamailio* --trace-children-skip=*opensips* --trace-children-skip=*asterisk* --trace-children-skip=*freeswitch* --trace-children-skip=*nagios* --trace-children-skip=*nrpe* --trace-children-skip=*collectd* --trace-children-skip=*snmpd* --trace-children-skip=*openvswitch* --trace-children-skip=*iptables* --trace-children-skip=*ip6tables* --trace-children-skip=*ipset* --trace-children-skip=*ulogd* --trace-children-skip=*dhcp6c* --trace-children-skip=*dhcp6s* --trace-children-skip=*wide-dhcpv6* --trace-children-skip=*radvd* --trace-children-skip=*6relayd* --trace-children-skip=*odhcp6c* --trace-children-skip=*odhcpd-dhcpv6* --trace-children-skip=*ip6tables-save* --trace-children-skip=*ip6tables-restore* --trace-children-skip=*iptables-save* --trace-children-skip=*iptables-restore* --trace-children-skip=*ip6tables-restore* --trace-children-skip=*iptables-restore* --trace-children-skip=*logrotate* --trace-children-skip=*sysupgrade* --trace-children-skip=*opkg* ``` 这里的参数根据需求来调整。 3. 运行 Valgrind 使用 `valgrind` 命令即可运行 Valgrind,例如: ``` valgrind --tool=memcheck --leak-check=full myprogram arg1 arg2 ``` 这里的 `myprogram` 是需要测试的程序,`arg1`、`arg2` 是该程序的参数。 注意:Valgrind 会对程序的运行速度有一定的影响,因此在测试时需要对程序进行压力测试,以确保测试结果的准确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值