在实际研发过程中,可能会遇到过这样的问题:测试通过 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. 2020-11-25:go中,map的底层数据结构是什么?

    福哥答案2020-11-25: 简单回答:hmap映射头.bmap桶.mapextra溢出额外信息 中级回答: // 映射头 type hmap struct { // Note: the forma ...

  2. 2021-01-18:java中,HashMap的创建流程是什么?

    福哥答案2021-01-18: jdk1.7创建流程:三种构造器.1.初始容量不能为负数,默认16.2.初始容量大于最大容量时,初始容量等于最大容量.3.负载因子必须大于0,默认0.75.4.根据初始 ...

  3. 初等数论——素数,逆元,EXGCD有关

    初等数论 素数定义 设整数 \(p\ne 0,\pm 1\) .如果 \(p\) 除了平凡约数以外没有其他约数,那么称 \(p\) 为素数(不可约数). 若整数 \(a\ne 0,\pm 1\) 且 ...

  4. 深度学习基础入门篇[8]::计算机视觉与卷积神经网络、卷积模型CNN综述、池化讲解、CNN参数计算

    深度学习基础入门篇[8]::计算机视觉与卷积神经网络.卷积模型CNN综述.池化讲解.CNN参数计算 1.计算机视觉与卷积神经网络 1.1计算机视觉综述 计算机视觉作为一门让机器学会如何去"看 ...

  5. nc工具利用

    c: 瑞士军刀/网络测评工具    将本地的cmd 权限移交到外网 nc工具:应用    本地cmd打开, 输入  nc -e cmd 远程ip  5577  #连接到远程ip的5577 远程cmd打 ...

  6. 数据库SQL复习

    数据库SQL介绍 Def:SQL是一种极其高效的数据库系统语言:可以实现对数据库中的数据进行增删改查等操作 增加操作:使用create命令: 可以create table 可以create View ...

  7. 如何使用 Megatron-LM 训练语言模型

    在 PyTorch 中训练大语言模型不仅仅是写一个训练循环这么简单.我们通常需要将模型分布在多个设备上,并使用许多优化技术以实现稳定高效的训练.Hugging Face  Accelerate 的创建 ...

  8. 【python基础】复杂数据类型-列表类型(排序/长度/遍历)

    1.列表数据元素排序 在创建的列表中,数据元素的排列顺序常常是无法预测的.这虽然在大多数情况下都是不可避免的,但经常需要以特定的顺序呈现信息.有时候希望保留列表数据元素最初的排列顺序,而有时候又需要调 ...

  9. 如何让别人访问你本地允许的Vue本地项目

    步骤一: 将config/index.js  中的host: localhost    改为   host:'0.0.0.0'步骤二:在package.json  将scripts 下面的dev  后 ...

  10. Spring Boot实现高质量的CRUD-1

    1.前言 ​ 在Spring Boot的SMM框架(SpringBoot+Mysql+Mybatis)的WEB项目中,CRUD(增删改查)大致占了50%-70%左右的工作量.提高CRUD的代码质量,提 ...