the Compartmented Robust Posix C++ Unit Test system

Chapter 8. Heap Management

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]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?