/
bslma_testallocator.h
1054 lines (915 loc) · 41.6 KB
/
bslma_testallocator.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// bslma_testallocator.h -*-C++-*-
#ifndef INCLUDED_BSLMA_TESTALLOCATOR
#define INCLUDED_BSLMA_TESTALLOCATOR
#include <bsls_ident.h>
BSLS_IDENT("$Id: $")
//@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: bslma_newdeleteallocator, bslma_mallocfreeallocator,
// 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:
//
//: o 'BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN(BSLMA_TESTALLOCATOR)'
//: o 'BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END'
//
// 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 'TestAllocatorException's 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.
#include <bslscm_version.h>
#include <bslma_allocator.h>
#include <bslma_testallocatorexception.h>
#include <bsls_atomic.h>
#include <bsls_bsllock.h>
#include <bsls_buildtarget.h>
#include <bsls_types.h>
#include <cstdio> // for printing in macros
namespace BloombergLP {
namespace bslma {
struct TestAllocator_List;
// ===================
// class TestAllocator
// ===================
class TestAllocator : public Allocator {
// This class defines a concrete "test" allocator mechanism that implements
// the 'Allocator' protocol, and provides instrumentation to track (1) the
// number of blocks/bytes currently in use, (2) the maximum number of
// blocks/bytes that have been outstanding at any one time, and (3) the
// cumulative number of blocks/bytes that have ever been allocated by this
// test allocator object. The accumulated statistics are based solely on
// the number of bytes requested. Additional testing facilities include
// allocation limits, verbosity modes, status, and automated report
// printing.
//
// Note that, unlike many other allocators, this allocator does NOT rely on
// the currently installed default allocator (see 'bslma_default'), but
// instead -- by default -- uses the 'MallocFreeAllocator' singleton, which
// in turn calls the C Standard Library functions 'malloc' and 'free' as
// needed. Clients may, however, override this allocator by supplying (at
// construction) any other allocator implementing the 'Allocator' protocol.
// DATA
// Control Points
const char *d_name_p; // optionally specified name of this
// test allocator object (or 0)
bsls::AtomicInt
d_noAbortFlag; // whether or not to suppress
// aborting on fatal errors
bsls::AtomicInt
d_quietFlag; // whether or not to suppress
// reporting hard errors
bsls::AtomicInt
d_verboseFlag; // whether or not to report
// allocation/deallocation events and
// print statistics on destruction
bsls::AtomicInt64
d_allocationLimit; // number of allocations before
// exception is thrown by this object
// Statistics
bsls::AtomicInt64
d_numAllocations; // total number of allocation
// requests on this object (including
// those for 0 bytes)
bsls::AtomicInt64
d_numDeallocations; // total number of deallocation
// requests on this object (including
// those supplying a 0 address)
bsls::AtomicInt64
d_numMismatches; // number of mismatched memory
// deallocation errors encountered by
// this object
bsls::AtomicInt64
d_numBoundsErrors; // number of overrun/underrun errors
// encountered by this object
bsls::AtomicInt64
d_numBlocksInUse; // number of blocks currently
// allocated from this object
bsls::AtomicInt64
d_numBytesInUse; // number of bytes currently
// allocated from this object
bsls::AtomicInt64
d_numBlocksMax; // maximum number of blocks ever
// allocated from this object at any
// one time
bsls::AtomicInt64
d_numBytesMax; // maximum number of bytes ever
// allocated from this object at any
// one time
bsls::AtomicInt64
d_numBlocksTotal; // cumulative number of blocks ever
// allocated from this object
bsls::AtomicInt64
d_numBytesTotal; // cumulative number of bytes ever
// allocated from this object
// Other Data
bsls::AtomicInt64
d_lastAllocatedNumBytes; // size (in bytes) of the most recent
// allocation request
bsls::AtomicInt64
d_lastDeallocatedNumBytes;
// size (in bytes) of the most
// recently deallocated memory
bsls::AtomicPointer<int>
d_lastAllocatedAddress_p;// address of the most recently
// allocated memory (or 0)
bsls::AtomicPointer<int>
d_lastDeallocatedAddress_p;
// address of the most recently
// deallocated memory (or 0)
TestAllocator_List
*d_list_p; // list of allocated memory (owned)
mutable bsls::BslLock
d_lock; // ensure mutual exclusion in
// 'allocate', 'deallocate', 'print',
// and 'status'
Allocator *d_allocator_p; // memory allocator (held, not owned)
private:
// NOT IMPLEMENTED
TestAllocator(const TestAllocator&); // = delete
TestAllocator& operator=(const TestAllocator&); // = delete
public:
// CREATORS
explicit
TestAllocator(Allocator *basicAllocator = 0);
explicit
TestAllocator(const char *name,
Allocator *basicAllocator = 0);
explicit
TestAllocator(bool verboseFlag,
Allocator *basicAllocator = 0);
TestAllocator(const char *name,
bool verboseFlag,
Allocator *basicAllocator = 0);
// Create an instrumented "test" allocator. Optionally specify a
// 'name' (associated with this object) to be included in diagnostic
// messages written to 'stdout', thereby distinguishing this test
// allocator from others that might be used in the same program. If
// 'name' is 0 (or not specified), no distinguishing name is
// incorporated in diagnostics. Optionally specify a 'verboseFlag'
// indicating whether this test allocator should automatically report
// all allocation/deallocation events to 'stdout' and print accumulated
// statistics on destruction. If 'verboseFlag' is 'false' (or not
// specified), allocation/deallocation and summary messages will not be
// written automatically. Optionally specify a 'basicAllocator' used
// to supply memory. If 'basicAllocator' is 0, the
// 'MallocFreeAllocator' singleton is used.
~TestAllocator();
// Destroy this allocator. In verbose mode, print all contained state
// values of this allocator object to 'stdout'. Except in quiet mode,
// automatically report any memory leaks to 'stdout'. Abort if either
// 'numBlocksInUse' or 'numBytesInUse' return non-zero unless in
// no-abort mode or quiet mode. Note that, in all cases, destroying
// this object has no effect on outstanding memory blocks allocated
// from this test allocator (and may result in memory leaks -- e.g., if
// the (default) 'MallocFreeAllocator' singleton was used).
// MANIPULATORS
void *allocate(size_type size);
// Return a newly-allocated block of memory of the specified 'size' (in
// bytes). If 'size' is 0, a null pointer is returned. Otherwise,
// invoke the 'allocate' method of the allocator supplied at
// construction, increment the number of currently (and cumulatively)
// allocated blocks, and increase the number of currently allocated
// bytes by 'size'. Update all other fields accordingly.
void deallocate(void *address);
// Return the memory block at the specified 'address' back to this
// allocator. If 'address' is 0, this function has no effect (other
// than to record relevant statistics). Otherwise, if the memory at
// 'address' is consistent with being allocated from this test
// allocator, decrement the number of currently allocated blocks, and
// decrease the number of currently allocated bytes by the size (in
// bytes) originally requested for the block. Although technically
// undefined behavior, if the memory can be determined not to have been
// allocated from this test allocator, increment the number of
// mismatches, and -- unless in quiet mode -- immediately report the
// details of the mismatch to 'stdout' (e.g., as an 'std::hex' memory
// dump) and abort.
void setAllocationLimit(bsls::Types::Int64 limit);
// Set the number of valid allocation requests before an exception is
// to be thrown for this allocator to the specified 'limit'. If
// 'limit' is less than 0, no exception is to be thrown. By default,
// no exception is scheduled.
void setNoAbort(bool flagValue);
// Set the no-abort mode for this test allocator to the specified
// (boolean) 'flagValue'. 'If flagValue' is 'true', aborting on fatal
// errors is suppressed, and the functions simply return. Diagnostics
// are not affected. Note that the default mode is to abort. Also
// note that this function is provided primarily to enable visual
// testing of diagnostic messages produced by this component.
void setQuiet(bool flagValue);
// Set the quiet mode for this test allocator to the specified
// (boolean) 'flagValue'. If 'flagValue' is 'true', mismatched
// allocations, overrun/underrun errors, and memory leak messages will
// not be displayed to 'stdout' and the process will not abort as a
// result of such conditions. Note that the default mode is *not*
// quiet. Also note that this function is provided primarily to enable
// testing of this component; in quiet mode, situations that would
// otherwise abort will just quietly increment the 'numMismatches'
// and/or 'numBoundsErrors' counters.
void setVerbose(bool flagValue);
// Set the verbose mode for this test allocator to the specified
// (boolean) 'flagValue'. If 'flagValue' is 'true', all
// allocation/deallocation events will be reported automatically on
// 'stdout', as will accumulated statistics upon destruction of this
// object. Note that the default mode is *not* verbose.
// ACCESSORS
bsls::Types::Int64 allocationLimit() const;
// Return the current number of allocation requests left before an
// exception is thrown. A negative value indicates that no exception
// is scheduled.
bool isNoAbort() const;
// Return 'true' if this allocator is currently in no-abort mode, and
// 'false' otherwise. In no-abort mode all diagnostic messages are
// printed, but all aborts are suppressed. Note that quiet mode
// implies no-abort mode.
bool isQuiet() const;
// Return 'true' if this allocator is currently in quiet mode, and
// 'false' otherwise. In quiet mode, messages about mismatched
// deallocations, overrun/underrun errors, and memory leaks will not be
// displayed to 'stdout' and will not cause the program to abort.
bool isVerbose() const;
// Return 'true' if this allocator is currently in verbose mode, and
// 'false' otherwise. In verbose mode, all allocation/deallocation
// events will be reported on 'stdout', as will summary statistics upon
// destruction of this object.
void *lastAllocatedAddress() const;
// Return the address that was returned by the most recent allocation
// request. Return 0 if the most recent allocation request was for 0
// bytes.
size_type lastAllocatedNumBytes() const;
// Return the number of bytes of the most recent allocation request.
void *lastDeallocatedAddress() const;
// Return the address that was supplied to the most recent deallocation
// request. Return 0 if a null pointer was most recently deallocated.
// Note that the address is always recorded regardless of the validity
// of the request.
size_type lastDeallocatedNumBytes() const;
// Return the number of bytes of the most recent deallocation request.
// Return 0 if a null pointer was most recently deallocated, or if the
// request was invalid (e.g., an attempt to deallocate memory not
// allocated through this allocator).
const char *name() const;
// Return the name of this test allocator, or 0 if no name was
// specified at construction.
bsls::Types::Int64 numAllocations() const;
// Return the cumulative number of allocation requests. Note that this
// number is incremented for every 'allocate' invocation.
bsls::Types::Int64 numBlocksInUse() const;
// Return the number of blocks currently allocated from this object.
// Note that 'numBlocksInUse() <= numBlocksMax()'.
bsls::Types::Int64 numBlocksMax() const;
// Return the maximum number of blocks ever allocated from this object
// at any one time. Note that
// 'numBlocksInUse() <= numBlocksMax() <= numBlocksTotal()'.
bsls::Types::Int64 numBlocksTotal() const;
// Return the cumulative number of blocks ever allocated from this
// object. Note that 'numBlocksMax() <= numBlocksTotal()'.
bsls::Types::Int64 numBoundsErrors() const;
// Return the number of times memory deallocations have detected that
// pad areas at the front or back of the user segment had been
// overwritten.
bsls::Types::Int64 numBytesInUse() const;
// Return the number of bytes currently allocated from this object.
// Note that 'numBytesInUse() <= numBytesMax()'.
bsls::Types::Int64 numBytesMax() const;
// Return the maximum number of bytes ever allocated from this object
// at any one time. Note that
// 'numBytesInUse() <= numBytesMax() <= numBytesTotal()'.
bsls::Types::Int64 numBytesTotal() const;
// Return the cumulative number of bytes ever allocated from this
// object. Note that 'numBytesMax() <= numBytesTotal()'.
bsls::Types::Int64 numDeallocations() const;
// Return the cumulative number of deallocation requests. Note that
// this number is incremented for every 'deallocate' invocation,
// regardless of the validity of the request.
bsls::Types::Int64 numMismatches() const;
// Return the number of mismatched memory deallocations that have
// occurred since this object was created. A memory deallocation is
// *mismatched* if that memory was not allocated directly from this
// allocator.
void print() const;
// Write the accumulated state information held in this allocator to
// 'stdout' in some reasonable (multi-line) format.
int status() const;
// Return 0 on success, and non-zero otherwise: If there have been any
// mismatched memory deallocations or over/under runs, return the
// number of such errors that have occurred as a positive number; if
// either '0 < numBlocksInUse()' or '0 < numBytesInUse()', return an
// arbitrary negative number; else return 0.
#ifndef BDE_OPENSOURCE_PUBLICATION // DEPRECATED
void *lastAllocateAddress() const;
// Return the allocated memory address of the most recent memory
// request. Return 0 if the request was invalid (e.g., allocate non-
// positive number of bytes).
//
// DEPRECATED: use 'lastAllocatedAddress' instead.
size_type lastAllocateNumBytes() const;
// Return the number of bytes of the most recent memory request. Note
// that this number is always recorded regardless of the validity of
// the request.
//
// DEPRECATED: use 'lastAllocatedNumBytes' instead.
void *lastDeallocateAddress() const;
// Return the memory address of the last memory deallocation request.
// Note that the address is always recorded regardless of the validity
// of the request.
//
// DEPRECATED: use 'lastDeallocatedAddress' instead.
size_type lastDeallocateNumBytes() const;
// Return the number of bytes of the most recent memory deallocation
// request. Return 0 if the request was invalid (e.g., deallocating
// memory not allocated through this allocator).
//
// DEPRECATED: use 'lastDeallocatedNumBytes' instead.
bsls::Types::Int64 numAllocation() const;
// Return the cumulative number of allocation requests. Note that this
// number is incremented for every 'allocate' invocation, regardless of
// the validity of the request.
//
// DEPRECATED: use 'numAllocations' instead.
bsls::Types::Int64 numDeallocation() const;
// Return the cumulative number of deallocation requests. Note that
// this number is incremented for every 'deallocate' invocation,
// regardless of the validity of the request.
//
// DEPRECATED: use 'numDeallocations' instead.
#endif // BDE_OPENSOURCE_PUBLICATION
};
} // close package namespace
// ==============================================
// macro BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN
// ==============================================
#ifdef BDE_BUILD_TARGET_EXC
namespace bslma {
class TestAllocator_ProxyBase {
// This class provides a common base class for the parameterized
// 'TestAllocator_Proxy' class (below). Note that the 'virtual'
// 'setAllocationLimit' method, although a "setter", *must* be declared
// 'const'.
public:
// CREATOR
virtual ~TestAllocator_ProxyBase()
{
}
// ACCESSORS
virtual void setAllocationLimit(bsls::Types::Int64 limit) const = 0;
};
template <class BSLMA_ALLOC_TYPE>
class TestAllocator_Proxy : public TestAllocator_ProxyBase {
// This class provides a proxy to the test allocator that is supplied to
// the 'BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN' macro. This proxy may be
// instantiated with 'TestAllocator', or with a type that supports the same
// interface as 'TestAllocator'.
// DATA
BSLMA_ALLOC_TYPE *d_allocator_p; // allocator used in '*_BEGIN' and
// '*_END' macros (held, not owned)
public:
// CREATORS
explicit TestAllocator_Proxy(BSLMA_ALLOC_TYPE *allocator)
: d_allocator_p(allocator)
{
}
~TestAllocator_Proxy()
{
}
// ACCESSORS
virtual void setAllocationLimit(bsls::Types::Int64 limit) const
{
d_allocator_p->setAllocationLimit(limit);
}
};
template <class BSLMA_ALLOC_TYPE>
inline
TestAllocator_Proxy<BSLMA_ALLOC_TYPE>
TestAllocator_getProxy(BSLMA_ALLOC_TYPE *allocator)
// Return, by value, a test allocator proxy for the specified parameterized
// 'allocator'.
{
return TestAllocator_Proxy<BSLMA_ALLOC_TYPE>(allocator);
}
} // close package namespace
#ifndef BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN
// Note that the `while` loop in the following code uses a flag
// `bslmaKeepLoopingInTestAllocatorExceptionTest`. This is a workaround for an
// XLC16 bug: a `continue` statement in a `catch` block can result in
// segementation faults on optimized XLC16 builds. Bug raised with IBM - see
// DRQS 169604597
#define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN(BSLMA_TESTALLOCATOR) { \
{ \
static int firstTime = 1; \
if (veryVerbose && firstTime) { \
std::puts("\t\tBSLMA EXCEPTION TEST -- (ENABLED) --"); \
} \
firstTime = 0; \
} \
if (veryVeryVerbose) { \
std::puts("\t\tBegin bslma exception test."); \
} \
int bslmaExceptionCounter = 0; \
const BloombergLP::bslma::TestAllocator_ProxyBase& \
bslmaExceptionTestAllocator = \
BloombergLP::bslma::TestAllocator_getProxy(&BSLMA_TESTALLOCATOR); \
bslmaExceptionTestAllocator.setAllocationLimit(bslmaExceptionCounter); \
bool bslmaKeepLoopingInTestAllocatorExceptionTest = true; \
while(bslmaKeepLoopingInTestAllocatorExceptionTest) { \
bslmaKeepLoopingInTestAllocatorExceptionTest = false; \
try {
#endif // BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN
#else // !defined(BDE_BUILD_TARGET_EXC)
#ifndef BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN
#define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN(BSLMA_TESTALLOCATOR) \
{ \
static int firstTime = 1; \
if (verbose && firstTime) { \
std::puts("\t\tBSLMA EXCEPTION TEST -- (NOT ENABLED) --"); \
firstTime = 0; \
} \
}
#endif // BSLMA_TESTALLOCATOR_EXCEPTION_TEST_BEGIN
#endif // BDE_BUILD_TARGET_EXC
// ============================================
// macro BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
// ============================================
#ifdef BDE_BUILD_TARGET_EXC
#ifndef BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
#define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END \
} catch (BloombergLP::bslma::TestAllocatorException& e) { \
if (veryVeryVerbose) { \
std::printf("\t*** BSLMA_EXCEPTION: " \
"alloc limit = %d, last alloc size = %d ***\n", \
bslmaExceptionCounter, \
static_cast<int>(e.numBytes())); \
} \
bslmaExceptionTestAllocator.setAllocationLimit( \
++bslmaExceptionCounter); \
bslmaKeepLoopingInTestAllocatorExceptionTest = true; \
} \
}; \
bslmaExceptionTestAllocator.setAllocationLimit(-1); \
if (veryVeryVerbose) { \
std::puts("\t\tEnd bslma exception test."); \
} \
}
#endif // BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
#else // !defined(BDE_BUILD_TARGET_EXC)
#ifndef BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
#define BSLMA_TESTALLOCATOR_EXCEPTION_TEST_END
#endif
#endif
namespace bslma {
// ============================================================================
// INLINE DEFINITIONS
// ============================================================================
// -------------------
// class TestAllocator
// -------------------
// MANIPULATORS
inline
void TestAllocator::setAllocationLimit(bsls::Types::Int64 limit)
{
d_allocationLimit.storeRelaxed(limit);
}
inline
void TestAllocator::setNoAbort(bool flagValue)
{
d_noAbortFlag.storeRelaxed(flagValue);
}
inline
void TestAllocator::setQuiet(bool flagValue)
{
d_quietFlag.storeRelaxed(flagValue);
}
inline
void TestAllocator::setVerbose(bool flagValue)
{
d_verboseFlag.storeRelaxed(flagValue);
}
// ACCESSORS
inline
bsls::Types::Int64 TestAllocator::allocationLimit() const
{
return d_allocationLimit.loadRelaxed();
}
inline
bool TestAllocator::isNoAbort() const
{
return d_noAbortFlag.loadRelaxed();
}
inline
bool TestAllocator::isQuiet() const
{
return d_quietFlag.loadRelaxed();
}
inline
bool TestAllocator::isVerbose() const
{
return d_verboseFlag.loadRelaxed();
}
inline
void *TestAllocator::lastAllocatedAddress() const
{
return reinterpret_cast<void *>(d_lastAllocatedAddress_p.loadRelaxed());
}
inline
Allocator::size_type TestAllocator::lastAllocatedNumBytes() const
{
return static_cast<size_type>(d_lastAllocatedNumBytes.loadRelaxed());
}
inline
void *TestAllocator::lastDeallocatedAddress() const
{
return reinterpret_cast<void *>(d_lastDeallocatedAddress_p.loadRelaxed());
}
inline
Allocator::size_type TestAllocator::lastDeallocatedNumBytes() const
{
return static_cast<size_type>(d_lastDeallocatedNumBytes.loadRelaxed());
}
inline
const char *TestAllocator::name() const
{
return d_name_p;
}
inline
bsls::Types::Int64 TestAllocator::numAllocations() const
{
return d_numAllocations.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numBlocksInUse() const
{
return d_numBlocksInUse.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numBlocksMax() const
{
return d_numBlocksMax.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numBlocksTotal() const
{
return d_numBlocksTotal.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numBoundsErrors() const
{
return d_numBoundsErrors.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numBytesInUse() const
{
return d_numBytesInUse.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numBytesMax() const
{
return d_numBytesMax.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numBytesTotal() const
{
return d_numBytesTotal.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numDeallocations() const
{
return d_numDeallocations.loadRelaxed();
}
inline
bsls::Types::Int64 TestAllocator::numMismatches() const
{
return d_numMismatches.loadRelaxed();
}
#ifndef BDE_OPENSOURCE_PUBLICATION // DEPRECATED
inline
void *TestAllocator::lastAllocateAddress() const
{
return lastAllocatedAddress();
}
inline
TestAllocator::size_type
TestAllocator::lastAllocateNumBytes() const
{
return lastAllocatedNumBytes();
}
inline
void *TestAllocator::lastDeallocateAddress() const
{
return lastDeallocatedAddress();
}
inline
TestAllocator::size_type
TestAllocator::lastDeallocateNumBytes() const
{
return lastDeallocatedNumBytes();
}
inline
bsls::Types::Int64 TestAllocator::numAllocation() const
{