Step 4: Dynamic Analysis¶
This step shows how to detect memory errors with two tools: AddressSanitizer and Valgrind.
Unlike the other steps, this one builds its own project in the
Step4/Project directory. Its source file writes to memory after it is
freed:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char* s = malloc(100);
free(s);
/* Bug: this writes to memory that was already freed. */
strcpy(s, "Hello world!");
printf("string is: %s\n", s);
return 0;
}
Both scripts call ctest_memcheck() instead of ctest_test().
This runs each test under the analysis tool, collects the problems it
reports, and submits them to CDash separately from the test results.
AddressSanitizer¶
AddressSanitizer is built into GCC and Clang. The project is compiled with
-fsanitize=address, and the tests report memory errors when they run.
set(CTEST_BUILD_NAME "Step4: AddressSanitizer")
site_name(CTEST_SITE)
set(CTEST_SOURCE_DIRECTORY "${CTEST_SCRIPT_DIRECTORY}/Project")
set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
set(CTEST_NOTES_FILES "${CMAKE_CURRENT_LIST_FILE}")
set(CTEST_UPDATE_COMMAND "git")
set(CTEST_UPDATE_VERSION_ONLY 1)
set(CTEST_USE_LAUNCHERS 1)
set(CTEST_BINARY_DIRECTORY "${CTEST_SCRIPT_DIRECTORY}/build-asan")
# Tell CTest that the tests use AddressSanitizer, so that it knows how to
# parse their output.
set(CTEST_MEMORYCHECK_TYPE "AddressSanitizer")
ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}")
ctest_start(Experimental)
ctest_update()
# Build with the -fsanitize=address flag to enable AddressSanitizer.
set(options
"-DCMAKE_BUILD_TYPE=Debug"
"-DCMAKE_C_FLAGS=-fsanitize=address"
)
ctest_configure(OPTIONS "${options}")
ctest_build()
# Run the tests with dynamic analysis instead of calling ctest_test().
ctest_memcheck()
ctest_submit()
Setting CTEST_MEMORYCHECK_TYPE tells CTest how to parse the
sanitizer output, so that it can report each problem to CDash.
ctest -S Step4/asan.cmake -V
Valgrind¶
Valgrind runs each test executable under its own instrumentation, so it needs no special compiler flags. It is more portable but slower than ASan.
set(CTEST_BUILD_NAME "Step4: Valgrind")
site_name(CTEST_SITE)
set(CTEST_SOURCE_DIRECTORY "${CTEST_SCRIPT_DIRECTORY}/Project")
set(CTEST_CMAKE_GENERATOR "Unix Makefiles")
set(CTEST_NOTES_FILES "${CMAKE_CURRENT_LIST_FILE}")
set(CTEST_UPDATE_COMMAND "git")
set(CTEST_UPDATE_VERSION_ONLY 1)
set(CTEST_USE_LAUNCHERS 1)
set(CTEST_BINARY_DIRECTORY "${CTEST_SCRIPT_DIRECTORY}/build-valgrind")
# Run the tests under Valgrind.
find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind)
ctest_empty_binary_directory("${CTEST_BINARY_DIRECTORY}")
ctest_start(Experimental)
ctest_update()
ctest_configure()
ctest_build()
# Run the tests with dynamic analysis instead of calling ctest_test().
ctest_memcheck()
ctest_submit()
ctest -S Step4/valgrind.cmake -V
Requirements¶
AddressSanitizer: GCC or Clang with
-fsanitize=address.Valgrind:
valgrindfound in thePATH.
See the CTest MemCheck Step for other supported tools.