Quick Links:

bal | bbl | bdl | bsl

Namespaces | Defines

Component bslma_testallocator
[Package bslma]

Provide instrumented malloc/free allocator to track memory usage. More...

Namespaces

namespace  bslma

Defines

#define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN(BSLMA_TESTALLOCATOR)
#define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END

Detailed Description

Outline
Purpose:
Provide instrumented malloc/free allocator to track memory usage.
Classes:
bslma::TestAllocator instrumented malloc/free memory allocator
Macros:
BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN macro to begin testing exceptions
BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END macro to end testing exceptions
See also:
Component bslma_newdeleteallocator, Component bslma_mallocfreeallocator, Component balst_stacktracetestallocator
Description:
This component provides an instrumented allocator, bslma::TestAllocator, that implements the bslma::Allocator protocol and can be used to track various aspects of memory allocated from it. Available statistics include the number of outstanding blocks (and bytes) that are currently in use, the cumulative number of blocks (and bytes) that have been allocated, and the maximum number of blocks (and bytes) that have been in use at any one time. A print function formats these values to stdout:
   ,--------------------.
  ( bslma::TestAllocator )
   `--------------------'
             |         ctor/dtor
             |         lastAllocatedAddress/lastDeallocatedAddress
             |         lastAllocatedNumBytes/lastDeallocatedNumBytes
             |         numAllocations/numDeallocations
             |         numBlocksInUse/numBlocksMax/numBlocksTotal
             |         numBytesInUse/numBytesMax/numBytesTotal
             |         numMismatches/numBoundsErrors
             |         print/name
             |         setAllocationLimit/allocationLimit
             |         setNoAbort/isNoAbort
             |         setQuiet/isQuiet
             |         setVerbose/isVerbose
             |         status
             V
     ,----------------.
    ( bslma::Allocator )
     `----------------'
                       allocate
                       deallocate
If exceptions are enabled, this allocator can be configured to throw an exception after the number of allocation requests exceeds some specified limit (see the subsection on "Allocation Limit" below). The level of verbosity can also be adjusted. Each allocator object also maintains a current status.
By default this allocator gets its memory from the C Standard Library functions malloc and free, but can be overridden to take memory from any allocator (supplied at construction) that implements the bslma::Allocator protocol. Note that allocation and deallocation using a bslma::TestAllocator object is explicitly incompatible with malloc and free (or any other allocation mechanism). Attempting to use free to deallocate memory allocated from a bslma::TestAllocator -- even when malloc and free are used by default -- will result in undefined behavior, almost certainly corrupting the C Standard Library's runtime memory manager.
Memory dispensed from a bslma::TestAllocator is marked such that attempting to deallocate previously unallocated (or already deallocated) memory will (with high probability) be flagged as an error (unless quiet mode is set for the purpose of testing the test allocator itself). A bslma::TestAllocator also supports a buffer overrun / underrun feature -- each allocation has "pads", areas of extra memory before and after the segment that are initialized to a particular value and checked upon deallocation to see if they have been modified. If they have, a message is printed and the allocator aborts, unless it is in quiet mode.
Detecting Memory Leaks:
The bslma::TestAllocator is useful for detecting memory leaks, unless configured in quiet mode. With the default configuration, if a test allocator is destroyed before all memory is reclaimed, a report will be logged and abort will be called. When such a memory leak is detected, clients can substitute balst::StackTraceTestAllocator for bslma::TestAllocator to report stack traces of allocations that were leaked. Note that balst::StackTraceTestAllocator is slower and consumes more memory than bslma::TestAllocator, and usually is not appropriate for automated tests.
Modes:
The test allocator's behavior is controlled by three basic mode flags:
VERBOSE MODE: (Default 0) Specifies that each allocation and deallocation should be printed to standard output. In verbose mode all state variables will be displayed at destruction.
QUIET MODE: (Default 0) Specifies that mismatched memory and memory leaks should not be reported, and should not cause the process to terminate when detected. Note that this mode is used primarily for testing the test allocator itself; behavior that would otherwise abort now quietly increments the numMismatches and numBoundsErrors counter.
NO-ABORT MODE: (Default 0) Specifies that the test allocator should not invoke abort under any circumstances without suppressing diagnostics. Although the internal state values are independent, quiet mode implies the behavior of no-abort mode in all cases. Note that this mode is used primarily for visual inspection of unusual error diagnostics in this component's test driver (in non-quiet mode only).
Taking the default mode settings, memory allocation/deallocation will not be displayed individually. However, in the event of a mismatched deallocation or a memory leak detected at destruction, the problem will be announced, any relevant state of the object will be displayed, and the program will abort.
The three modes are independently set using the setVerbose, setQuiet, and setNoAbort manipulators.
Allocation Limit:
If exceptions are enabled at compile time, the test allocator can be configured to throw a bslma::TestAllocatorException after a specified number of allocation requests is exceeded. If the allocation limit is less than 0 (default), then the allocator won't throw a TestAllocatorException exception. Note that a non-negative allocation limit is decremented after each allocation attempt, and an exception is thrown only when the current allocation limit transitions from 0 to -1; no additional exceptions will be thrown until the allocation limit is again reset to a non-negative value.
The allocation limit is set using the setAllocationLimit manipulator.
Exception Test Macros:
This component also provides a pair of macros:
These macros can be used for testing exception-safety of classes and their methods when memory allocation is needed. A reference to an object of type bslma::TestAllocator must be supplied as an argument to the _BEGIN macro. Note that if exception-handling is disabled (i.e., if BDE_BUILD_TARGET_EXC is not defined when building the code under test), then the macros simply print the following:
  BSLMA EXCEPTION TEST -- (NOT ENABLED) --
