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)中.你可以用 ...
随机推荐
- docker无法启动,报错grpc: addrConn.createTransport failed to connect to {unix:///run/containerd/containerd.
docker无法启动,报错.k8s的pod镜像加载失败. 解法方法: 删除/var/lib/docker/和/var/lib/containerd/ 这两个文件夹,重起docker服务. 问题完美解决 ...
- 2021-10-01:矩阵置零。给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。进阶:一个直观的解决方案是使用 O(mn) 的额外空间
2021-10-01:矩阵置零.给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 .请使用 原地 算法.进阶:一个直观的解决方案是使用 O(mn) 的额外空间, ...
- macOS下由yarn与npm差异引发的Electron镜像地址读取问题
记录macOS下由yarn与npm差异引发的Electron镜像地址读取问题 写在前面:该问题仅仅出现在Linux和macOS上,Windows上不存在该问题! 初始背景 最近笔者重新拾起了Elect ...
- Error: Cannot find module ‘webpack-cli/bin/config-yargs‘
今配置一个webpack-dev-server进行服务端渲染时老是不正确 npm run dev 就崩了 起初的配置为 "devDependencies": { "web ...
- 源码解析:数据批量导入bukl_crete()原理
在Django中需要向数据库中插入多条数据(list).使用如下方法,每次save()的时候都会访问一次数据库.导致性能问题: for i in resultlist: p = Account(nam ...
- Python连接es笔记三之es更新操作
本文首发于公众号:Hunter后端 原文链接:Python连接es笔记三之es更新操作 这一篇笔记介绍如何使用 Python 对数据进行更新操作. 对于 es 的更新的操作,不用到 Search() ...
- MySQL读取的记录和我想象的不一致
摘要:并发的事务在运行过程中会出现一些可能引发一致性问题的现象,本篇将详细分析一下. 本文分享自华为云社区<MySQL读取的记录和我想象的不一致--事物隔离级别和MVCC>,作者:砖业洋_ ...
- 【HarmonyOS】HarmonyOS应用APP与HAP包签名信息查看方法
HarmonyOS可以通过DevEco Studio 构建对应的APP包或者是HAP包,对于签名我们有两种方式: DevEco Studio提供了根据开发者信息生成自动调试签名的能力方便各位开发者进 ...
- 前端vue单个文件上传支持图片,压缩包以及文件 , 下载完整代码请访问uni-app插件市场址:https://ext.dcloud.net.cn/plugin?id=13066
前端vue单个文件上传支持图片,压缩包以及文件 , 下载完整代码请访问uni-app插件市场址:https://ext.dcloud.net.cn/plugin?id=13066 效果图如下: 使用方 ...
- synchronized中wait、notify的原理与源码
synchronized中wait.notify的原理与源码 1.wait和notify的流程图 2.JVM源码 java层面wait的方法 public final native void wait ...