[QT编程系列-45]: 内存检测工具Dr.Memory在Windows上的使用实践与详解

目录

一、使用前的澄清

二、下载地址

三、功能概述

四、 使用方法与步骤

4.1 常见命令

4.2 命令选项详解

4.3 常见问题监测

4.3.1 内存泄露相关参数

4.4 结果输出参数

4.5 输出分析


一、使用前的澄清

(1)之前在https://blog.csdn.net/fengbingchun/article/details/51626705 中介绍过Dr.Memory,那时在Windows上还不支持x64,最新的版本对x64已有了支持。

(2)Dr.Memory支持Windows和Linux

(3)Dr.Memory是命令行工具,不是图形化工具

(4)Dr. Memory 只能检测到应用程序运行时出现的内存错误,无法检测到编译时错误。

(5)在使用 Dr. Memory 时,建议先备份应用程序,以防止误操作导致数据丢失。

二、下载地址

github官网:https://github.com/DynamoRIO/drmemory

csnd:https://download.csdn.net/download/guojiwu001/11978661

License为LGPL。它支持Windows、Linux、Mac和Android平台。

三、功能概述

      Dr.Memory是一种内存监视工具,能够识别与内存相关的编程错误,例如:

      (1).访问未初始化的内存;

      (2).访问不可寻址(unaddressable)的内存(heap underflow and overflow);

      (3).访问释放的内存;

      (4).double free;

      (5).内存泄漏;

      (6).Windows上的:句柄泄漏(handle leaks)、GDI API使用错误;

      (7).对未保留的线程本地存储槽的访问.

四、 使用方法与步骤

4.1 常见命令

(1)通过执行drmemory.exe --help 可查看支持哪些输入参数

(2)执行方式: drmemory.exe [options] -- <app and args to run>

        待检测的可执行程序需要在Debug模式下,虽然在Release模式下也能运行有结果,但是会存在很多误导信息;

命令案例:

E:\test\test_gtest\DrMemory-Windows-2.5.19327\bin64>drmemory.exe -visual_studio -logdir "../../../tmp"  -- ../../../../GitCode/Messy_Test/lib/dbg/x64_vc12/Test.exe

4.2 命令选项详解

