目录
一、使用前的澄清
二、下载地址
三、功能概述
四、 使用方法与步骤
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
:表示应用程序的调试信息。