In this example, we will use two source files and two tests, as follows:
.
├── CMakeLists.txt
├── CTestConfig.cmake
├── dashboard.cmake
├── src
│ ├── buggy.cpp
│ ├── buggy.hpp
│ └── CMakeLists.txt
└── tests
├── CMakeLists.txt
├── leaky.cpp
└── use_after_free.cpp
The file buggy.cpp contains two buggy functions, as follows:
#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;
}
These functions are exposed in the corresponding header file (buggy.hpp):
#pragma once
int function_leaky();
int function_use_after_free();
The test source, leaky.cpp, verifies the return code from function_leaky:
#include "buggy.hpp"
int main() {
int return_code = function_leaky();
return return_code;
}
Correspondingly, use_after_free.cpp checks the return value of function_use_after_free, as follows:
#include "buggy.hpp"
int main() {
int return_code = function_use_after_free();
return return_code;
}