Dr. Memory 选项(使用 -no_<opt> 来禁止布尔值):
-version                          [ false] 显示 Dr. Memory 版本
-help                             [ false] 显示选项列表
-dr <string>                      [    ""] 指定 DynamoRIO 安装路径
-drmemory <string>                [    ""] 指定 Dr. Memory 安装路径
-top_stats                        [ false] 显示整个进程运行时间和内存使用情况
-fetch_symbols                    [ false] 在运行结束时获取缺失的符号文件
-follow_children                  [  true] 监控子进程
-nudge <int>                      [     0] 要唤醒的进程ID
-v                                [ false] 在Dr. Memory前端显示详细信息
-light                            [ false] 启用轻量级模式,仅检测关键错误
-brief                            [ false] 显示简化并易于阅读的错误报告
-visual_studio                    [ false] 产生Visual Studio外部工具输出
-logdir <string>                  ["<install>/logs"] 结果文件子目录和符号缓存的基本目录
-verbose <int>                    [     1] 日志文件中的详细程度
-quiet                            [ false] 抑制stderr消息和结果
-results_to_stderr                [  true] 除了将错误报告写入结果文件以外,还将其打印到stderr中
-prefix_style <int>               [     0] 调整每行的默认输出前缀
-log_suppressed_errors            [ false] 记录抑制的错误报告以进行后处理。
-ignore_asserts                   [ false] 在调试编译中不中断断言
-exit_code_if_errors <int>        [     0] 如果找到错误,则更改应用程序的退出代码为此代码
-pause_at_error                   [ false] 在任何类型的报告错误时暂停
-pause_at_unaddressable           [ false] 在每个不可访问的访问处暂停
-pause_at_uninitialized           [ false] 在每个未初始化的读取处暂停
-pause_at_exit                    [ false] 在进程退出时暂停
-pause_at_assert                  [ false] 在每个调试构建断言处暂停
-pause_via_loop                   [ false] 通过循环暂停(不等待标准输入)
-crash_at_unaddressable           [ false] 在第一个不可访问的访问处崩溃
-crash_at_error                   [ false] 在第一个报告的任何类型的错误处崩溃
-dump_at_error_mask <int>         [     0] 在指定的错误处创建内存转储文件
-dump_at_unaddressable            [ false] 在不可访问的位置处创建内存转储文件
-callstack_max_frames <int>       [    20] 记录的最大调用堆栈帧数
-malloc_max_frames <int>          [    12] 每个malloc记录的调用堆栈帧数
-free_max_frames <int>            [     6] 每个free记录的调用堆栈帧数
-callstack_style <int>            [0x0301] 控制调用堆栈打印样式的一组标志
-callstack_truncate_below <string>["main,wmain,WinMain,wWinMain,*RtlUserThreadStart,_threadstartex,BaseThreadInitThun    k"] 要在其处截断调用堆栈的函数名称列表,以逗号分隔
-callstack_modname_hide <string>  ["drmemory"] 调用堆栈帧中要隐藏的模块名称列表,以逗号分隔
-callstack_exe_hide               [  true] 从调用堆栈帧中省略可执行文件名称
-callstack_srcfile_hide <string>  [    ""] 要在调用堆栈帧中隐藏的源文件路径列表,以逗号分隔
-callstack_srcfile_prefix <string>[    ""] 要删除的路径前缀的列表,以逗号分隔
-lib_blocklist_default <string>   [    ""] 要将其视为非应用程序库的路径模式基础列表
-lib_blocklist <string>           [    ""] 要将其视为非应用程序库的路径模式列表
-lib_blocklist_frames <int>       [     4] 与 -lib_blocklist 匹配的帧数
-lib_allowlist <string>           [    ""] 要为其报告错误的路径模式列表
-lib_allowlist_frames <int>       [     4] 与之匹配的帧数
-src_allowlist <string>           [    ""]  :在报告错误时,使用逗号分隔的源模式列表。
-src_allowlist_frames <int>       [     4]  :与-src_allowlist匹配的帧数。
-check_uninit_blocklist <string>  [    ""]  :在其中不检查uninit的模块基本名称的逗号分隔列表。
-callstack_use_unwind             [ false]  :使用取消信息来遍历调用栈。
-callstack_use_top_fp             [  true]  :使用顶层ebp / rbp寄存器作为第一个帧指针。
-callstack_use_top_fp_selectively [  true]  :在某些情况下使用顶层ebp / rbp寄存器作为第一个帧指针。
-callstack_use_fp                 [  true]  :使用帧指针来遍历调用栈。
-callstack_conservative           [ false]  :执行额外的检查以进行更准确的调用堆栈。
-callstack_max_scan <int>         [  4096]  :扫描以定位第一个或下一个堆栈帧的距离。
-callstack_bad_fp_list <string>   [    ""]  :路径模式的逗号分隔列表,其中帧指针不可信。
-check_leaks                      [  true]  :列出检测到的内存泄漏的详细信息。
-count_leaks                      [  true]  :查找内存泄漏。
-symbol_offsets                   [ false]  :已弃用:使用-callstack_style标志0x4
-ignore_early_leaks               [  true]  :忽略应用程序之前的泄漏。
-check_leaks_on_destroy           [  true]  :在堆破坏时报告泄漏。
-possible_leaks                   [  true]  :显示可能泄漏的调用堆栈。
-check_encoded_pointers           [  true]  :检查编码指针。
-midchunk_size_ok                 [  true]  :将中间块后大小指针视为合法。
-midchunk_new_ok                  [  true]  :将中间块后new []头指针视为合法。
-midchunk_inheritance_ok          [  true]  :将中间块多继承指针视为合法。
-midchunk_string_ok               [  true]  :将中间块std :: string指针视为合法。
-scan_read_only_files             [ false]  :内存泄漏扫描是否应扫描只读文件映射的内存。
-strings_vs_pointers              [  true]  :使用启发式方法排除子字符串作为泄漏扫描指针。
-show_reachable                   [ false]  :列出可到达的分配。
-suppress <string>                [    ""]  :包含要抑制的错误的文件。
-default_suppress                 [  true]  :使用默认抑制集。
-gen_suppress_offs                [  true]  :在输出抑制文件中生成mod + offs抑制。
-gen_suppress_syms                [  true]  :在输出抑制文件中生成mod!syms抑制。
-show_threads                     [  true]  :打印每个错误引用的线程创建点的调用堆栈。
-show_all_threads                 [ false]  :打印每个线程创建点的调用堆栈。
-conservative                     [ false]  :保守阅读应用程序内存并假定死亡reg。
-check_uninit_cmps                [  true]  :检查比较指令的定义。
-check_uninit_non_moves           [ false]  :检查所有非移动指令的定义。
-check_uninit_all                 [ false]  :检查所有指令的定义。
-strict_bitops                    [ false]  :完全检查位操作的定义。
-check_pc                         [  true]  :检查程序计数器是否存在无地址执行。
-stack_swap_threshold <int>       [0x9000]  :堆栈更改量以考虑交换
-redzone_size <int>               [    16]  :每个malloc的两侧缓冲区。
-report_max <int>                 [ 20000]  :最大的非泄漏错误报告(-1 =无限制)。
-report_leak_max <int>            [ 10000]  :最多泄漏报告(-1 =无限制)。
-report_write_to_read_only        [  true]  :将写入只读内存的操作报告为无地址错误。
-show_duplicates                  [ false]  :打印每个重复错误的详细信息。
-batch                            [ false]  :不要在结束时调用记事本。
-summary                          [  true]  :在stderr中显示结果摘要。
-use_symcache                     [  true]  :缓存符号结果
-symcache_dir <string>            ["<install>/logs/symcache"]  用于符号缓存文件的目录
-symcache_minsize <int>           [  1000]  用于缓存符号的最小模块大小
-use_symcache_postcall            [  true]  缓存 post-call 位置以加快未来的运行速度
-preload_symbols                  [ false]  在模块加载时预加载调试符号
-skip_msvc_importers              [  true]  不搜索导入了 msvc* 的模块中的 alloc 例程
-warn_null_ptr                    [ false]  报告向 free/realloc 传递 NULL 的情况
-delay_frees <int>                [  2000]  延迟释放的次数
-delay_frees_maxsz <int>          [20000000]  延迟释放的最大大小
-delay_frees_stack                [  true]  在释放时记录调用栈用于报告 use-after-free
-leaks_only                       [ false]  仅检查泄漏而不是内存访问错误
-handle_leaks_only                [ false]  仅检查 handle 泄漏错误而不是其他错误
-check_uninitialized              [  true]  检查未初始化的读取错误
-check_stack_bounds               [ false]  对于 -no_check_uninitialized,是否检查堆栈顶部之外的访问
-check_stack_access               [ false]  对于 -no_check_uninitialized,是否检查堆栈或框架引用上的错误
-check_alignment                  [ false]  对于 -no_check_uninitialized,是否考虑对齐
-fault_to_slowpath                [  true]  对于 -no_check_uninitialized,使用 faults 做慢速路径退出
-check_gdi                        [  true]  检查 GDI API 使用错误
-check_gdi_multithread            [ false]  检查一个 DC 被多个线程使用的 GDI API 使用错误
-check_handle_leaks               [  true]  检查 handle 泄漏错误
-check_heap_mismatch              [  true]  是否检查 Windows API 与 C 库的不匹配
-check_delete_mismatch            [  true]  是否检查 free/delete/delete[] 的不匹配
-check_prefetch                   [  true]  是否将不可寻址的 prefetch 报告为警告
-malloc_callstacks                [ false]  在 allocs 时记录调用栈用于报告不匹配
-prctl_allowlist <string>         [    ""]  禁用检测除非 PR_SET_NAME 在列表中
-auxlib <string>                  [    ""]  加载辅助系统调用处理库
-analyze_unknown_syscalls         [  true]  对于未知的系统调用,使用内存比较查找输出参数
-syscall_dword_granularity        [  true]  对于未知系统调用比较,使用 dword 粒度
-syscall_sentinels                [ false]  使用 sentinel 检测未知 syscall 的写入
-prefer_msize                     [  true]  当两者都存在时,优先使用 _msize 而不是 malloc_usable_size
-perturb                          [ false]  打乱线程调度以提高捕获 races 的机会
-perturb_only                     [ false]  打乱线程调度但禁用内存检查
-perturb_max <int>                [    50]  -perturb 增加的最大延迟
-perturb_seed <int>               [     0]  用于 -perturb 的随机延迟种子
-unaddr_only                      [ false]  启用仅检测 unaddressable 错误的轻量级模式
-pattern <int>                    [     0]  启用 pattern 模式,必须提供非零的两字节值
-persist_code                     [ false]  缓存经过仪器化的代码以加速未来运行(仅限轻量级模式)
-persist_dir <string>             ["<install>/logs/codecache"]  用于代码缓存文件的目录
-soft_kills                       [  true]  确保这个进程结束外部进程时干净地退出
-ignore_kernel                    [ false]  在不支持的内核上尝试
use_syscall_tables                [  true]  使用Dr. Memory自己的系统调用表(在可能的情况下)
-syscall_number_path <string>     [    ""]  指向包含系统调用编号文件的目录
-coverage                         [ false]  测量并提供代码覆盖信息
-fuzz                             [ false]  启用Dr. Memory 的模糊测试
-fuzz_module <string>             [    ""]  模糊测试目标模块的名称。默认情况下使用应用程序主可执行文件。
-fuzz_function <string>           ["DrMemFuzzFunc"]  模糊测试目标函数符号名称。默认情况下使用DrMemFuzzFunc。
-fuzz_offset <int>                [     0]  模糊测试目标函数在模块中的偏移量。
-fuzz_num_args <int>              [     2]  传递给模糊测试目标函数的参数数量。
-fuzz_data_idx <int>              [     0]  模糊测试数据参数的索引。
-fuzz_size_idx <int>              [     1]  模糊测试数据大小参数的索引。
-fuzz_num_iters <int>             [   100]  重复执行目标函数的次数。
-fuzz_replace_buffer              [ false]  用单独分配的内存替换输入数据缓冲区。
-fuzz_call_convention <string>    [    ""]  模糊测试目标函数使用的调用约定。
可能的调用约定代码为:
arm32    = ARM32
amd64    = AMD64
fastcall = fastcall
ms64     = Microsoft x64 (Visual Studio)
stdcall  = cdecl 或 stdcall
thiscall = thiscall
-fuzz_dump_on_error               [  true]  在出现错误报告时将当前模糊测试输入转储到当前日志目录。
-fuzz_input_file <string>         [    ""]  从指定文件中加载数据作为模糊测试输入。
-fuzz_corpus <string>             [    ""]  加载一个数据文件语料库并执行基于代码覆盖率的模糊测试。
-fuzz_corpus_out <string>         [    ""]  创建和存储从-fuzz_corpus 到 -fuzz_corpus_out 最小化的数据文件语料库输入
-fuzz_coverage                    [ false]  启用基本块代码覆盖率引导的模糊测试。
-fuzz_target <string>             [    ""]  根据指定的描述符对目标程序进行模糊测试
模糊描述符格式:<target>|<arg-count>|<buffer-index>|<size-index>|<repeat-count>[|<calling-convention>]
其中,<target> 是以下之一:
<module>!<symbol>
<module>+<offset>
<arg-count> 指定函数的参数数量(对于变量参数函数,这必须与应用程序传递的实际参数数量相匹配)。
< *-index> 参数指定目标函数中相应参数的索引。 <repeat-count> 指示重复目标函数的次数(使用0不重复和无变异,使用-1重复,直到变异器耗尽。别名<main>可被给出作为<module>指的是程序的主模块。
调用约定代码为:
1 = AMD64
2 = Microsoft x64 (Visual Studio)
3 = ARM32
4 = cdecl 或 stdcall
5 = fastcall
6 = thiscall

-fuzz_mutator_lib <string>        [    ""]  指定自定义的第三方变异器库
-fuzz_mutator_ops <string>        [    ""]  指定变异器选项
-fuzz_mutator_alg <string>        ["ordered"]  指定变异器算法:“random”或“ordered”
-fuzz_mutator_unit <string>       ["bits"]  指定变异器单元:“bits”或“num”
-fuzz_mutator_flags <int>         [     1]  指定变异器标志
-fuzz_mutator_sparsity <int>      [     1]  在变异之间跳过的值
-fuzz_mutator_max_value <int>     [     0]  <8字节缓冲区的最大突变值(0为无限制)
-fuzz_mutator_random_seed <int>   [0x5a8390e9a31dc65fULL]  随机算法的随机化种子

4.3 常见问题监测

4.3.1 内存泄露相关参数

  • -check_leaks                           [  true]  :列出检测到的内存泄漏的详细信息
  • -count_leaks                            [  true]  :查找内存泄漏
  • -ignore_early_leaks                 [  true]  :忽略应用程序之前的泄漏。
  • -check_leaks_on_destroy        [  true]  :在堆破坏时报告泄漏
  • -possible_leaks                        [  true]  :显示可能泄漏的调用堆栈
  • -report_leak_max <int>            [ 10000]  :最多泄漏报告(-1 =无限制)。
  • -leaks_only                               [ false]  仅检查泄漏而不是内存访问错误
  • -handle_leaks_only                  [ false]  仅检查 handle 泄漏错误而不是其他错误
  • -check_handle_leaks               [  true]  检查 handle 泄漏错误
  • -check_bounds:检测内存越界。
  • -check_invalid_pointer_write:检测无效指针写操作。

4.4 结果输出参数

(1)生成的报告结果存放在解压缩后drmemory/logs目录下,目录名方式为:DrMemory-<appname>.<pid>.NNN目录的results.txt文件中, NNN是一个递增计数器,以确保名称唯一;

(2)-light: 默认关闭,开启后只检测验证错误的轻量级模式;

(3)-brief: 默认关闭,开启后显示简化且易于阅读的错误报告;

(4)-visual_studio: 默认关闭,开启后直接在终端上显示报告,不会主动打开results.txt文件

(5)-logdir: 指定输出结果存放的目录,使用此参数经常会有问题,弹出异常对话框;关闭此对话框,会继续执行;当再此执行时一般又会正常.

(6)数据结果文件:results.txt

案例:测试代码还是采用之前的,执行命令如下:

E:\test\test_gtest\DrMemory-Windows-2.5.19327\bin64>drmemory.exe -visual_studio -logdir "../../../tmp"  -- ../../../../GitCode/Messy_Test/lib/dbg/x64_vc12/DrMemoryTest.exe

执行结果如下所示:执行完后,会在../../../tmp目录下生成类似DrMemory-DrMemoryTest.exe.5112.000的目录,打开里面的results.txt文件,最后部分内容如下:通过搜索unaddressable、uninitialized、leak等关键字可快速定位问题。

4.5 输出分析

Dr. Memory 的输出信息包含了应用程序中的内存错误和调试信息。以下是一些常见的输出信息:

  • ERROR:表示应用程序中存在内存错误。
  • WARNING:表示应用程序中存在潜在的内存错误。
  • INFO:表示应用程序的调试信息。

4.6 案例

cd E:\3MySourceRef\3KL\test\

C:\Users\admin\Downloads\DrMemory-Windows-2.2.0-1\bin\drmemory.exe -check_leaks -ignore_kernel -logdir ".\log" -- ".\LWIM\LWIM.exe" 


C:\Users\admin\Downloads\DrMemory-Windows-2.2.0-1\bin\drmemory.exe -check_leaks -ignore_kernel -logdir ".\log" -leaks_only -- ".\LWIM\LWIM.exe" 


  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文火冰糖的硅基工坊

你的鼓励是我前进的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值