valgrind 配合 gdb 调试程序
在实际研发过程中,可能会遇到过这样的问题:测试通过 valgrind 验证当前代码存在变量未初始化的问题,但仅通过 valgrind 测试报告,研发无法确认具体的应用场景。本文将通过 valgrind 检测并定位程序中变量未初始化的问题,并给出用户具体的操作场景。
前言
为保证程序的健壮性和可靠性,程序在完成基本的功能测试后,一般来说还要进行内存使用相关的测试。Valgrind 是一个强大的 C 和 C++ 程序调试和性能分析工具。它可以检测内存泄漏、未初始化的内存使用以及其他各种错误。本文将以 MariaDB 为例,通过 valgrind 检测并定位程序中变量未初始化的问题。
使用 valgrind 检测程序错误
- 为说明问题,在 MariaDB 的 mysql_execute_command 函数中添加如下代码:
int unitialized_value;
if (SQLCOM_SHOW_TABLES != thd_sql_command(thd)) {
unitialized_value = 0;
}
if (unitialized_value) {
sql_print_information("Unitialized value");
}
- 使用 valgrind 运行 mariadbd 程序
valgrind --tool=memcheck --trace-children=yes --track-origins=yes \
--leak-check=full --show-leak-kinds=all \
--log-file=./valgrind.log --error-limit=no \
/home/dbdev/mariadb/bin/mariadbd --defaults-file=./etc/mariadb.cnf &
- 登录 MariaDB server
/home/dbdev/mariadb/bin/mysql -S /home/dbdev/mariadb/data/mysqld.sock
- 执行如下 SQL 语句
MariaDB [(none)]>
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sakila |
| sys |
| test |
| world_x |
+--------------------+
7 rows in set (0.486 sec)
MariaDB [(none)]> use test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [test]> show tables;
+----------------+
| Tables_in_test |
+----------------+
| v1 |
+----------------+
1 row in set (0.096 sec)
- 查看 valgrind.log 日志
==5432== Memcheck, a memory error detector
==5432== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5432== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==5432== Command: /home/dbdev/mariadb/bin/mariadbd --defaults-file=./etc/mariadb.cnf
==5432== Parent PID: 1055
==5432==
==5432== Warning: set address range perms: large range [0x124746000, 0x164746000) (defined)
==5432== Warning: set address range perms: large range [0x164746000, 0x1a4746000) (defined)
==5432== Warning: set address range perms: large range [0x124746000, 0x144063000) (defined)
==5432== Warning: set address range perms: large range [0x124746000, 0x144063000) (defined)
==5432== Thread 20:
==5432== Conditional jump or move depends on uninitialised value(s)
==5432== at 0xAA9991: mysql_execute_command(THD*, bool) (sql_parse.cc:3482)
==5432== by 0xAB52D3: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:7779)
==5432== by 0xAA4E5A: dispatch_command(enum_server_command, THD*, char*, unsigned int, bool) (sql_parse.cc:1892)
==5432== by 0xAA3C74: do_command(THD*, bool) (sql_parse.cc:1405)
==5432== by 0xC9381C: do_handle_one_connection(CONNECT*, bool) (sql_connect.cc:1416)
==5432== by 0xC9359C: handle_one_connection (sql_connect.cc:1318)
==5432== by 0x11D4C72: pfs_spawn_thread (pfs.cc:2201)
==5432== by 0x5330B42: start_thread (pthread_create.c:442)
==5432== by 0x53C1BB3: clone (clone.S:100)
==5432== Uninitialised value was created by a stack allocation
==5432== at 0xAA977B: mysql_execute_command(THD*, bool) (sql_parse.cc:3444)
==5432==
valgrind 配合 gdb 调试程序错误
存在的问题
测试生成了 valgrind 测试报告 valgrind.log,测试报告内容如下:
==5432== Memcheck, a memory error detector
==5432== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5432== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==5432== Command: /home/dbdev/mariadb/bin/mariadbd --defaults-file=./etc/mariadb.cnf
==5432== Parent PID: 1055
==5432==
==5432== Warning: set address range perms: large range [0x124746000, 0x164746000) (defined)
==5432== Warning: set address range perms: large range [0x164746000, 0x1a4746000) (defined)
==5432== Warning: set address range perms: large range [0x124746000, 0x144063000) (defined)
==5432== Warning: set address range perms: large range [0x124746000, 0x144063000) (defined)
==5432== Thread 20:
==5432== Conditional jump or move depends on uninitialised value(s)
==5432== at 0xAA9991: mysql_execute_command(THD*, bool) (sql_parse.cc:3482)
==5432== by 0xAB52D3: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:7779)
==5432== by 0xAA4E5A: dispatch_command(enum_server_command, THD*, char*, unsigned int, bool) (sql_parse.cc:1892)
==5432== by 0xAA3C74: do_command(THD*, bool) (sql_parse.cc:1405)
==5432== by 0xC9381C: do_handle_one_connection(CONNECT*, bool) (sql_connect.cc:1416)
==5432== by 0xC9359C: handle_one_connection (sql_connect.cc:1318)
==5432== by 0x11D4C72: pfs_spawn_thread (pfs.cc:2201)
==5432== by 0x5330B42: start_thread (pthread_create.c:442)
==5432== by 0x53C1BB3: clone (clone.S:100)
==5432== Uninitialised value was created by a stack allocation
==5432== at 0xAA977B: mysql_execute_command(THD*, bool) (sql_parse.cc:3444)
==5432==
研发进能够根据该堆栈信息查询到未初始化值的设置地方及使用地方。但是不清楚具体是哪种操作(具体 SQL 语句)导致的,因为具体应用中未初始化 unitialized_value 的地方可能存在多处。
valgrind 配合 gdb 调试 MariaDB
- 开启终端 T1,使用 gdb 模式运行 valgrind,即指定 --vgdb=yes --vgdb-error=0 选项运行 valgrind
valgrind --tool=memcheck --trace-children=yes --track-origins=yes \
--vgdb=yes --vgdb-error=0 --leak-check=full \
--show-leak-kinds=all --log-file=./valgrind.log \
--error-limit=no /home/dbdev/mariadb/bin/mariadbd \
--defaults-file=./etc/mariadb.cnf &
- 开启终端 T2,使用 gdb 调试运行 mariadbd
gdb /home/dbdev/mariadb/bin/mariadbd
GNU gdb (Ubuntu 13.1-2ubuntu2) 13.1
Copyright (C) 2023 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from bin/mariadbd...
(gdb)
(gdb)
- 终端 T1 打开 valgrind.log
cat valgrind.log
==7516== Memcheck, a memory error detector
==7516== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7516== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==7516== Command: /home/dbdev/mariadb/bin/mariadbd --defaults-file=./etc/mariadb.cnf
==7516== Parent PID: 1055
==7516==
==7516== (action at startup) vgdb me ...
==7516==
==7516== TO DEBUG THIS PROCESS USING GDB: start GDB like this
==7516== /path/to/gdb /home/dbdev/mariadb/bin/mariadbd
==7516== and then give GDB the following command
==7516== target remote | /usr/bin/vgdb --pid=7516
==7516== --pid is optional if only one valgrind process is running
==7516==
- 将 "target remote | /usr/bin/vgdb --pid=7516" 输入到 T2 执行
(gdb) target remote | /usr/bin/vgdb --pid=7516
Remote debugging using | /usr/bin/vgdb --pid=7516
relaying data between gdb and process 7516
warning: remote target does not support file transfer, attempting to access files from local filesystem.
Reading symbols from /lib64/ld-linux-x86-64.so.2...
Reading symbols from /usr/lib/debug/.build-id/bf/789e981fb305f374f3975a4b248eb4cd207ce6.debug...
0x00000000040202f0 in _start () from /lib64/ld-linux-x86-64.so.2
- T2 输入 c 命令后程序自动运行,后续用户连接到 MariaDB 实例执行 SQL 语句时,valgrind 在检测到代码可能存在问题时会自动激活 valgrind 内部设置的断点,此时就可以观察程序内部的变量是否正确
(gdb) target remote | /usr/bin/vgdb --pid=7516
Remote debugging using | /usr/bin/vgdb --pid=7516
relaying data between gdb and process 7516
warning: remote target does not support file transfer, attempting to access files from local filesystem.
Reading symbols from /lib64/ld-linux-x86-64.so.2...
Reading symbols from /usr/lib/debug/.build-id/bf/789e981fb305f374f3975a4b248eb4cd207ce6.debug...
0x00000000040202f0 in _start () from /lib64/ld-linux-x86-64.so.2
(gdb) c
Continuing.
- T1 登录 MariaDB 实例,执行如下 SQL 语句,该操作会激活 T2 的 gdb 断点
MariaDB [(none)]> use test
- T2 查看堆栈信息,输出当前的 SQL 语句信息,通过这种方式,我们可以清楚的知道具体是什么操作导致了未初始化内存的使用
(gdb) bt
#0 0x0000000000aa99a0 in mysql_execute_command (thd=0x1aa290f88, is_called_from_prepared_stmt=false) at /home/dbdev/workspace/server/sql/sql_parse.cc:3482
#1 0x0000000000ab52e4 in mysql_parse (thd=0x1aa290f88, rawbuf=0x1aa30bf20 "show tables", length=11, parser_state=0x1aa51b1f0) at /home/dbdev/workspace/server/sql/sql_parse.cc:7779
#2 0x0000000000aa4e5b in dispatch_command (command=COM_QUERY, thd=0x1aa290f88, packet=0x1aa29b479 "show tables", packet_length=11, blocking=true) at /home/dbdev/workspace/server/sql/sql_parse.cc:1892
#3 0x0000000000aa3c75 in do_command (thd=0x1aa290f88, blocking=true) at /home/dbdev/workspace/server/sql/sql_parse.cc:1405
#4 0x0000000000c9382d in do_handle_one_connection (connect=0x1aa28f0c8, put_in_cache=true) at /home/dbdev/workspace/server/sql/sql_connect.cc:1416
#5 0x0000000000c935ad in handle_one_connection (arg=0x1aa28f0c8) at /home/dbdev/workspace/server/sql/sql_connect.cc:1318
#6 0x00000000011d4c83 in pfs_spawn_thread (arg=0x1aa290898) at /home/dbdev/workspace/server/storage/perfschema/pfs.cc:2201
#7 0x0000000005330b43 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#8 0x00000000053c1bb4 in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:100
(gdb) p thd->query_string
$1 = {string = {str = 0x1aa30bf20 "show tables", length = 11}, cs = 0x24cbda0 <my_charset_utf8mb3_general_ci>}
valgrind 配合 gdb 调试程序的更多相关文章
- 用GDB调试程序(一)
http://blog.csdn.net/haoel/article/details/2879 用GDB调试程序 GDB概述———— GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或 ...
- Linux下使用GDB调试程序
问题描述: Linux下使用GDB调试程序 问题解决: (1)生成调试文件 注: 使用命令 gdb IOStream.c -o IOStre ...
- 用gdb调试程序笔记: 以段错误(Segmental fault)为例
用gdb调试程序笔记: 以段错误(Segmental fault)为例[转] 1.背景介绍2.程序中常见的bug分类3.程序调试器(如gdb)有什么用4.段错误(Segmental fault)介绍5 ...
- 用GDB调试程序
转自:http://blog.csdn.net/haoel/article/details/2879 是一篇从基础讲gdb的博文 用GDB调试程序 GDB概述---- GDB是GNU开源组织发布的一个 ...
- gdb调试程序函数名为问号,什么原因?step by step解决方案
gdb调试程序函数名为问号,什么原因? http://bbs.chinaunix.net/thread-1823649-1-1.html http://www.bubuko.com/infodetai ...
- 用gdb调试程序(Linux环境)
一般来说,GDB主要帮忙你完成下面四个方面的功能: 1.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序. 2.可让被调试的程序在你所指定的调置的断点处停住.(断点可以是条件表达式) ...
- [Z] 用GDB调试程序
原文:http://blog.csdn.net/haoel/article/details/2879 用GDB调试程序 GDB概述———— GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工 ...
- 用 GDB 调试程序
Linux 包含了一个叫 gdb 的 GNU 调试程序. gdb 是一个用来调试 C 和 C++ 程序的强力调试器. 它使你能在程序运行时观察程序的内部结构和内存的使用情况. 以下是 gdb 所提供的 ...
- 转载 gdb调试程序
转载自csdn,作者haoel,链接http://blog.csdn.net/haoel/article/details/2879 用GDB调试程序 GDB概述———— GDB是GNU开源组织发布的一 ...
- Linux高级编程--04.GDB调试程序(查看数据)
查看栈信息 当程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的.当你的程序调用了一个函数,函数的地址,函数参数,函数内的局部变量都会被压入"栈"(Stack)中.你可以用 ...
随机推荐
- Kerberos协议原理
本文主要介绍Kerberos认证协议的原理以及解决了什么问题 Kerberos是什么 Kerberos是计算机网络世界中的一种身份认证协议. 身份认证是我们日常生活中经常进行的活动,比如我们要去银行取 ...
- JDBC-Utils层的简单运用
项目中JDBC的Utils层运行需要以下六个步骤 //1.定义属性为空 private static String driver = null; private static String url = ...
- 如何进行测试分析与设计-HTSM启发式测试策略模型 | 京东云技术团队
测试,没有分析与设计就失去了灵魂: 测试人员在编写用例之前,该如何进行测试分析与设计呢?上次在<测试的底层逻辑>中讲到了[输入输出测试模型],还讲到了[2W+1H测试分析法],但2W1H分 ...
- 一个.Net强大的Excel控件,支持WinForm、WPF、Android【强烈推荐】
推荐一个强大的电子表单控件,使用简单且功能强大. 项目简介 这是一个开源的表格控制组件,支持Winform.WPF和Android平台,可以方便的加载.修改和导出Excel文件,支持数据格式.大纲.公 ...
- Galaxy Project | 一些尝试与思考
很久都没有更新推文了,脑壳羞涩,快码不出字的节奏! 最近在尝试内部 Galaxy 一些新工具的开发和 Galaxy 核心版本的升级测试,发现一些问题,简单记录和聊一下吧. 一些尝试 对于在线的 web ...
- clusterProfiler 的 GO/KEGG 富集分析用法小结
以下文章来源于简书,作者 biobin,文章已获原作者授权. 前言 关于 clusterProfiler这个 R 包就不介绍了,网红教授宣传得很成功,功能也比较强大,主要是做 GO 和 KEGG 的功 ...
- Nginx 反向代理的配置和注意点(成功配置)
反向代理配置成功 首先,Nginx 和 Java 后端都运行在云服务器的 docker 容器中.ps: 需要确保云服务器端口正常开放,以及两个容器都能被正常的访问. 现在想让 ng 做反向代理达到如下 ...
- 安卓第一课:gradle仓库的导入
今天装好android studio,结果刚进入就报错了: SSL peer shut down incorrectly 读注释发现原来是gradle下载文件不成功.果然,原来是vpn掉线了,上网查了 ...
- 深入解析React DnD拖拽原理,轻松掌握拖放技巧!
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值.. 本文作者:霁明 一.背景 1.业务背景 业务中会有一些需要实现拖拽 ...
- Some book
## book [C++] Accelerated C++ C++ Primer 5th C++ 程序设计语言: 1 ~ 3 C++ 程序设计语言: 4 C++ 编程思想 C++ 标准库 2th C+ ...