BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balst_stacktracetestallocator.h
Go to the documentation of this file.
1/// @file balst_stacktracetestallocator.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balst_stacktracetestallocator.h -*-C++-*-
8#ifndef INCLUDED_BALST_STACKTRACETESTALLOCATOR
9#define INCLUDED_BALST_STACKTRACETESTALLOCATOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balst_stacktracetestallocator balst_stacktracetestallocator
15/// @brief Provide a test allocator that reports the call stack for leaks.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balst
19/// @{
20/// @addtogroup balst_stacktracetestallocator
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balst_stacktracetestallocator-purpose"> Purpose</a>
25/// * <a href="#balst_stacktracetestallocator-classes"> Classes </a>
26/// * <a href="#balst_stacktracetestallocator-description"> Description </a>
27/// * <a href="#balst_stacktracetestallocator-overhead-efficiency"> Overhead Efficiency </a>
28/// * <a href="#balst_stacktracetestallocator-failure-handler"> Failure Handler </a>
29/// * <a href="#balst_stacktracetestallocator-usage"> Usage </a>
30/// * <a href="#balst_stacktracetestallocator-example-1-basic-usage"> Example 1: Basic Usage </a>
31///
32/// # Purpose {#balst_stacktracetestallocator-purpose}
33/// Provide a test allocator that reports the call stack for leaks.
34///
35/// # Classes {#balst_stacktracetestallocator-classes}
36///
37/// - balst::StackTraceTestAllocator: allocator that reports call stack for leaks
38///
39/// # Description {#balst_stacktracetestallocator-description}
40/// This component provides an instrumented allocator,
41/// `balst::StackTraceTestAllocator`, that implements the
42/// `bdlma::ManagedAllocator` protocol. An object of this type records the call
43/// stack for each allocation performed, and can report, either using the
44/// `reportBlocksInUse` method or implicitly at destruction, the call stack
45/// associated with every allocated block that has not (yet) been freed. It is
46/// optionally supplied a `bslma::Allocator` at construction that it uses to
47/// allocate memory.
48/// @code
49/// ,------------------------------.
50/// ( balst::StackTraceTestAllocator )
51/// `------------------------------'
52/// | ctor/dtor
53/// | numAllocations
54/// | allocationLimit
55/// | numBlocksInUse
56/// | reportBlocksInUse
57/// | setFailureHandler
58/// V
59/// ,----------------------.
60/// ( bdlma::ManagedAllocator)
61/// `----------------------'
62/// | release
63/// V
64/// ,----------------.
65/// ( bslma::Allocator )
66/// `----------------'
67/// allocate
68/// deallocate
69/// @endcode
70/// Note that allocation using a `balst::StackTraceTestAllocator` is
71/// deliberately incompatible with the default global `new`, `malloc`, `delete`,
72/// and `free`. Using `delete` or `free` to free memory supplied by this
73/// allocator will corrupt the dynamic memory manager and also cause a memory
74/// leak (and will be reported by purify as freeing mismatched memory, freeing
75/// unallocated memory, or as a memory leak). Using `deallocate` to free memory
76/// supplied by global `new` or `malloc` will immediately cause an error to be
77/// reported to the associated `ostream` and the abort handler (which can be
78/// configured to be a no-op) called.
79///
80/// ## Overhead Efficiency {#balst_stacktracetestallocator-overhead-efficiency}
81///
82///
83/// There is some overhead to using this allocator. It's is slower than
84/// `bslma::NewDeleteAllocator` and uses more memory. It is, however,
85/// comparable in speed and memory usage to `bslma::TestAllocator`. The stack
86/// trace stored for each allocation is stack pointers only, which are compact
87/// and quick to obtain. Actual resolving of the stack pointer to subroutine
88/// names and, on some platforms, source file names and line numbers, is
89/// expensive but doesn't happen during allocation or deallocation and is put
90/// off until a memory leak report is being generated.
91///
92/// Note that the overhead increases and efficiency decreases as the
93/// `numRecordedFrames` argument to the constructor is increased.
94///
95/// ## Failure Handler {#balst_stacktracetestallocator-failure-handler}
96///
97///
98/// An object of type `balst::StackTraceTestAllocator` always has a failure
99/// handler associated with it. This is a configurable `bdef::Functton` object
100/// that will be called if any error condition is detected, after the error
101/// condition is reported. By default, it is set to
102/// `balst::StackTraceTestAllocator::failAbort` which calls `abort`, but it may
103/// be set by `setFailureHandler` to another routine. If the client does not
104/// want a core dump to occur, it is recommended they do:
105/// @code
106/// stackTraceTestAllocator.setFailureHandler(
107/// &balst::StackTraceTestAllocator::failNoop);
108/// @endcode
109/// The stack trace test allocator is prepared for the failure handler to
110/// return, throw (provided the client will catch the exception) or longjmp
111/// without undefined behavior.
112///
113/// If a memory is found to be outstanding during destruction, that is
114/// considered a memory leak and a report is written. After the report, the
115/// failure handler is called, and if the failure handler returns, the leaked
116/// memory is then released. This means that if the failure handler throws or
117/// longjmps in this case, the leaked memory will not be freed, and there will
118/// be no way to release it afterward since the allocator will no longer exist.
119///
120/// ## Usage {#balst_stacktracetestallocator-usage}
121///
122///
123/// This section illustrates intended use of this component.
124///
125/// ### Example 1: Basic Usage {#balst_stacktracetestallocator-example-1-basic-usage}
126///
127///
128/// In this example, we will define a class `ShipsCrew` that does something,
129/// but leaks memory, and then we will demonstrate the use of the stack trace
130/// test allocator to locate the leak.
131///
132/// First, we define `ShipsCrew`, a class that will read the names of a ship's
133/// crew from a file at construction, and make the results available through
134/// accessors:
135/// @code
136/// struct ShipsCrew {
137/// // This struct will, at construction, read and parse a file describing
138/// // the names of the crew of a ship.
139///
140/// private:
141/// // PRIVATE TYPES
142/// struct CharStrLess {
143/// // Functor to compare two 'const char *'s in alphabetical order.
144///
145/// bool operator()(const char *a, const char *b) const
146/// {
147/// return bsl::strcmp(a, b) < 0;
148/// }
149/// };
150///
151/// typedef bsl::set<const char *, CharStrLess> NameSet;
152///
153/// // DATA
154/// const char *d_captain;
155/// const char *d_firstMate;
156/// const char *d_cook;
157/// NameSet d_sailors;
158/// bslma::Allocator *d_allocator_p;
159///
160/// private:
161/// // PRIVATE MANIPULATORS
162/// void addSailor(const bsl::string& name);
163/// // Add the specified 'name' to the set of sailor's names.
164/// // Redundant names are ignored.
165///
166/// const char *copy(const bsl::string& str);
167/// // Allocate memory for a copy of the specified 'str' as a char
168/// // array, copy the contents of 'str' into it, and return a pointer
169/// // to the new copy.
170///
171/// void free(const char **str);
172/// // If '0 != str', deallocate '*str' using the allocator associated
173/// // with this object and set '*str' to 0, otherwise do nothing. The
174/// // behavior is undefined if '0 == str'.
175///
176/// void setCaptain(const bsl::string& name);
177/// // Set the name of the ship's captain to the specified 'name'.
178///
179/// void setCook(const bsl::string& name);
180/// // Set the name of the ship's cook to the specified 'name'.
181///
182/// void setFirstMate(const bsl::string& name);
183/// // Set the name of the ship's first mate to the specified 'name'.
184///
185/// public:
186/// // CREATORS
187/// explicit
188/// ShipsCrew(const char *crewFileName,
189/// bslma::Allocator *basicAllocator = 0);
190/// // Read the names of the ship's crew in from the file with the
191/// // specified name 'crewFileName'.
192///
193/// ~ShipsCrew();
194/// // Destroy this object and free memory.
195///
196/// // ACCESSORS
197/// const char *captain();
198/// // Return the captain's name.
199///
200/// const char *cook();
201/// // Return the cook's name.
202///
203/// const char *firstMate();
204/// // Return the first mate's name.
205///
206/// const char *firstSailor();
207/// // Return the name of the sailor whose name is alphabetically the
208/// // first in the list.
209///
210/// const char *nextSailor(const char *currentSailor);
211/// // Return the next sailor alphabetically after the specified
212/// // 'currentSailor', or 0 if 'currentSailor' is the last in the list
213/// // or not found. The behavior is undefined if
214/// // '0 == currentSailor'.
215/// };
216/// @endcode
217/// Then, we implement the private manipulators of the class:
218/// @code
219/// PRIVATE MANIPULATORS
220/// void ShipsCrew::addSailor(const bsl::string& name)
221/// {
222/// if (!d_sailors.count(name.c_str())) {
223/// d_sailors.insert(copy(name));
224/// }
225/// }
226///
227/// const char *ShipsCrew::copy(const bsl::string& str)
228/// {
229/// char *result = (char *) d_allocator_p->allocate(str.length() + 1);
230/// bsl::strcpy(result, str.c_str());
231/// return result;
232/// }
233///
234/// void ShipsCrew::free(const char **str)
235/// {
236/// assert(str);
237///
238/// if (*str) {
239/// d_allocator_p->deallocate(const_cast<char *>(*str));
240/// *str = 0;
241/// }
242/// }
243///
244/// void ShipsCrew::setCaptain(const bsl::string& name)
245/// {
246/// free(&d_captain);
247///
248/// d_captain = copy(name);
249/// }
250///
251/// void ShipsCrew::setCook(const bsl::string& name)
252/// {
253/// free(&d_cook);
254///
255/// d_cook = copy(name);
256/// }
257///
258/// void ShipsCrew::setFirstMate(const bsl::string& name)
259/// {
260/// free(&d_firstMate);
261///
262/// d_firstMate = copy(name);
263/// }
264/// @endcode
265/// Next, we implement the creators:
266/// @code
267/// // CREATORS
268/// ShipsCrew::ShipsCrew(const char *crewFileName,
269/// bslma::Allocator *basicAllocator)
270/// : d_captain(0)
271/// , d_firstMate(0)
272/// , d_cook(0)
273/// , d_sailors( bslma::Default::allocator(basicAllocator))
274/// , d_allocator_p(bslma::Default::allocator(basicAllocator))
275/// {
276/// bsl::ifstream input(crewFileName);
277/// BSLS_ASSERT(!input.eof() && !input.bad());
278///
279/// bsl::string line(d_allocator_p);
280///
281/// while (bsl::getline(input, line), !line.empty()) {
282/// bsl::size_t colon = line.find(':');
283/// if (bsl::string::npos != colon) {
284/// const bsl::string& field = line.substr(0, colon);
285/// const bsl::string& name = line.substr(colon + 1);
286///
287/// if (0 == bdlb::String::lowerCaseCmp(field, "captain")) {
288/// setCaptain(name);
289/// }
290/// else if (0 == bdlb::String::lowerCaseCmp(field, "first mate")){
291/// setFirstMate(name);
292/// }
293/// else if (0 == bdlb::String::lowerCaseCmp(field, "cook")) {
294/// setCook(name);
295/// }
296/// else if (0 == bdlb::String::lowerCaseCmp(field, "sailor")) {
297/// addSailor(name);
298/// }
299/// else {
300/// cerr << "Unrecognized field '" << field << "' in line '" <<
301/// line << "'\n";
302/// }
303/// }
304/// else {
305/// cerr << "Garbled line '" << line << "'\n";
306/// }
307/// }
308/// }
309///
310/// ShipsCrew::~ShipsCrew()
311/// {
312/// free(&d_captain);
313/// free(&d_firstMate);
314///
315/// // Note that deallocating the strings will invalidate 'd_sailors' --
316/// // any manipulation of 'd_sailors' other than destruction after this
317/// // would lead to undefined behavior.
318///
319/// const NameSet::iterator end = d_sailors.end();
320/// for (NameSet::iterator it = d_sailors.begin(); end != it; ++it) {
321/// d_allocator_p->deallocate(const_cast<char *>(*it));
322/// }
323/// }
324/// @endcode
325/// Then, we implement the public accessors:
326/// @code
327/// ACCESSORS
328/// const char *ShipsCrew::captain()
329/// {
330/// return d_captain ? d_captain : "";
331/// }
332///
333/// const char *ShipsCrew::cook()
334/// {
335/// return d_cook ? d_cook : "";
336/// }
337///
338/// const char *ShipsCrew::firstMate()
339/// {
340/// return d_firstMate ? d_firstMate : "";
341/// }
342///
343/// const char *ShipsCrew::firstSailor()
344/// {
345/// NameSet::iterator it = d_sailors.begin();
346/// return d_sailors.end() == it ? 0 : *it;
347/// }
348///
349/// const char *ShipsCrew::nextSailor(const char *currentSailor)
350/// {
351/// assert(currentSailor);
352/// NameSet::iterator it = d_sailors.find(currentSailor);
353/// if (d_sailors.end() != it) {
354/// ++it;
355/// }
356/// return d_sailors.end() == it ? 0 : *it;
357/// }
358/// @endcode
359/// Next, in `main`, we create our file `./shipscrew.txt` describing the crew of
360/// the ship. Note that the order of crew members is not important:
361/// @code
362/// {
363/// bsl::ofstream outFile("shipscrew.txt");
364///
365/// outFile << "sailor:Mitch Sandler\n"
366/// << "sailor:Ben Lampert\n"
367/// << "cook:Bob Jones\n"
368/// << "captain:Steve Miller\n"
369/// << "sailor:Daniel Smith\n"
370/// << "first mate:Sally Chandler\n"
371/// << "sailor:Joe Owens\n";
372/// }
373/// @endcode
374/// Then, we set up a test case to test our `ShipsCrew` class. We do not use
375/// the stack trace test allocator yet, we just use a `bslma::TestAllocator` to
376/// get memory usage statistics and determine whether any leakage occurred.
377/// @code
378/// {
379/// bslma::TestAllocator ta("Bslma Test Allocator");
380/// bslma::TestAllocatorMonitor tam(&ta);
381///
382/// {
383/// ShipsCrew crew("shipscrew.txt", &ta);
384/// assert(tam.isInUseUp());
385/// assert(tam.isTotalUp());
386///
387/// if (verbose) {
388/// cout << "Captain: " << crew.captain() <<
389/// "\nFirst Mate: " << crew.firstMate() <<
390/// "\nCook: " << crew.cook() << endl;
391/// for (const char *sailor = crew.firstSailor(); sailor;
392/// sailor = crew.nextSailor(sailor)) {
393/// cout << "Sailor: " << sailor << endl;
394/// }
395/// }
396/// }
397///
398/// int bytesLeaked = ta.numBytesInUse();
399/// if (bytesLeaked > 0) {
400/// cout << bytesLeaked << " bytes of memory were leaked!\n";
401/// }
402/// }
403/// @endcode
404/// The program generates the following output in non-verbose mode, telling us
405/// that one segment of 10 bytes was leaked:
406/// @code
407/// 10 bytes of memory were leaked!
408/// MEMORY_LEAK from Bslma Test Allocator:
409/// Number of blocks in use = 1
410/// Number of bytes in use = 10
411/// @endcode
412/// Next, we would like to use stack trace test allocator to tell us WHERE the
413/// memory leak is, but we have a problem: our test case not only uses
414/// `bslma::TestAllocator`, but it calls the `numBytesInUse` accessor, which is
415/// not available from stack trace test allocator. We are also using
416/// `bslma::TestAllocatorMonitor`, which will only work with
417/// `bslma::TestAllocator`. So if we were to just substitute the stack trace
418/// test allocator for the bslma test allocator, it would break our test case in
419/// several ways. To instrument our test with a minimal change to the code, we
420/// create a stack test test allocator and feed that allocator to the
421/// constructor to bslma test allocator. The rest of our example will now work
422/// without modification. (Note that it is important to call
423/// `ta.setNoAbort(true)` when we use this method, otherwise the bslma test
424/// allocator will bomb out before the destructor for `stta` is able to generate
425/// its report).
426/// @code
427/// {
428/// balst::StackTraceTestAllocator stta;
429/// stta.setName("stta");
430/// stta.setFailureHandler(&stta.failNoop);
431///
432/// bslma::TestAllocator ta("Bslma Test Allocator", &stta);
433/// ta.setNoAbort(true);
434///
435/// // the rest of the test case after this is totally unchanged
436///
437/// bslma::TestAllocatorMonitor tam(&ta);
438///
439/// {
440/// ShipsCrew crew("shipscrew.txt", &ta);
441/// assert(tam.isInUseUp());
442/// assert(tam.isTotalUp());
443///
444/// if (verbose) {
445/// cout << "Captain: " << crew.captain() <<
446/// "\nFirst Mate: " << crew.firstMate() <<
447/// "\nCook: " << crew.cook() << endl;
448/// for (const char *sailor = crew.firstSailor(); sailor;
449/// sailor = crew.nextSailor(sailor)) {
450/// cout << "Sailor: " << sailor << endl;
451/// }
452/// }
453/// }
454///
455/// int bytesLeaked = ta.numBytesInUse();
456/// if (bytesLeaked > 0) {
457/// cout << bytesLeaked << " bytes of memory were leaked!\n";
458/// }
459/// }
460/// @endcode
461/// Now, this generates the following report:
462/// @code
463/// 10 bytes of memory were leaked!
464/// MEMORY_LEAK from Bslma Test Allocator:
465/// Number of blocks in use = 1
466/// Number of bytes in use = 10
467/// ===========================================================================
468/// Error: memory leaked:
469/// 1 block(s) in allocator 'stta' in use.
470/// Block(s) allocated from 1 trace(s).
471/// ---------------------------------------------------------------------------
472/// Allocation trace 1, 1 block(s) in use.
473/// Stack trace at allocation time:
474/// (0): BloombergLP::balst::StackTraceTestAllocator::allocate(int)+0x17d at 0x
475/// 805e741 in balst_stacktracetestallocator.t.dbg_exc_mt
476/// (1): BloombergLP::bslma::TestAllocator::allocate(int)+0x12c at 0x8077398 in
477/// balst_stacktracetestallocator.t.dbg_exc_mt
478/// (2): ShipsCrew::copy(bsl::basic_string<char, std::char_traits<char>, bsl::a
479/// llocator<char> > const&)+0x31 at 0x804c3db in balst_stacktracetestallocator
480/// .t.dbg_exc_mt
481/// (3): ShipsCrew::setCook(bsl::basic_string<char, std::char_traits<char>, bsl
482/// ::allocator<char> > const&)+0x2d at 0x804c4c1 in balst_stacktracetestalloca
483/// tor.t.dbg_exc_mt
484/// (4): ShipsCrew::ShipsCrew(char const*, BloombergLP::bslma::Allocator*)+0x23
485/// 4 at 0x804c738 in balst_stacktracetestallocator.t.dbg_exc_mt
486/// (5): main+0x53c at 0x804d55e in balst_stacktracetestallocator.t.dbg_exc_mt
487/// (6): __libc_start_main+0xdc at 0x182e9c in /lib/libc.so.6
488/// (7): --unknown-- at 0x804c1d1 in balst_stacktracetestallocator.t.dbg_exc_mt
489/// @endcode
490/// Finally, Inspection shows that frame (3) of the stack trace from the
491/// allocation of the leaked segment was from `ShipsCrew::setCook`. Inspection
492/// of the code shows that we neglected to free `d_cook` in the destructor and
493/// we can now easily fix our leak.
494/// @}
495/** @} */
496/** @} */
497
498/** @addtogroup bal
499 * @{
500 */
501/** @addtogroup balst
502 * @{
503 */
504/** @addtogroup balst_stacktracetestallocator
505 * @{
506 */
507
508#include <balscm_version.h>
509
510#include <bslmt_mutex.h>
511
513
514#include <bslma_allocator.h>
515
516#include <bsls_atomic.h>
517#include <bsls_keyword.h>
518
519#include <bsl_cstddef.h>
520#include <bsl_functional.h>
521#include <bsl_iosfwd.h>
522
523
524namespace balst {
525
526 // =============================
527 // class StackTraceTestAllocator
528 // =============================
529
530/// This class defines a concrete "test" allocator mechanism that implements
531/// the `bdlma::ManagedAllocator` protocol, and provides instrumentation to
532/// track the set of all blocks allocated by this allocator that have yet to
533/// be freed. At any time it can produce a report about such blocks,
534/// listing for each place that any unfreed blocks were allocated
535/// * the number of unfreed blocks allocated at that place
536/// * the stack trace at that place
537/// The allocator will also detect redundant frees of the same block, and
538/// frees by the wrong allocator. The client can choose whether such
539/// violations are handled by a core dump, or merely a report being written.
540///
541/// Note that, unlike many other allocators, this allocator does DOES NOT
542/// rely on the currently installed default allocator (see @ref bslma_default )
543/// at all, but instead -- by default -- uses `MallocFreeAllocator`
544/// singleton, which in turn calls the C Standard Library functions `malloc`
545/// and `free` as needed. Clients may, however, override this allocator by
546/// supplying (at construction) any other allocator implementing the
547/// `bslma::Allocator` protocol.
548///
549/// See @ref balst_stacktracetestallocator
551
552 public:
553 // PUBLIC TYPES
555 // Type of functor called by this object to handle failures.
556 // Note that this can be set and accessed using th
557 // 'setFailureHandler' and 'failureHandler' methods
558 // respectively.
559
560 private:
561 // PRIVATE TYPES
562 enum AllocatorMagic { k_STACK_TRACE_TEST_ALLOCATOR_MAGIC = 1335775331 };
563
564 struct BlockHeader; // information stored in
565 // each block (defined in
566 // .cpp)
567
568 // DATA
569 AllocatorMagic d_magic; // magic # to identify type
570 // of memory allocator
571
572 bsls::AtomicInt d_numBlocksInUse; // number of currently
573 // allocated blocks, unfreed
574
575 bsls::AtomicInt64 d_numAllocations; // number of allocations
576 // that have occurred since
577 // creation
578
579 bsls::AtomicInt64 d_allocationLimit; // number of allocations
580 // before exception is
581 // thrown by this object
582
583 BlockHeader *d_blocks; // list of currently
584 // allocated, unfreed blocks
585
586 mutable bslmt::Mutex d_mutex; // mutex used to synchronize
587 // access to this object
588
589 const char *d_name; // name of this allocator
590
591 FailureHandler d_failureHandler; // function we are to call
592 // on errors. The default
593 // handler will call
594 // 'abort'.
595
596 const int d_maxRecordedFrames; // max number of stack trace
597 // frames to store in each
598 // block; may be larger than
599 // the number of frames
600 // requested to the ctor due
601 // to ignored frames
602
603 const int d_traceBufferLength; // length, in pointers, of
604 // area for storing stack
605 // traces; may be larger
606 // than
607 // 'd_maxRecordedFrames' due
608 // to alignment
609 // considerations
610
611 bsl::ostream *d_ostream; // stream to which
612 // diagnostics are to be
613 // written; held, not owned
614
615 bool d_demangleFlag; // if 'true', demangling of
616 // symbol names is attempted
617
618 bslma::Allocator *d_allocator_p; // held, not owned
619
620 private:
621 // NOT IMPLEMENTED
623 StackTraceTestAllocator& operator=(
625
626 private:
627 // PRIVATE ACCESSORS
628
629 /// Return 0 if the block specified by `blockHdr` was allocated with
630 /// this allocator, is not corrupted, and has not yet been freed; report
631 /// diagnostics to `*d_ostream` and return a non-zero value otherwise.
632 int checkBlockHeader(const BlockHeader *blockHdr) const;
633
634 public:
635 // CLASS METHODS
636
637 /// Calls `bsl::abort()`, `d_failureHandler` is initialized to this
638 /// value by all constructors. Note that in ALL failure situations,
639 /// errors or warnings will be written to the `ostream` associated with
640 /// this object prior to the failure handler call.
641 static void failAbort();
642
643 /// Does nothing. `setFailureHandler` may be called with this function,
644 /// in which case this allocator object, when a failure occurs, will
645 /// recover rather than abort. Note that in ALL failure situations,
646 /// errors or warnings will be written to the `ostream` associated with
647 /// this object prior to the failure handler call.
648 static void failNoop();
649
650 // CREATORS
651
652 explicit
654 /// Create a test allocator. Optionally specify `numRecordedFrames`,
655 /// the number of stack trace frame pointers to be saved for every
656 /// allocation. Specifying a larger value of `numRecordedFrames` means
657 /// that stack traces, when given, will be more complete, but will also
658 /// mean that both more CPU time and more memory per allocation will be
659 /// consumed. If `numRecordedFrames` is not specified, a value of `12`
660 /// will be assumed. Optionally specify `basicAllocator`, the allocator
661 /// from which memory will be provided. If `basicAllocator` is 0, the
662 /// `MallocFreeAllocator` singleton is used. Associate `bsl::cerr` with
663 /// this object for error diagnostic output, which may be changed by
664 /// calling the `setOstream` manipulator. Set the
665 /// `demanglingPreferringFlag` attribute to `true`, which may be changed
666 /// using the `setDemanglingPreferredFlag` manipulator. The behavior is
667 /// undefined if `numRecordedFrames < 2`.
668 explicit
669 StackTraceTestAllocator(int numRecordedFrames,
670 bslma::Allocator *basicAllocator = 0);
671
672 /// Destroy this allocator. Report any memory leaks to the `ostream`
673 /// that was supplied at construction. If no memory leaks are observed,
674 /// nothing is written to the output `ostream`. Call the failure
675 /// handler if `numBlocksInUse() > 0`. Note that a report of
676 /// outstanding memory blocks is written to `ostream` before the failure
677 /// handler is called, and if the failure handler returns, all
678 /// outstanding memory blocks will be released.
680
681 // MANIPULATORS
682
683 /// Return a newly allocated block of memory of the specified positive
684 /// `size` (in bytes). If `size` is 0, a null pointer is returned with
685 /// no other other effect. Otherwise, invoke the `allocate` method of
686 /// the allocator supplied at construction and record the returned block
687 /// in order to be able to report leaked blocks upon destruction.
689
690 /// Return the memory block at the specified `address` back to this
691 /// allocator. If `address` is 0, this function has no effect.
692 /// Otherwise, if the memory at `address` is consistent with being
693 /// allocated from this test allocator, deallocate it using the
694 /// underlying allocator and delete it from the data structures keeping
695 /// track of blocks in use'. If `address` is not zero and is not the
696 /// address of a block allocated with this allocator (or if it is being
697 /// deallocated a second time), write an error message and call the
698 /// failure handler.
700
701 /// Deallocate all memory held by this allocator.
703
704 /// Set the number of valid allocation requests before an exception is
705 /// to be thrown for this allocator to the specified `limit`. If
706 /// `limit` is less than 0, no exception is to be thrown. By default,
707 /// no exception is scheduled.
708 void setAllocationLimit(bsls::Types::Int64 limit);
709
710 /// Set the `demanglingPreferredFlag` attribute, which is used to
711 /// determine whether demangling of symbols is to be attempted when
712 /// generating diagnostics, to the specified `value`. The default value
713 /// of the flag is `true`. However the flag is ignored on some
714 /// platforms; demangling never happens on some platforms and always
715 /// happens on others.
717
718 /// Set the failure handler associated with this allocator object to the
719 /// specified `func`. Upon construction, the function `failAbort` is
720 /// associated with this object by default. Note that `func` will be
721 /// called by this object's destructor if memory is leaked, so it is
722 /// important that it not throw. Note that in ALL failure situations,
723 /// errors or warnings will be written to the `ostream` associated with
724 /// this object prior to the call to the failure handler.
726
727 /// Set the name of this allocator to the specified `name`. If
728 /// `setName` is never called, the name of the allocator is "<unnamed>".
729 /// Note that the lifetime of `name` must exceed the lifetime of this
730 /// object.
731 void setName(const char * name);
732
733 /// Set the stream to which diagnostics will be written to the specified
734 /// `ostream`. If `setOstream` is never called, diagnostics will be
735 /// written to `bsl::cerr`.
736 void setOstream(bsl::ostream *ostream);
737
738 // ACCESSORS
739
740 /// Return the current number of allocation requests left before an
741 /// exception is thrown. A negative value indicates that no exception
742 /// is scheduled.
743 bsls::Types::Int64 allocationLimit() const;
744
745 /// Return a reference to the function that will be called when a
746 /// failure is observed.
747 const FailureHandler& failureHandler() const;
748
749 /// Return the number of allocations from this object that have occurred
750 /// since creation. Note that this does not count allocations of 0
751 /// length, which return null pointers.
752 bsls::Types::Int64 numAllocations() const;
753
754 /// Return the number of blocks currently allocated from this object.
755 bsl::size_t numBlocksInUse() const;
756
757 /// Write a report to the specified `ostream`, reporting the unique
758 /// call-stacks for each block that has been allocated and has not yet
759 /// been freed. If `ostream` is not specified, the value of `ostream`
760 /// passed to the last call to `setOstream` will be used. If
761 /// `setOstream` was never called, `bsl::cerr` will be used.
762 void reportBlocksInUse(bsl::ostream *ostream = 0) const;
763};
764
765 // -----------------------------
766 // class StackTraceTestAllocator
767 // -----------------------------
768
769inline
772{
773 return d_failureHandler;
774}
775
776inline
778{
779 return d_numBlocksInUse;
780}
781
782inline
784{
785 return d_numAllocations;
786}
787
788} // close package namespace
789
790
791#endif
792
793// ----------------------------------------------------------------------------
794// Copyright 2015 Bloomberg Finance L.P.
795//
796// Licensed under the Apache License, Version 2.0 (the "License");
797// you may not use this file except in compliance with the License.
798// You may obtain a copy of the License at
799//
800// http://www.apache.org/licenses/LICENSE-2.0
801//
802// Unless required by applicable law or agreed to in writing, software
803// distributed under the License is distributed on an "AS IS" BASIS,
804// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
805// See the License for the specific language governing permissions and
806// limitations under the License.
807// ----------------------------- END-OF-FILE ----------------------------------
808
809/** @} */
810/** @} */
811/** @} */
Definition balst_stacktracetestallocator.h:550
const FailureHandler & failureHandler() const
Definition balst_stacktracetestallocator.h:771
void setFailureHandler(const FailureHandler &func)
bsl::size_t numBlocksInUse() const
Return the number of blocks currently allocated from this object.
Definition balst_stacktracetestallocator.h:777
bsl::function< void()> FailureHandler
Definition balst_stacktracetestallocator.h:554
StackTraceTestAllocator(bslma::Allocator *basicAllocator=0)
void * allocate(size_type size) BSLS_KEYWORD_OVERRIDE
void setOstream(bsl::ostream *ostream)
void setAllocationLimit(bsls::Types::Int64 limit)
void setName(const char *name)
~StackTraceTestAllocator() BSLS_KEYWORD_OVERRIDE
void deallocate(void *address) BSLS_KEYWORD_OVERRIDE
bsls::Types::Int64 allocationLimit() const
bsls::Types::Int64 numAllocations() const
Definition balst_stacktracetestallocator.h:783
StackTraceTestAllocator(int numRecordedFrames, bslma::Allocator *basicAllocator=0)
void release() BSLS_KEYWORD_OVERRIDE
Deallocate all memory held by this allocator.
void setDemanglingPreferredFlag(bool value)
void reportBlocksInUse(bsl::ostream *ostream=0) const
Definition bdlma_managedallocator.h:391
Forward declaration.
Definition bslstl_function.h:934
Definition bslma_allocator.h:457
std::size_t size_type
Definition bslma_allocator.h:499
Definition bslmt_mutex.h:315
Definition bsls_atomic.h:892
Definition bsls_atomic.h:743
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition balst_objectfileformat.h:161
Definition bdlb_printmethods.h:283
Definition bdlt_iso8601util.h:691
long long Int64
Definition bsls_types.h:132