<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 14.3 使用AddressSanifier向CDash報告內存缺陷 **NOTE**:*此示例代碼可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-14/recipe-03 中找到,其中包含一個C++示例和一個Fortran例子。該示例在CMake 3.5版(或更高版本)中是有效的,并且已經在GNU/Linux、macOS和Windows上進行過測試。* AddressSanitizer(ASan)是可用于C++、C和Fortran的內存檢測。它可以發現內存缺陷,比如:在空閑后使用、返回后使用、作用域后使用、緩沖區溢出、初始化順序錯誤和內存泄漏(請參見 https://github.com/google/sanitizers/wiki/AddressSanitizer )。從3.1版本開始,AddressSanitizer是LLVM的一部分;從4.8版本開始,作為GCC的一部分。在這個示例中,我們將在代碼中加入兩個bug,正常的測試中可能無法檢測到。為了檢測這些bug,我們將使用AddressSanitizer工具,并將CTest與動態分析結合起來,從而將缺陷報告給CDash。 ## 準備工作 這個例子中,我們將使用兩個源文件和兩個測試集: ```shell . ├── CMakeLists.txt ├── CTestConfig.cmake ├── dashboard.cmake ├── src │ ├── buggy.cpp │ ├── buggy.hpp │ └── CMakeLists.txt └── tests ├── CMakeLists.txt ├── leaky.cpp └── use_after_free.cpp ``` `buggy.cpp`包含有兩個bug: ```c++ #include "buggy.hpp" #include <iostream> int function_leaky() { double *my_array = new double[1000]; // do some work ... // we forget to deallocate the array // delete[] my_array; return 0; } int function_use_after_free() { double *another_array = new double[1000]; // do some work ... // deallocate it, good! delete[] another_array; // however, we accidentally use the array // after it has been deallocated std::cout << "not sure what we get: " << another_array[123] << std::endl; return 0; } ``` 這些函數在相應的頭文件中聲明(`buggy.hpp`): ```c++ #pragma once int function_leaky(); int function_use_after_free(); ``` 測試文件`leaky.cpp`中將會驗證`function_leaky`的返回值: ```c++ #include "buggy.hpp" int main() { int return_code = function_leaky(); return return_code; } ``` 相應地,`use_after_free.cpp`會檢查`function_use_after_free`的返回值: ```c++ #include "buggy.hpp" int main() { int return_code = function_use_after_free(); return return_code; } ``` ## 具體實施 為了使用ASan,我們需要使用特定的標志來編譯代碼。然后,我們將運行測試并將它們提交到面板。 1. 生成bug庫的工作將在` src/CMakeLists.txt`中完成: ```cmake add_library(buggy "") target_sources(buggy PRIVATE buggy.cpp PUBLIC ${CMAKE_CURRENT_LIST_DIR}/buggy.hpp ) target_include_directories(buggy PUBLIC ${CMAKE_CURRENT_LIST_DIR} ) ``` 2. 在文件`src/CMakeLists.txt`中,我們將添加一個選項用于使用ASan: ```cmake option(ENABLE_ASAN "Enable AddressSanitizer" OFF) if(ENABLE_ASAN) if(CMAKE_CXX_COMPILER_ID MATCHES GNU) message(STATUS "AddressSanitizer enabled") target_compile_options(buggy PUBLIC -g -O1 -fsanitize=address -fno-omit-frame-pointer ) target_link_libraries(buggy PUBLIC asan ) else() message(WARNING "AddressSanitizer not supported for this compiler") endif() endif() ``` 3. 測試在`tests/CMakeLists.txt`中定義: ```cmake foreach(_test IN ITEMS leaky use_after_free) add_executable(${_test} ${_test}.cpp) target_link_libraries(${_test} buggy) add_test( NAME ${_test} COMMAND $<TARGET_FILE:${_test}> ) endforeach() ``` 4. 主`CMakeLists.txt`與之前的示例基本相同: ```cmake # set minimum cmake version cmake_minimum_required(VERSION 3.5 FATAL_ERROR) # project name and language project(recipe-03 LANGUAGES CXX) # require C++11 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_STANDARD_REQUIRED ON) # process src/CMakeLists.txt add_subdirectory(src) enable_testing() # allow to report to a cdash dashboard include(CTest) # process tests/CMakeLists.txt add_subdirectory(tests) ``` 5. ` CTestConfig.cmake `也沒有修改: ```cmake set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "my.cdash.org") set(CTEST_DROP_LOCATION "/submit.php?project=cmake-cookbook") set(CTEST_DROP_SITE_CDASH TRUE) ``` 6. 這個示例中,我們使用CTest腳本向CDash提交結果;為此,我們將創建一個文件` dashboard.cmake`(與主`CMakeLists.txt`和`` CTestConfig.cmake`位于同一個目錄下): ```cmake set(CTEST_PROJECT_NAME "example") cmake_host_system_information(RESULT _site QUERY HOSTNAME) set(CTEST_SITE ${_site}) set(CTEST_BUILD_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") set(CTEST_SOURCE_DIRECTORY "${CTEST_SCRIPT_DIRECTORY}") set(CTEST_BINARY_DIRECTORY "${CTEST_SCRIPT_DIRECTORY}/build") include(ProcessorCount) ProcessorCount(N) if(NOT N EQUAL 0) set(CTEST_BUILD_FLAGS -j${N}) set(ctest_test_args ${ctest_test_args} PARALLEL_LEVEL ${N}) endif() ctest_start(Experimental) ctest_configure( OPTIONS -DENABLE_ASAN:BOOL=ON ) ctest_build() ctest_test() set(CTEST_MEMORYCHECK_TYPE "AddressSanitizer") ctest_memcheck() ctest_submit() ``` 7. 我們將執行` dashboard.cmake`腳本。注意,我們使用`CTEST_CMAKE_GENERATOR`與生成器選項的方式: ```shell $ ctest -S dashboard.cmake -D CTEST_CMAKE_GENERATOR="Unix Makefiles" Each . represents 1024 bytes of output . Size of output: 0K Each symbol represents 1024 bytes of output. '!' represents an error and '*' a warning. . Size of output: 1K ``` 8. 結果將會出現在CDash網站上: ![](https://img.kancloud.cn/69/67/696791f88cb989dc0f07a138626bfab9_2759x756.png) ## 具體實施 這個示例中,成功地向儀表板的動態分析部分報告了內存錯誤。我們可以通過瀏覽缺陷詳細信息,得到進一步的了解: ![](https://img.kancloud.cn/19/c0/19c02708841f97ab35c041624d7f482a_1420x482.png) 通過單擊各個鏈接,可以瀏覽完整信息的輸出。 注意,也可以在本地生成AddressSanitizer報告。這個例子中,我們需要設置`ENABLE_ASAN`: ```shell $ mkdir -p build $ cd build $ cmake -DENABLE_ASAN=ON .. $ cmake --build . $ cmake --build . --target test Start 1: leaky 1/2 Test #1: leaky ............................***Failed 0.07 sec Start 2: use_after_free 2/2 Test #2: use_after_free ...................***Failed 0.04 sec 0% tests passed, 2 tests failed out of 2 ``` 運行`leaky`測試,直接產生以下結果: ```shell $ ./build/tests/leaky ================================================================= ==18536==ERROR: LeakSanitizer: detected memory leaks Direct leak of 8000 byte(s) in 1 object(s) allocated from: #0 0x7ff984da1669 in operator new[](unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cc:82 #1 0x564925c93fd2 in function_leaky() /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/src/buggy.cpp:7 #2 0x564925c93fb2 in main /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/tests/leaky.cpp:4 #3 0x7ff98403df49 in __libc_start_main (/usr/lib/libc.so.6+0x20f49) SUMMARY: AddressSanitizer: 8000 byte(s) leaked in 1 allocation(s). ``` 相應地,我們可以直接運行`use_after_free`,得到詳細的輸出: ```shell $ ./build/tests/use_after_free ================================================================= ==18571==ERROR: AddressSanitizer: heap-use-after-free on address 0x6250000004d8 at pc 0x557ffa8b0102 bp 0x7ffe8c560200 sp 0x7ffe8c5601f0 READ of size 8 at 0x6250000004d8 thread T0 #0 0x557ffa8b0101 in function_use_after_free() /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/src/buggy.cpp:28 #1 0x557ffa8affb2 in main /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/tests/use_after_free.cpp:4 #2 0x7ff1d6088f49 in __libc_start_main (/usr/lib/libc.so.6+0x20f49) #3 0x557ffa8afec9 in _start (/home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/build/tests/use_after_free+0xec9) 0x6250000004d8 is located 984 bytes inside of 8000-byte region [0x625000000100,0x625000002040) freed by thread T0 here: #0 0x7ff1d6ded5a9 in operator delete[](void*) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cc:128 #1 0x557ffa8afffa in function_use_after_free() /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/src/buggy.cpp:24 #2 0x557ffa8affb2 in main /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/tests/use_after_free.cpp:4 #3 0x7ff1d6088f49 in __libc_start_main (/usr/lib/libc.so.6+0x20f49) previously allocated by thread T0 here: #0 0x7ff1d6dec669 in operator new[](unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cc:82 #1 0x557ffa8affea in function_use_after_free() /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/src/buggy.cpp:19 #2 0x557ffa8affb2 in main /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/tests/use_after_free.cpp:4 #3 0x7ff1d6088f49 in __libc_start_main (/usr/lib/libc.so.6+0x20f49) SUMMARY: AddressSanitizer: heap-use-after-free /home/user/cmake-recipes/chapter-14/recipe-03/cxx-example/src/buggy.cpp:28 in function_use_after_free() Shadow bytes around the buggy address: 0x0c4a7fff8040: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4a7fff8050: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4a7fff8060: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4a7fff8070: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4a7fff8080: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd =>0x0c4a7fff8090: fd fd fd fd fd fd fd fd fd fd fd[fd]fd fd fd fd 0x0c4a7fff80a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4a7fff80b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4a7fff80c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4a7fff80d0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c4a7fff80e0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==18571==ABORTING ``` 如果我們在沒有AddressSanitizer的情況下進行測試(默認情況下`ENABLE_ASAN`是關閉的),就不會報告錯誤: ```shell $ mkdir -p build_no_asan $ cd build_no_asan $ cmake .. $ cmake --build . $ cmake --build . --target test Start 1: leaky 1/2 Test #1: leaky ............................ Passed 0.00 sec Start 2: use_after_free 2/2 Test #2: use_after_free ................... Passed 0.00 sec 100% tests passed, 0 tests failed out of 2 ``` 實際上,泄漏只會浪費內存,而`use_after_free`可能會導致未定義行為。調試這些問題的一種方法是使用valgrind (http://valgrind.org )。 與前兩個示例相反,我們使用了CTest腳本來配置、構建和測試代碼,并將報告提交到面板。要了解此示例的工作原理,請仔細查看` dashboard.cmake `腳本。首先,我們定義項目名稱并設置主機報告和構建名稱: ```cmake set(CTEST_PROJECT_NAME "example") cmake_host_system_information(RESULT _site QUERY HOSTNAME) set(CTEST_SITE ${_site}) set(CTEST_BUILD_NAME "${CMAKE_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") ``` 我們的例子中,`CTEST_BUILD_NAME`的計算結果是`Linux-x86_64`。不同的操作系統下,可能會觀察到不同的結果。 接下來,我們為源和構建目錄指定路徑: ```cmake set(CTEST_SOURCE_DIRECTORY "${CTEST_SCRIPT_DIRECTORY}") set(CTEST_BINARY_DIRECTORY "${CTEST_SCRIPT_DIRECTORY}/build") ``` 我們可以將生成器設置為`Unix Makefile`: ```cmake set(CTEST_CMAKE_GENERATOR "Unix Makefiles") ``` 但是,對于更具可移植性的測試腳本,我們更愿意通過命令行提供生成器: ```shell $ ctest -S dashboard.cmake -D CTEST_CMAKE_GENERATOR="Unix Makefiles" ``` ` dashboard.cmake`中的下一個代碼片段,將計算出機器上可用的CPU芯數量,并將測試步驟的并行級設置為可用CPU芯數量,以使總測試時間最小化: ```cmake include(ProcessorCount) ProcessorCount(N) if(NOT N EQUAL 0) set(CTEST_BUILD_FLAGS -j${N}) set(ctest_test_args ${ctest_test_args} PARALLEL_LEVEL ${N}) endif() ``` 接下來,我們開始測試步驟并配置代碼,將`ENABLE_ASAN`設置為`ON`: ```cmake ctest_start(Experimental) ctest_configure( OPTIONS -DENABLE_ASAN:BOOL=ON ) ``` ` dashboard.cmake `其他命令為映射到構建、測試、內存檢查和提交步驟: ```cmake ctest_build() ctest_test() set(CTEST_MEMORYCHECK_TYPE "AddressSanitizer") ctest_memcheck() ctest_submit() ``` ## 更多信息 細心的讀者會注意到,在鏈接目標之前,我們沒有在系統上搜索AddressSanitizer。實際中,庫查找工作已經提前做完,以避免在鏈接階段出現意外。 有關AddressSanitizer文檔和示例的更多信息,請參見https://github.com/google/sanitizers/wiki/AddressSanitizer 。AddressSanitizer并不僅限于C和C++。對于Fortran示例,讀者可以參考 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-14/recipe-03/fortran-example 。 **NOTE**:*可以在https://github.com/arsenm/sanitizers-cmake 上找到CMake程序,用來查找殺毒程序和調整編譯器標志* 下面的博客文章討論了如何添加對動態分析工具的支持,對我們很有啟發性:https://blog.kitware.com/ctest-cdash-add-support-for-new-dynamic-analysis-tools/
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看