目录
(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).对未保留的线程本地存储槽的访问.
(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
- 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> ["
/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> ["
/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> ["
/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] 随机算法的随机化种子
-check_bounds
:检测内存越界。-check_invalid_pointer_write
:检测无效指针写操作。(1)生成的报告结果存放在解压缩后drmemory/logs目录下,目录名方式为:DrMemory-
(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等关键字可快速定位问题。
Dr. Memory 的输出信息包含了应用程序中的内存错误和调试信息。以下是一些常见的输出信息:
ERROR
:表示应用程序中存在内存错误。WARNING
:表示应用程序中存在潜在的内存错误。INFO
:表示应用程序的调试信息。- 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"
-
-