the Compartmented Robust Posix C++ Unit Test system | hosted by |
---|
Finding memory leaks can be tricky, and testing behavior under out of memory situations even trickier still. With crpcut both are easy, since crpcut provides simple access to query and limit the heap.
The function
size_t crpcut::heap::allocated_bytes
()
is used to ask the heap how much memory is allocated on the heap.
The number returned is the sum of bytes allocated, sans any overhead,
i.e. it is the sum of the size arguments to all calls to
malloc
(), calloc
(),
realloc
(), operator new
and
operator new[]
.
![]() | Tip |
---|---|
Use a fixture that compares allocated bytes at destruction time with allocated bytes at construction time. If they aren't equal, the test has leaked. |
The heap can also be limited with the function
size_t crpcut::heap::set_limit
(size_t bytes
).
The parameter bytes
is the maximum number of
bytes that is allowed to allocate from the heap. The return value is the
previous limit. There is a special value
crpcut::heap::system
, which removes
any artificial limitations.
Here's a function and helper class that casts between types by means of interpreting the stream representation.
#include <sstream> #include <ostream> #include <istream> #include <string> class cast_type { private: cast_type(const std::string str) : s(str) {} cast_type& operator=(const cast_type&); public: cast_type(const cast_type &other) : s(other.s) { } ~cast_type() { } template <typename T> operator T() const { std::istringstream is(s); T rv = T(); is >> rv; return rv; } private: std::string s; template <typename T> friend cast_type stream_cast(const T&); }; template <typename T> inline cast_type stream_cast(const T& t) { std::ostringstream os; os << t; return cast_type(os.str()); }
Below is a small test program to verify its correctness. It includes a memory leak check and a low memory situation:
#include "stream-cast.hpp" #include <crpcut.hpp> class leak_detect { protected: leak_detect() : pre(crpcut::heap::allocated_bytes()) {} ~leak_detect() { size_t post = crpcut::heap::allocated_bytes(); if (post != pre) { FAIL << "Memory leak detected\n" << pre << " Bytes allocated at construction time\n" << post << " Bytes allocated at destruction time"; } } private: size_t pre; }; TEST(simple_string_to_int, leak_detect) { const char s[] = "123"; int n = stream_cast(s); ASSERT_EQ(n, 123); } TEST(constrained_string_to_int, leak_detect) { crpcut::heap::set_limit(crpcut::heap::allocated_bytes() + 10); const char s[] = "1234567"; int n = stream_cast(s); ASSERT_EQ(1234567, n); } int main(int argc, char *argv[]) { return crpcut::run(argc, argv); }
Running the test yields:
FAILED: constrained_string_to_int phase="running" -------------------------------------------------------------- /home/bjorn/devel/crpcut/doc-src/samples/heap-check.cpp:60 ASSERT_EQ(1234567, n) where n = 0 ------------------------------------------------------------------------------- =============================================================================== Total 2 test cases selected UNTESTED : 0 PASSED : 1 FAILED : 1
No memory leaks, that's the good news, but that it silently provides the wrong answer under low-memory situations, that is very bad. Can you see why?