在实际研发过程中,可能会遇到过这样的问题:测试通过 valgrind 验证当前代码存在变量未初始化的问题,但仅通过 valgrind 测试报告,研发无法确认具体的应用场景。本文将通过 valgrind 检测并定位程序中变量未初始化的问题,并给出用户具体的操作场景。

前言

为保证程序的健壮性和可靠性,程序在完成基本的功能测试后,一般来说还要进行内存使用相关的测试。Valgrind 是一个强大的 C 和 C++ 程序调试和性能分析工具。它可以检测内存泄漏、未初始化的内存使用以及其他各种错误。本文将以 MariaDB 为例,通过 valgrind 检测并定位程序中变量未初始化的问题。

使用 valgrind 检测程序错误

  1. 为说明问题,在 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");
}
  1. 使用 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 &
  1. 登录 MariaDB server
/home/dbdev/mariadb/bin/mysql -S /home/dbdev/mariadb/data/mysqld.sock
  1. 执行如下 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)
  1. 查看 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

  1. 开启终端 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 &
  1. 开启终端 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)
  1. 终端 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==
  1. 将 "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
  1. 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.
  1. T1 登录 MariaDB 实例,执行如下 SQL 语句,该操作会激活 T2 的 gdb 断点
MariaDB [(none)]> use test

  1. 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 调试程序的更多相关文章

  1. 用GDB调试程序(一)

    http://blog.csdn.net/haoel/article/details/2879 用GDB调试程序 GDB概述———— GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具.或 ...

  2. Linux下使用GDB调试程序

    问题描述:          Linux下使用GDB调试程序 问题解决:          (1)生成调试文件 注:         使用命令   gdb IOStream.c   -o IOStre ...

  3. 用gdb调试程序笔记: 以段错误(Segmental fault)为例

    用gdb调试程序笔记: 以段错误(Segmental fault)为例[转] 1.背景介绍2.程序中常见的bug分类3.程序调试器(如gdb)有什么用4.段错误(Segmental fault)介绍5 ...

  4. 用GDB调试程序

    转自:http://blog.csdn.net/haoel/article/details/2879 是一篇从基础讲gdb的博文 用GDB调试程序 GDB概述---- GDB是GNU开源组织发布的一个 ...

  5. gdb调试程序函数名为问号,什么原因?step by step解决方案

    gdb调试程序函数名为问号,什么原因? http://bbs.chinaunix.net/thread-1823649-1-1.html http://www.bubuko.com/infodetai ...

  6. 用gdb调试程序(Linux环境)

    一般来说,GDB主要帮忙你完成下面四个方面的功能: 1.启动你的程序,可以按照你的自定义的要求随心所欲的运行程序.    2.可让被调试的程序在你所指定的调置的断点处停住.(断点可以是条件表达式)   ...

  7. [Z] 用GDB调试程序

    原文:http://blog.csdn.net/haoel/article/details/2879 用GDB调试程序 GDB概述———— GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工 ...

  8. 用 GDB 调试程序

    Linux 包含了一个叫 gdb 的 GNU 调试程序. gdb 是一个用来调试 C 和 C++ 程序的强力调试器. 它使你能在程序运行时观察程序的内部结构和内存的使用情况. 以下是 gdb 所提供的 ...

  9. 转载 gdb调试程序

    转载自csdn,作者haoel,链接http://blog.csdn.net/haoel/article/details/2879 用GDB调试程序 GDB概述———— GDB是GNU开源组织发布的一 ...

  10. Linux高级编程--04.GDB调试程序(查看数据)

    查看栈信息 当程序被停住了,你需要做的第一件事就是查看程序是在哪里停住的.当你的程序调用了一个函数,函数的地址,函数参数,函数内的局部变量都会被压入"栈"(Stack)中.你可以用 ...

随机推荐

  1. 2022-08-24:给定一个长度为3N的数组,其中最多含有0、1、2三种值, 你可以把任何一个连续区间上的数组,全变成0、1、2中的一种, 目的是让0、1、2三种数字的个数都是N。 返回最小的变化次

    2022-08-24:给定一个长度为3N的数组,其中最多含有0.1.2三种值, 你可以把任何一个连续区间上的数组,全变成0.1.2中的一种, 目的是让0.1.2三种数字的个数都是N. 返回最小的变化次 ...

  2. 2022-03-18:arr数组长度为n, magic数组长度为m 比如 arr = { 3, 1, 4, 5, 7 },如果完全不改变arr中的值, 那么收益就是累加和 = 3 + 1 + 4 +

    2022-03-18:arr数组长度为n, magic数组长度为m 比如 arr = { 3, 1, 4, 5, 7 },如果完全不改变arr中的值, 那么收益就是累加和 = 3 + 1 + 4 + ...

  3. vue全家桶进阶之路18:Vue Router

    Vue Router 是 Vue.js 的官方路由管理器,它可以帮助我们实现单页应用(Single Page Application,SPA)的前端路由. Vue Router 基于 Vue.js 的 ...

  4. 【GiraKoo】C++多线程消息分发架构

    [开源需求]C++多线程消息分发架构 项目[gi_messager] 在多线程环境中,为每个线程提供独立的消息队列 MessageLoop.注:主线程默认自动创建消息队列. MessageLoopCe ...

  5. 一次redis主从切换导致的数据丢失与陷入只读状态故障

    背景 最近一组业务redis数据不断增长需要扩容内存,而扩容内存则需要重启云主机,在按计划扩容升级执行主从切换时意外发生了数据丢失与master进入只读状态的故障,这里记录分享一下. 业务redis高 ...

  6. Kubernetes 架构原则和对象设计

    Kubernet¶ Kubernetes 架构原则和对象设计¶ 什么是云计算¶ 云计算平台的分类¶ 以Openstack为典型的虚拟化平台 虚拟机构建和业务代码部署分离. 可变的基础架构使后续维护风险 ...

  7. 计算机网络 vlan

    目录 一.vlan的概念 二.vlan的优势 三.vlan的种类 四.静态vlan的配置 五.trunk的概念和配值 六.实验 一.vlan的概念 在传统的以太网中,所有的用户都是同一个广播域,当数据 ...

  8. Redash 可视化BI系统部署安装及简单使用

    这篇文章主要为介绍一下Redash的使用和安装 概览 Redash 主要使用的语言为 Python 和 TypeScript 这个安装主要是基于Docker 来安装的,官网教程基本没有不是基于Dock ...

  9. Firefox Quantum 向左,Google Chrome 向右

    今天,又重新安装了一下 Firefox Quantum-68.0 (64 位),不同的是这一次安装的是国际中文版,而不是北京谋智火狐的版本. 北京谋智火狐 国际中文版 总的来说,有几点体验: 在 ht ...

  10. 基于Microsoft SEAL 同态加密场景特性

    基于Microsoft SEAL 同态加密场景特性 同态加密是一种特殊的加密技术,它允许在加密状态下进行计算操作而无需解密数据.在传统的加密算法中,对加密的数据进行运算操作通常需要先解密数据,然后再进 ...