BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bdlma_guardingallocator.h
Go to the documentation of this file.
1/// @file bdlma_guardingallocator.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bdlma_guardingallocator.h -*-C++-*-
8#ifndef INCLUDED_BDLMA_GUARDINGALLOCATOR
9#define INCLUDED_BDLMA_GUARDINGALLOCATOR
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bdlma_guardingallocator bdlma_guardingallocator
15/// @brief Provide a memory allocator that guards against buffer overruns.
16/// @addtogroup bdl
17/// @{
18/// @addtogroup bdlma
19/// @{
20/// @addtogroup bdlma_guardingallocator
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bdlma_guardingallocator-purpose"> Purpose</a>
25/// * <a href="#bdlma_guardingallocator-classes"> Classes </a>
26/// * <a href="#bdlma_guardingallocator-description"> Description </a>
27/// * <a href="#bdlma_guardingallocator-guard-pages"> Guard Pages </a>
28/// * <a href="#bdlma_guardingallocator-thread-safety"> Thread Safety </a>
29/// * <a href="#bdlma_guardingallocator-usage"> Usage </a>
30/// * <a href="#bdlma_guardingallocator-example-1-diagnosing-buffer-overflow"> Example 1: Diagnosing Buffer Overflow </a>
31/// * <a href="#bdlma_guardingallocator-example-2-allowing-for-maximal-alignment"> Example 2: Allowing for Maximal Alignment </a>
32///
33/// # Purpose {#bdlma_guardingallocator-purpose}
34/// Provide a memory allocator that guards against buffer overruns.
35///
36/// # Classes {#bdlma_guardingallocator-classes}
37///
38/// - bdlma::GuardingAllocator: memory allocator that detects buffer overruns
39///
40/// @see bslma_allocator, bslma_testallocator
41///
42/// # Description {#bdlma_guardingallocator-description}
43/// This component provides a concrete allocation mechanism,
44/// `bdlma::GuardingAllocator`, that implements the `bslma::Allocator` protocol
45/// and adjoins a read/write protected guard page to each block of memory
46/// returned by the `allocate` method. Each returned block is maximally aligned
47/// for the platform. The guard page is located immediately following (subject
48/// to alignment requirements) or immediately preceding the block returned from
49/// `allocate` according to an optionally-supplied constructor argument:
50/// @code
51/// ,------------------------.
52/// ( bdlma::GuardingAllocator )
53/// `------------------------'
54/// | ctor/dtor
55/// V
56/// ,----------------.
57/// ( bslma::Allocator )
58/// `----------------'
59/// allocate
60/// deallocate
61/// @endcode
62/// *WARNING*: Note that this allocator should *not* be used for production use;
63/// it is intended for debugging purposes only. In particular, clients should
64/// be aware that a multiple of the page size is allocated for *each* `allocate`
65/// invocation (unless the size of the request is 0).
66///
67/// Also note that, unlike many other BDE allocators, a `bslma::Allocator *`
68/// cannot be (optionally) supplied upon construction of a `GuardingAllocator`;
69/// instead, a system facility is used that allocates blocks of memory in
70/// multiples of the system page size.
71///
72/// ## Guard Pages {#bdlma_guardingallocator-guard-pages}
73///
74///
75/// A `GuardingAllocator` may be used to debug buffer overflow (or underflow) by
76/// protecting a memory page after (or before) each block of memory returned
77/// from `allocate`. Consequently, certain memory access outside the block
78/// returned to the client will trigger a memory protection fault.
79///
80/// A constructor argument of type `GuardingAllocator::GuardPageLocation`, an
81/// enumeration, determines whether guard pages are located following
82/// (`e_AFTER_USER_BLOCK`) or preceding (`e_BEFORE_USER_BLOCK`) the user block.
83/// If no value is supplied at construction, `e_AFTER_USER_BLOCK` is assumed.
84///
85/// To illustrate, the following diagram shows the memory layout resulting from
86/// an `N`-byte allocation request from a guarding allocator, where `N` is
87/// assumed to be less than or equal to the size of a memory page. Note that
88/// two pages of memory are consumed for each such allocation request:
89/// @code
90/// M - N rounded up to the least multiple of the maximum alignment
91/// A - address of (2-page) block of memory returned by system allocator
92/// U - address returned from 'allocate' to user
93/// G - address of the guard page
94/// PS - page size (in bytes)
95///
96/// e_AFTER_USER_BLOCK
97/// ------------------
98///
99/// [ - - - one memory page - - - | - - - one memory page - - - ]
100/// ---------------------------------------------------------------
101/// | | M bytes | ******* R/W protected ****** |
102/// ---------------------------------------------------------------
103/// ^ ^ ^
104/// A U == G - M G == A + PS
105///
106///
107/// e_BEFORE_USER_BLOCK
108/// -------------------
109///
110/// ---------------------------------------------------------------
111/// | ******* R/W protected ****** | M bytes | |
112/// ---------------------------------------------------------------
113/// ^ ^
114/// A == G U == A + PS
115/// @endcode
116/// Notice that `M`, the distance from the returned address to the start of the
117/// guard page, may be larger than the user requested `N` bytes. See {Example
118/// 2: Allowing for Maximal Alignment}.
119///
120/// ## Thread Safety {#bdlma_guardingallocator-thread-safety}
121///
122///
123/// The `bdlma::GuardingAllocator` class is fully thread-safe (see
124/// @ref bsldoc_glossary ).
125///
126/// ## Usage {#bdlma_guardingallocator-usage}
127///
128///
129/// This section illustrates intended use of this component.
130///
131/// ### Example 1: Diagnosing Buffer Overflow {#bdlma_guardingallocator-example-1-diagnosing-buffer-overflow}
132///
133///
134/// Use of a `bdlma::GuardingAllocator` is indicated, for example, if some code
135/// under development is suspected of having a buffer overrun (or underrun) bug,
136/// and more sophisticated tools that detect such conditions are either not
137/// available, or are inconvenient to apply to the situation at hand.
138///
139/// This usage example illustrates a guarding allocator being brought to bear on
140/// a buffer overrun bug. The bug in question arises in the context of an
141/// artificial data handling class, `my_DataHandler`. This class makes use of a
142/// (similarly artificial) data translation utility that translates chunks of
143/// data among various data styles. In our idealized example, we assume that
144/// the length of the output resulting from some data translation is precisely
145/// determinable from the length of the input data and the respective styles of
146/// the input and the (desired) output. For simplicity, we also assume that
147/// input data comes from a trusted source.
148///
149/// First, we define an enumeration of data styles:
150/// @code
151/// enum my_DataStyle {
152/// e_STYLE_NONE = 0
153/// , e_STYLE_A = 1 // default style
154/// , e_STYLE_AA = 2 // style exactly twice as verbose as 'e_STYLE_A'
155/// // etc.
156/// };
157/// @endcode
158/// Next, we define the (elided) interface of our data translation utility:
159/// @code
160/// struct my_DataTranslationUtil {
161/// // This 'struct' provides a namespace for data translation utilities.
162///
163/// // CLASS METHODS
164/// static int outputSize(my_DataStyle outputStyle,
165/// my_DataStyle inputStyle,
166/// int inputLength);
167/// // Return the buffer size (in bytes) required to store the result
168/// // of converting input data of the specified 'inputLength' (in
169/// // bytes), in the specified 'inputStyle', into the specified
170/// // 'outputStyle'. The behavior is undefined unless
171/// // '0 <= inputLength'.
172///
173/// static int translate(char *output,
174/// my_DataStyle outputStyle,
175/// const char *input,
176/// my_DataStyle inputStyle);
177/// // Load into the specified 'output' buffer the result of converting
178/// // the specified 'input' data, in the specified 'inputStyle', into
179/// // the specified 'outputStyle'. Return 0 on success, and a
180/// // non-zero value otherwise. The behavior is undefined unless
181/// // 'output' has sufficient capacity to hold the translated result.
182/// // Note that this method assumes that 'input' originated from a
183/// // trusted source.
184/// };
185/// @endcode
186/// Next, we define `my_DataHandler`, a simple class that makes use of
187/// `my_DataTranslationUtil`:
188/// @code
189/// class my_DataHandler {
190/// // This 'class' provides a basic data handler.
191///
192/// // DATA
193/// my_DataStyle d_inStyle; // style of 'd_inBuffer' contents
194/// char *d_inBuffer; // input supplied at construction
195/// int d_inCapacity; // capacity (in bytes) of 'd_inBuffer'
196/// my_DataStyle d_altStyle; // alternative style (if requested)
197/// char *d_altBuffer; // buffer for alternative style
198/// bslma::Allocator *d_allocator_p; // memory allocator (held, not owned)
199///
200/// private:
201/// // Not implemented:
202/// my_DataHandler(const my_DataHandler&);
203///
204/// public:
205/// // CREATORS
206/// my_DataHandler(const char *input,
207/// int inputLength,
208/// my_DataStyle inputStyle,
209/// bslma::Allocator *basicAllocator = 0);
210/// // Create a data handler for the specified 'input' data, in the
211/// // specified 'inputStyle', having the specified 'inputLength' (in
212/// // bytes). Optionally specify a 'basicAllocator' used to supply
213/// // memory. If 'basicAllocator' is 0, the currently installed
214/// // default allocator is used. The behavior is undefined unless
215/// // '0 <= inputLength'.
216///
217/// ~my_DataHandler();
218/// // Destroy this data handler.
219///
220/// // ...
221///
222/// // MANIPULATORS
223/// int generateAlternate(my_DataStyle alternateStyle);
224/// // Generate data for this data handler in the specified
225/// // 'alternateStyle'. Return 0 on success, and a non-zero value
226/// // otherwise. If 'alternateStyle' is the same as the style of data
227/// // supplied at construction, this method returns 0 with no effect.
228///
229/// // ...
230/// };
231/// @endcode
232/// Next, we show the definition of the `my_DataHandler` constructor:
233/// @code
234/// my_DataHandler::my_DataHandler(const char *input,
235/// int inputLength,
236/// my_DataStyle inputStyle,
237/// bslma::Allocator *basicAllocator)
238/// : d_inStyle(inputStyle)
239/// , d_inBuffer(0)
240/// , d_inCapacity(inputLength)
241/// , d_altStyle(e_STYLE_NONE)
242/// , d_altBuffer(0)
243/// , d_allocator_p(bslma::Default::allocator(basicAllocator))
244/// {
245/// BSLS_ASSERT(0 <= inputLength);
246///
247/// void *tmp = d_allocator_p->allocate(inputLength);
248/// bsl::memcpy(tmp, input, inputLength);
249/// d_inBuffer = static_cast<char *>(tmp);
250/// }
251/// @endcode
252/// Next, we show the definition of the `generateAlternate` manipulator. Note
253/// that we have deliberately introduced a bug in `generateAlternate` to cause
254/// buffer overrun:
255/// @code
256/// int my_DataHandler::generateAlternate(my_DataStyle alternateStyle)
257/// {
258/// if (alternateStyle == d_inStyle) {
259/// return 0; // RETURN
260/// }
261///
262/// int altLength = my_DataTranslationUtil::outputSize(alternateStyle,
263/// d_inStyle,
264/// d_inCapacity);
265/// (void)altLength;
266///
267/// // Oops! Should have used 'altLength'.
268/// char *tmpAltBuffer = (char *)d_allocator_p->allocate(d_inCapacity);
269/// int rc = my_DataTranslationUtil::translate(tmpAltBuffer,
270/// alternateStyle,
271/// d_inBuffer,
272/// d_inStyle);
273///
274/// if (rc) {
275/// d_allocator_p->deallocate(tmpAltBuffer);
276/// return rc; // RETURN
277/// }
278///
279/// d_altStyle = alternateStyle;
280/// d_altBuffer = tmpAltBuffer;
281///
282/// return 0;
283/// }
284/// @endcode
285/// Next, we define some data (in `e_STYLE_A`):
286/// @code
287/// const char *input = "AAAAAAAAAAAAAAA@"; // data always terminated with '@'
288/// @endcode
289/// Then, we define a `my_DataHandler` object, `handler`, to process that data:
290/// @code
291/// my_DataHandler handler(input, 16, e_STYLE_A);
292/// @endcode
293/// Note that our `handler` object uses the default allocator.
294///
295/// Next, we request that an alternate data style, `e_STYLE_AA`, be generated by
296/// `handler`. Unfortunately, data in style `e_STYLE_AA` is twice as large as
297/// that in style `e_STYLE_A` making it a virtual certainty that the program
298/// will crash due to the insufficiently sized buffer that is allocated in the
299/// `generateAlternate` method to accommodate the `e_STYLE_AA` data:
300/// @code
301/// int rc = handler.generateAlternate(e_STYLE_AA);
302/// if (!rc) {
303/// // use data in alternate style
304/// }
305/// @endcode
306/// Suppose that after performing a brief post-mortem on the resulting core
307/// file, we strongly suspect that a buffer overrun is the root cause, but the
308/// program crashed in a context far removed from that of the source of the
309/// problem (which is often the case with buffer overrun issues).
310///
311/// Consequently, we modify the code to supply a guarding allocator to the
312/// `handler` object, then rebuild and rerun the program. We have configured
313/// the guarding allocator (below) to place guard pages *after* user blocks.
314/// Note that `e_AFTER_USER_BLOCK` is the default, so it need not be specified
315/// at construction as we have (pedantically) done here:
316/// @code
317/// typedef bdlma::GuardingAllocator GA;
318/// GA guard(GA::e_AFTER_USER_BLOCK);
319///
320/// my_DataHandler handler(input, 16, e_STYLE_A, &guard);
321/// @endcode
322/// With a guarding allocator now in place, a memory fault is triggered when a
323/// guard page is overwritten as a result of the buffer overrun bug. Hence, the
324/// program will dump core in a context that is more proximate to the buggy
325/// code, resulting in a core file that will be more amenable to revealing the
326/// issue when analyzed in a debugger.
327///
328/// ### Example 2: Allowing for Maximal Alignment {#bdlma_guardingallocator-example-2-allowing-for-maximal-alignment}
329///
330///
331/// The requirement that this allocator always return maximally aligned memory
332/// can lead to situations when using `e_AFTER_USER_BLOCK` where there is unused
333/// memory between the end of allocated memory and the first address of the
334/// guard page. If so, small memory overruns (e.g., a single byte) will not
335/// land on the guard page and go undetected. Fortunately, users can often
336/// compensate for this behavior and position their data adjacent to the guard
337/// page.
338///
339/// Suppose one must test a function, `myIntSort`, having the signature and
340/// contract:
341/// @code
342/// void myIntSort(int *begin, int *end);
343/// // Efficiently sort in place the values in the specified range
344/// // '[start .. end - 1]' into ascending order.
345/// @endcode
346/// If the `myIntSort` function uses some manner of partitioning algorithm the
347/// implementation will involve considerable pointer arithmetic, recursion,
348/// etc., then a reasonable test concern would be:
349/// @code
350/// // Concerns:
351/// //: 1 The implementation never modifies or even reads data outside of
352/// //: the given input range.
353/// //:
354/// //: 2 Some other concern.
355/// //:
356/// //: 3 Yet another concern.
357/// //:
358/// //: 4 ...
359/// @endcode
360/// Addressing that test concern is ordinarily challenging. One approach is to
361/// bracket the data for each test with data having a distinctive value (e.g.,
362/// `0x0BADCAFE`) and then check that the test does not corrupt that pattern
363/// (any overwrite being *very* unlikely to preserve the special value). Tests
364/// of reads past the given range are harder to prove. One could argue that
365/// incorporating that data into the sort would corrupt the result but one
366/// cannot prove that it was never accessed. Alternatively, using
367/// `bdlma::GuardingAllocator` provides a stronger proof from a simpler test
368/// case. Thus, our test plan would include:
369/// @code
370/// // Plan:
371/// //: 1 Test for range overflow and underflow by positioning test data in
372/// //: memory obtained from 'bdlma::GuardingAllocator' objects. Each
373/// //: test is run twice, once with the guard page below the test data,
374/// //: and again with the guard page above the test data.
375/// @endcode
376/// First, create a set of test data for thoroughly testing all concerns of
377/// `myIntSort`, and a framework for running through those tests:
378/// @code
379/// void testMyIntSort()
380/// // Thoroughly test the 'myIntSort' function using a table-driven
381/// // framework. Note that the testing concerns were listed above.
382/// {
383/// const bsl::size_t MAX_NUM_INPUTS = 5;
384/// struct {
385/// int d_line;
386/// bsl::size_t d_numInputs;
387/// int d_input[MAX_NUM_INPUTS];
388/// } DATA [] = {
389/// { __LINE__, 1, { 0 } }
390/// , { __LINE__, 2, { 2, 1 } }
391///
392/// // ...
393///
394/// , { __LINE__, 3, { 2, 1, 3 } }
395///
396/// // ...
397///
398/// };
399/// const bsl::size_t NUM_DATA = sizeof DATA / sizeof *DATA;
400///
401/// const int pageSize = myGetPageSize();
402/// assert(myIsPowerOfTwo(pageSize));
403///
404/// for (bsl::size_t ti = 0; ti < NUM_DATA; ++ti) {
405/// const int LINE = DATA[ti].d_line; (void) LINE;
406/// const bsl::size_t NUM_INPUTS = DATA[ti].d_numInputs;
407/// const int *const INPUT = DATA[ti].d_input;
408/// @endcode
409/// Then, create a 'bdlma::GuardingAllocator to that will be used to test for
410/// under-runs of the given range and, for each data point, run the test on data
411/// that will segfault if there is any reference to an address in the page below
412/// `begin`, even by a single byte:
413/// @code
414/// bdlma::GuardingAllocator underRun(
415/// bdlma::GuardingAllocator::e_BEFORE_USER_BLOCK);
416///
417/// const bsl::size_t numBytes = NUM_INPUTS * sizeof(int);
418/// void *block = underRun.allocate(numBytes);
419///
420/// assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
421/// block,
422/// pageSize));
423///
424/// bsl::memcpy(block, INPUT, numBytes);
425///
426/// int *begin = static_cast<int *>(block);
427/// int *end = begin + NUM_INPUTS;
428///
429/// myIntSort(begin, end); // TEST
430///
431/// assert(myIsIntSorted(begin, end)); // oracle
432///
433/// underRun.deallocate(block);
434/// @endcode
435/// Notice that, for expository purposes, we confirmed that the `block` is page
436/// aligned.
437///
438/// Next, we will *rerun* the test using data positioned in memory to catch
439/// over-runs of the input range.
440/// @code
441/// bdlma::GuardingAllocator overRun(
442/// bdlma::GuardingAllocator::e_AFTER_USER_BLOCK);
443/// @endcode
444/// The step would be to allocate memory and initialize memory as we did
445/// before. The problem is that memory returned from the
446/// `bdlma::GuardingAllocator` may not abut the following guard page.
447///
448/// Consider a platform where:
449/// * Maximal alignment is 8 bytes.
450/// * `sizeof(int)` is 4 bytes.
451///
452/// For the data point above consisting of 3 values, the required space is 12
453/// bytes (3 * 4) but the maximally aligned address closest to the top of the
454/// returned page is 16 bytes (2 * 8) below the page boundary -- a gap of 4
455/// bytes.
456///
457/// We handle this situation by padding our allocation size to the nearest
458/// multiple of maximal alignment -- 16 bytes in this case. That gives us
459/// allocated memory that abuts the page boundary. This allows us to position
460/// our test data into the allocated memory so that last element fits in the
461/// upper bytes of the returned bytes (i.e., the first 4 bytes of the returned
462/// block are not used by this test).
463///
464/// Now, we calculate the padded allocation size and allocate a block that abuts
465/// the page boundary:
466/// @code
467/// const bsl::size_t paddedSize =
468/// bsls::AlignmentUtil::roundUpToMaximalAlignment(numBytes);
469///
470/// block = overRun.allocate(paddedSize);
471///
472/// int *firstProtectedAddress = static_cast<int *>(
473/// static_cast<void *>(static_cast<char *>(block) + paddedSize));
474///
475/// begin = firstProtectedAddress - NUM_INPUTS;
476/// end = firstProtectedAddress;
477///
478/// assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
479/// block,
480/// bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT));
481///
482/// assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
483/// begin,
484/// sizeof(int)));
485///
486/// assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
487/// end,
488/// pageSize));
489/// @endcode
490/// Notice that again, for purposes of exposition, we have checked the returned
491/// addresses and confirmed:
492/// * The returned address, `block`, is maximally aligned.
493/// * The calculated `begin` is correctly aligned to hold the data value.
494/// * The upper end of the returned block, `end`, is page aligned.
495///
496/// Finally, we load the test data into the carefully positioned memory and
497/// rerun the test:
498/// @code
499/// bsl::memcpy(begin, INPUT, numBytes);
500///
501/// myIntSort(begin, end); // TEST
502/// assert(myIsIntSorted(begin, end)); // oracle
503///
504/// overRun.deallocate(block);
505/// }
506/// }
507/// @endcode
508/// @}
509/** @} */
510/** @} */
511
512/** @addtogroup bdl
513 * @{
514 */
515/** @addtogroup bdlma
516 * @{
517 */
518/** @addtogroup bdlma_guardingallocator
519 * @{
520 */
521
522#include <bdlscm_version.h>
523
524#include <bslma_allocator.h>
525
526#include <bsls_keyword.h>
527#include <bsls_types.h>
528
529
530namespace bdlma {
531
532 // -----------------------
533 // class GuardingAllocator
534 // -----------------------
535
536/// This class defines a concrete thread-safe "guarding" allocator mechanism
537/// that implements the `bslma::Allocator` protocol, and adjoins a
538/// read/write protected guard page to each block of memory returned by the
539/// `allocate` method. The guard page is placed immediately before or
540/// immediately following the block returned from `allocate` according to
541/// the `GuardPageLocation` enumerator value (optionally) supplied at
542/// construction. Note that, unlike many other allocators, an allocator
543/// cannot be (optionally) supplied at construction; instead, a system
544/// facility is used that allocates blocks of memory in multiples of the
545/// system page size. Also note that this allocator is intended for
546/// debugging purposes *only*.
547///
548/// See @ref bdlma_guardingallocator
550
551 public:
552 // TYPES
554 // Enumerate the configuration options for 'GuardingAllocator' that may
555 // be (optionally) supplied at construction.
556
557 e_AFTER_USER_BLOCK, // locate the guard page after the user block
558 e_BEFORE_USER_BLOCK // locate the guard page before the user block
559 };
560
561 private:
562 // DATA
563 GuardPageLocation d_guardPageLocation; // if 'e_AFTER_USER_BLOCK', place
564 // the read/write protected guard
565 // page after the user block;
566 // otherwise, place it before the
567 // block ('e_BEFORE_USER_BLOCK')
568
569 private:
570 // NOT IMPLEMENTED
572 GuardingAllocator& operator=(const GuardingAllocator&);
573
574 public:
575 // CREATORS
576
577 /// Create a guarding allocator. Optionally specify a `guardLocation`
578 /// indicating where read/write protected guard pages should be placed
579 /// with respect to the memory blocks returned by the `allocate` method.
580 /// If `guardLocation` is not specified, guard pages are placed
581 /// immediately following the memory blocks returned by `allocate`.
582 explicit
584
585 /// Destroy this allocator object. Note that destroying this allocator
586 /// has no effect on any outstanding allocated memory.
588
589 // MANIPULATORS
590
591 /// Return a newly-allocated maximally-aligned block of memory of the
592 /// specified `size` (in bytes) that has a read/write protected guard
593 /// page located immediately before or after it according to the
594 /// `GuardPageLocation` indicated at construction. If `size` is 0, no
595 /// memory is allocated and 0 is returned. Note that a multiple of the
596 /// platform's memory page size is allocated for *every* call to this
597 /// method.
599
600 /// Return the memory block at the specified `address` back to this
601 /// allocator. If `address` is 0, this method has no effect.
602 /// Otherwise, the guard page associated with `address` is unprotected
603 /// and also deallocated. The behavior is undefined unless `address`
604 /// was returned by `allocate` and has not already been deallocated.
606};
607
608// ============================================================================
609// INLINE DEFINITIONS
610// ============================================================================
611
612 // -----------------------
613 // class GuardingAllocator
614 // -----------------------
615
616// CREATORS
617inline
619: d_guardPageLocation(guardLocation)
620{
621}
622
623} // close package namespace
624
625
626#endif
627
628// ----------------------------------------------------------------------------
629// Copyright 2016 Bloomberg Finance L.P.
630//
631// Licensed under the Apache License, Version 2.0 (the "License");
632// you may not use this file except in compliance with the License.
633// You may obtain a copy of the License at
634//
635// http://www.apache.org/licenses/LICENSE-2.0
636//
637// Unless required by applicable law or agreed to in writing, software
638// distributed under the License is distributed on an "AS IS" BASIS,
639// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
640// See the License for the specific language governing permissions and
641// limitations under the License.
642// ----------------------------- END-OF-FILE ----------------------------------
643
644/** @} */
645/** @} */
646/** @} */
Definition bdlma_guardingallocator.h:549
~GuardingAllocator() BSLS_KEYWORD_OVERRIDE
GuardPageLocation
Definition bdlma_guardingallocator.h:553
@ e_BEFORE_USER_BLOCK
Definition bdlma_guardingallocator.h:558
@ e_AFTER_USER_BLOCK
Definition bdlma_guardingallocator.h:557
void * allocate(bsls::Types::size_type size) BSLS_KEYWORD_OVERRIDE
void deallocate(void *address) BSLS_KEYWORD_OVERRIDE
Definition bslma_allocator.h:457
std::size_t size_type
Definition bslma_allocator.h:499
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition bdlma_alignedallocator.h:276
Definition bdlt_iso8601util.h:691