返回介绍

4.5 使用动态分析来检测内存缺陷

发布于 2025-05-06 21:45:55 字数 4025 浏览 0 评论 0 收藏

NOTE : 此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-04/recipe-05 中找到,包含一个 C++的示例。该示例在 CMake 3.5 版(或更高版本) 中是有效的,并且已经在 GNU/Linux、macOS 和 Windows 上进行过测试。

内存缺陷:写入或读取越界,或者内存泄漏(已分配但从未释放的内存),会产生难以跟踪的 bug,最好尽早将它们检查出来。Valgrind( http://valgrind.org ) 是一个通用的工具,用来检测内存缺陷和内存泄漏。本节中,我们将在使用 CMake/CTest 测试时使用 Valgrind 对内存问题进行警告。

准备工作

对于这个配置,需要三个文件。第一个是测试的实现(我们可以调用文件 leaky_implementation.cpp ):

#include "leaky_implementation.hpp"
​
int do_some_work() {
​
  // we allocate an array
  double *my_array = new double[1000];
​
  // do some work
  // ...
​
  // we forget to deallocate it
  // delete[] my_array;
​
  return 0;
}

还需要相应的头文件( leaky_implementation.hpp ):

#pragma once
​
int do_some_work();

并且,需要测试文件( test.cpp ):

#include "leaky_implementation.hpp"
​
int main() {
  int return_code = do_some_work();
​
  return return_code;
}

我们希望测试通过,因为 return_code 硬编码为 0 。这里我们也期望检测到内存泄漏,因为 my_array 没有释放。

具体实施

下面展示了如何设置 CMakeLists.txt 来执行代码动态分析:

  1. 我们首先定义 CMake 最低版本、项目名称、语言、目标和依赖关系:
    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    ​
    project(recipe-05 LANGUAGES CXX)
    ​
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_EXTENSIONS OFF)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    ​
    add_library(example_library leaky_implementation.cpp)
    ​
    add_executable(cpp_test test.cpp)
    target_link_libraries(cpp_test example_library)
  2. 然后,定义测试目标,还定义了 MEMORYCHECK_COMMAND :
    find_program(MEMORYCHECK_COMMAND NAMES valgrind)
    set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full")
    ​
    # add memcheck test action
    include(CTest)
    ​
    enable_testing()
    ​
    add_test(
      NAME cpp_test
      COMMAND $<TARGET_FILE:cpp_test>
      )
  3. 运行测试集,报告测试通过情况,如下所示:
    $ ctest
    ​
    Test project /home/user/cmake-recipes/chapter-04/recipe-05/cxx-example/build
    Start 1: cpp_test
    1/1 Test #1: cpp_test ......................... Passed 0.00 sec
    100% tests passed, 0 tests failed out of 1
    Total Test time (real) = 0.00 sec
  4. 现在,我们希望检查内存缺陷,可以观察到被检测到的内存泄漏:
    $ ctest -T memcheck
    ​
    Site: myhost
    Build name: Linux-c++
    Create new tag: 20171127-1717 - Experimental
    Memory check project /home/user/cmake-recipes/chapter-04/recipe-05/cxx-example/build
    Start 1: cpp_test
    1/1 MemCheck #1: cpp_test ......................... Passed 0.40 sec
    100% tests passed, 0 tests failed out of 1
    Total Test time (real) = 0.40 sec
    -- Processing memory checking output:
    1/1 MemCheck: #1: cpp_test ......................... Defects: 1
    MemCheck log files can be found here: ( * corresponds to test number)
    /home/user/cmake-recipes/chapter-04/recipe-05/cxx-example/build/Testing/Temporary/MemoryChecker.*.log
    Memory checking results:
    Memory Leak - 1
  5. 最后一步,应该尝试修复内存泄漏,并验证 ctest -T memcheck 没有报告错误。

工作原理

使用 find_program(MEMORYCHECK_COMMAND NAMES valgrind) 查找 valgrind,并将 MEMORYCHECK_COMMAND 设置为其绝对路径。我们显式地包含 CTest 模块来启用 memcheck 测试操作,可以使用 CTest -T memcheck 来启用这个操作。此外,使用 set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full") ,将相关参数传递给 Valgrind。内存检查会创建一个日志文件,该文件可用于详细记录内存缺陷信息。

NOTE : 一些工具,如代码覆盖率和静态分析工具,可以进行类似地设置。然而,其中一些工具的使用更加复杂,因为需要专门的构建和工具链。Sanitizers 就是这样一个例子。有关更多信息,请参见 https://github.com/arsenm/sanitizers-cmake 。另外,请参阅第 14 章,其中讨论了 AddressSanitizer 和 ThreadSanitizer。

更多信息

该方法可向测试面板报告内存缺陷,这里演示的功能也可以独立于测试面板使用。我们将在第 14 章中重新讨论,与 CDash 一起使用的情况。

有关 Valgrind 及其特性和选项的文档,请参见 http://valgrind.org

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。