When exception-handling is enabled, the _BEGIN macro will set the allocation limit of the supplied allocator to 0, try the code being tested, catch any TestAllocatorExceptions that are thrown, and keep increasing the allocation limit until the code being tested completes successfully.
Thread Safety:
The bslma::TestAllocator class is fully thread-safe (see bsldoc_glossary). Note that the bslma::MallocFreeAllocator singleton (the allocator used by the test allocator if none is supplied at construction) is fully thread-safe.
Usage:
The bslma::TestAllocator defined in this component can be used in conjunction with the BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN and BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END macros to test the memory usage patterns of an object that uses the bslma::Allocator protocol in its interface. In this example, we illustrate how we might test that an object under test is exception-neutral. For illustration purposes, we will assume the existence of a my_shortarray component implementing an std::vector-like array type, myShortArray:
  // my_shortarray.t.cpp
  #include <my_shortarray.h>

  #include <bslma_testallocator.h>
  #include <bslma_testallocatorexception.h>

  // ...
Below we provide a static function, areEqual, that will allow us to compare two short arrays:
  static
  bool areEqual(const short *array1, const short *array2, int numElements)
      // Return 'true' if the specified initial 'numElements' in the
      // specified 'array1' and 'array2' have the same values, and 'false'
      // otherwise.
  {
      for (int i = 0; i < numElements; ++i) {
          if (array1[i] != array2[i]) {
              return false;                                         // RETURN
          }
      }
      return true;
  }

  // ...
The following is an abbreviated standard test driver. Note that the number of arguments specify the verbosity level that the test driver uses for printing messages:
  int main(int argc, char *argv[])
  {
      int                 test = argc > 1 ? atoi(argv[1]) : 0;
      bool             verbose = argc > 2;
      bool         veryVerbose = argc > 3;
      bool     veryVeryVerbose = argc > 4;
      bool veryVeryVeryVerbose = argc > 5;
We now define a bslma::TestAllocator, sa, named "supplied" to indicate that it is the allocator to be supplied to our object under test, as well as to the BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN macro (below). Note that if veryVeryVeryVerbose is true, then sa prints all allocation and deallocation requests to stdout and also prints the accumulated statistics on destruction:
  bslma::TestAllocator sa("supplied", veryVeryVeryVerbose);

  switch (test) { case 0:

    // ...

    case 6: {

      // ...

      struct {
          int   d_line;
          int   d_numElem;
          short d_exp[NUM_VALUES];
      } DATA[] = {
          { L_, 0, { } },
          { L_, 1, { V0 } },
          { L_, 5, { V0, V1, V2, V3, V4 } }
      };
      const int NUM_DATA = sizeof DATA / sizeof *DATA;

      for (int ti = 0; ti < NUM_DATA; ++ti) {
          const int    LINE     = DATA[ti].d_line;
          const int    NUM_ELEM = DATA[ti].d_numElem;
          const short *EXP      = DATA[ti].d_exp;

          if (veryVerbose) { T_ P_(ti) P_(NUM_ELEM) }

          // ...
All code that we want to test for exception-safety must be enclosed within the BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN and BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END macros, which internally implement a do-'while' loop. Code provided by the BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN macro sets the allocation limit of the supplied allocator to 0 causing it to throw an exception on the first allocation. This exception is caught by code provided by the BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END macro, which increments the allocation limit by 1 and re-runs the same code again. Using this scheme we can check that our code does not leak memory for any memory allocation request. Note that the curly braces surrounding these macros, although visually appealing, are not technically required:
      BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN(sa) {
        my_ShortArray mA(&sa);
        const my_ShortArray& A = mA;
        for (int ei = 0; ei < NUM_ELEM; ++ei) {
            mA.append(VALUES[ei]);
        }
        if (veryVerbose) { T_ T_  P_(NUM_ELEM) P(A) }
        LOOP_ASSERT(LINE, areEqual(EXP, A, NUM_ELEM));
      } BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
  }
After the exception-safety test we can ensure that all the memory allocated from sa was successfully deallocated:
          if (veryVerbose) sa.print();

        } break;

        // ...

      }

      // ...
  }
Note that the BDE_BUILD_TARGET_EXC macro is defined at compile-time to indicate whether or not exceptions are enabled.

Define Documentation

#define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN (   BSLMA_TESTALLOCATOR  ) 
Value:
{                                                                           \
    static int firstTime = 1;                                               \
    if (verbose && firstTime) {                                             \
        std::puts("\t\tBSLMA EXCEPTION TEST -- (NOT ENABLED) --");          \
        firstTime = 0;                                                      \
    }                                                                       \
}
#define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END