// bdlma_guardingallocator.h                                          -*-C++-*-
#ifndef INCLUDED_BDLMA_GUARDINGALLOCATOR
#define INCLUDED_BDLMA_GUARDINGALLOCATOR

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a memory allocator that guards against buffer overruns.
//
//@CLASSES:
//  bdlma::GuardingAllocator: memory allocator that detects buffer overruns
//
//@SEE_ALSO: bslma_allocator, bslma_testallocator
//
//@DESCRIPTION: This component provides a concrete allocation mechanism,
// 'bdlma::GuardingAllocator', that implements the 'bslma::Allocator' protocol
// and adjoins a read/write protected guard page to each block of memory
// returned by the 'allocate' method.  Each returned block is maximally aligned
// for the platform.  The guard page is located immediately following (subject
// to alignment requirements) or immediately preceding the block returned from
// 'allocate' according to an optionally-supplied constructor argument:
//..
//   ,------------------------.
//  ( bdlma::GuardingAllocator )
//   `------------------------'
//               |         ctor/dtor
//               V
//      ,----------------.
//     ( bslma::Allocator )
//      `----------------'
//                         allocate
//                         deallocate
//..
// *WARNING*: Note that this allocator should *not* be used for production use;
// it is intended for debugging purposes only.  In particular, clients should
// be aware that a multiple of the page size is allocated for *each* 'allocate'
// invocation (unless the size of the request is 0).
//
// Also note that, unlike many other BDE allocators, a 'bslma::Allocator *'
// cannot be (optionally) supplied upon construction of a 'GuardingAllocator';
// instead, a system facility is used that allocates blocks of memory in
// multiples of the system page size.
//
///Guard Pages
///-----------
// A 'GuardingAllocator' may be used to debug buffer overflow (or underflow) by
// protecting a memory page after (or before) each block of memory returned
// from 'allocate'.  Consequently, certain memory access outside the block
// returned to the client will trigger a memory protection fault.
//
// A constructor argument of type 'GuardingAllocator::GuardPageLocation', an
// enumeration, determines whether guard pages are located following
// ('e_AFTER_USER_BLOCK') or preceding ('e_BEFORE_USER_BLOCK') the user block.
// If no value is supplied at construction, 'e_AFTER_USER_BLOCK' is assumed.
//
// To illustrate, the following diagram shows the memory layout resulting from
// an 'N'-byte allocation request from a guarding allocator, where 'N' is
// assumed to be less than or equal to the size of a memory page.  Note that
// two pages of memory are consumed for each such allocation request:
//..
//  M  - N rounded up to the least multiple of the maximum alignment
//  A  - address of (2-page) block of memory returned by system allocator
//  U  - address returned from 'allocate' to user
//  G  - address of the guard page
//  PS - page size (in bytes)
//
//                          e_AFTER_USER_BLOCK
//                          ------------------
//
//      [ - - - one memory page  - - - | - - - one memory page  - - - ]
//      ---------------------------------------------------------------
//      |                 |  M  bytes  | ******* R/W protected ****** |
//      ---------------------------------------------------------------
//      ^                 ^            ^
//      A                 U == G - M   G == A + PS
//
//
//                          e_BEFORE_USER_BLOCK
//                          -------------------
//
//      ---------------------------------------------------------------
//      | ******* R/W protected ****** |  M  bytes  |                 |
//      ---------------------------------------------------------------
//      ^                              ^
//      A == G                         U == A + PS
//..
// Notice that 'M', the distance from the returned address to the start of the
// guard page, may be larger than the user requested 'N' bytes.  See {Example
// 2: Allowing for Maximal Alignment}.
//
///Thread Safety
///-------------
// The 'bdlma::GuardingAllocator' class is fully thread-safe (see
// 'bsldoc_glossary').
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Diagnosing Buffer Overflow
///- - - - - - - - - - - - - - - - - - -
// Use of a 'bdlma::GuardingAllocator' is indicated, for example, if some code
// under development is suspected of having a buffer overrun (or underrun) bug,
// and more sophisticated tools that detect such conditions are either not
// available, or are inconvenient to apply to the situation at hand.
//
// This usage example illustrates a guarding allocator being brought to bear on
// a buffer overrun bug.  The bug in question arises in the context of an
// artificial data handling class, 'my_DataHandler'.  This class makes use of a
// (similarly artificial) data translation utility that translates chunks of
// data among various data styles.  In our idealized example, we assume that
// the length of the output resulting from some data translation is precisely
// determinable from the length of the input data and the respective styles of
// the input and the (desired) output.  For simplicity, we also assume that
// input data comes from a trusted source.
//
// First, we define an enumeration of data styles:
//..
//  enum my_DataStyle {
//      e_STYLE_NONE = 0
//    , e_STYLE_A    = 1  // default style
//    , e_STYLE_AA   = 2  // style exactly twice as verbose as 'e_STYLE_A'
//    // etc.
//  };
//..
// Next, we define the (elided) interface of our data translation utility:
//..
//  struct my_DataTranslationUtil {
//      // This 'struct' provides a namespace for data translation utilities.
//
//      // CLASS METHODS
//      static int outputSize(my_DataStyle outputStyle,
//                            my_DataStyle inputStyle,
//                            int          inputLength);
//          // Return the buffer size (in bytes) required to store the result
//          // of converting input data of the specified 'inputLength' (in
//          // bytes), in the specified 'inputStyle', into the specified
//          // 'outputStyle'.  The behavior is undefined unless
//          // '0 <= inputLength'.
//
//      static int translate(char         *output,
//                           my_DataStyle  outputStyle,
//                           const char   *input,
//                           my_DataStyle  inputStyle);
//          // Load into the specified 'output' buffer the result of converting
//          // the specified 'input' data, in the specified 'inputStyle', into
//          // the specified 'outputStyle'.  Return 0 on success, and a
//          // non-zero value otherwise.  The behavior is undefined unless
//          // 'output' has sufficient capacity to hold the translated result.
//          // Note that this method assumes that 'input' originated from a
//          // trusted source.
//  };
//..
// Next, we define 'my_DataHandler', a simple class that makes use of
// 'my_DataTranslationUtil':
//..
//  class my_DataHandler {
//      // This 'class' provides a basic data handler.
//
//      // DATA
//      my_DataStyle      d_inStyle;     // style of 'd_inBuffer' contents
//      char             *d_inBuffer;    // input supplied at construction
//      int               d_inCapacity;  // capacity (in bytes) of 'd_inBuffer'
//      my_DataStyle      d_altStyle;    // alternative style (if requested)
//      char             *d_altBuffer;   // buffer for alternative style
//      bslma::Allocator *d_allocator_p; // memory allocator (held, not owned)
//
//    private:
//      // Not implemented:
//      my_DataHandler(const my_DataHandler&);
//
//    public:
//      // CREATORS
//      my_DataHandler(const char       *input,
//                     int               inputLength,
//                     my_DataStyle      inputStyle,
//                     bslma::Allocator *basicAllocator = 0);
//          // Create a data handler for the specified 'input' data, in the
//          // specified 'inputStyle', having the specified 'inputLength' (in
//          // bytes).  Optionally specify a 'basicAllocator' used to supply
//          // memory.  If 'basicAllocator' is 0, the currently installed
//          // default allocator is used.  The behavior is undefined unless
//          // '0 <= inputLength'.
//
//      ~my_DataHandler();
//          // Destroy this data handler.
//
//      // ...
//
//      // MANIPULATORS
//      int generateAlternate(my_DataStyle alternateStyle);
//          // Generate data for this data handler in the specified
//          // 'alternateStyle'.  Return 0 on success, and a non-zero value
//          // otherwise.  If 'alternateStyle' is the same as the style of data
//          // supplied at construction, this method returns 0 with no effect.
//
//      // ...
//  };
//..
// Next, we show the definition of the 'my_DataHandler' constructor:
//..
//  my_DataHandler::my_DataHandler(const char       *input,
//                                 int               inputLength,
//                                 my_DataStyle      inputStyle,
//                                 bslma::Allocator *basicAllocator)
//  : d_inStyle(inputStyle)
//  , d_inBuffer(0)
//  , d_inCapacity(inputLength)
//  , d_altStyle(e_STYLE_NONE)
//  , d_altBuffer(0)
//  , d_allocator_p(bslma::Default::allocator(basicAllocator))
//  {
//      BSLS_ASSERT(0 <= inputLength);
//
//      void *tmp = d_allocator_p->allocate(inputLength);
//      bsl::memcpy(tmp, input, inputLength);
//      d_inBuffer = static_cast<char *>(tmp);
//  }
//..
// Next, we show the definition of the 'generateAlternate' manipulator.  Note
// that we have deliberately introduced a bug in 'generateAlternate' to cause
// buffer overrun:
//..
//  int my_DataHandler::generateAlternate(my_DataStyle alternateStyle)
//  {
//      if (alternateStyle == d_inStyle) {
//          return 0;                                                 // RETURN
//      }
//
//      int altLength = my_DataTranslationUtil::outputSize(alternateStyle,
//                                                         d_inStyle,
//                                                         d_inCapacity);
//      (void)altLength;
//
//      // Oops!  Should have used 'altLength'.
//      char *tmpAltBuffer = (char *)d_allocator_p->allocate(d_inCapacity);
//      int rc = my_DataTranslationUtil::translate(tmpAltBuffer,
//                                                 alternateStyle,
//                                                 d_inBuffer,
//                                                 d_inStyle);
//
//      if (rc) {
//          d_allocator_p->deallocate(tmpAltBuffer);
//          return rc;                                                // RETURN
//      }
//
//      d_altStyle  = alternateStyle;
//      d_altBuffer = tmpAltBuffer;
//
//      return 0;
//  }
//..
// Next, we define some data (in 'e_STYLE_A'):
//..
//  const char *input = "AAAAAAAAAAAAAAA@";  // data always terminated with '@'
//..
// Then, we define a 'my_DataHandler' object, 'handler', to process that data:
//..
//  my_DataHandler handler(input, 16, e_STYLE_A);
//..
// Note that our 'handler' object uses the default allocator.
//
// Next, we request that an alternate data style, 'e_STYLE_AA', be generated by
// 'handler'.  Unfortunately, data in style 'e_STYLE_AA' is twice as large as
// that in style 'e_STYLE_A' making it a virtual certainty that the program
// will crash due to the insufficiently sized buffer that is allocated in the
// 'generateAlternate' method to accommodate the 'e_STYLE_AA' data:
//..
//  int rc = handler.generateAlternate(e_STYLE_AA);
//  if (!rc) {
//      // use data in alternate style
//  }
//..
// Suppose that after performing a brief post-mortem on the resulting core
// file, we strongly suspect that a buffer overrun is the root cause, but the
// program crashed in a context far removed from that of the source of the
// problem (which is often the case with buffer overrun issues).
//
// Consequently, we modify the code to supply a guarding allocator to the
// 'handler' object, then rebuild and rerun the program.  We have configured
// the guarding allocator (below) to place guard pages *after* user blocks.
// Note that 'e_AFTER_USER_BLOCK' is the default, so it need not be specified
// at construction as we have (pedantically) done here:
//..
//  typedef bdlma::GuardingAllocator GA;
//  GA guard(GA::e_AFTER_USER_BLOCK);
//
//  my_DataHandler handler(input, 16, e_STYLE_A, &guard);
//..
// With a guarding allocator now in place, a memory fault is triggered when a
// guard page is overwritten as a result of the buffer overrun bug.  Hence, the
// program will dump core in a context that is more proximate to the buggy
// code, resulting in a core file that will be more amenable to revealing the
// issue when analyzed in a debugger.
//
///Example 2: Allowing for Maximal Alignment
///- - - - - - - - - - - - - - - - - - - - -
// The requirement that this allocator always return maximally aligned memory
// can lead to situations when using 'e_AFTER_USER_BLOCK' where there is unused
// memory between the end of allocated memory and the first address of the
// guard page.  If so, small memory overruns (e.g., a single byte) will not
// land on the guard page and go undetected.  Fortunately, users can often
// compensate for this behavior and position their data adjacent to the guard
// page.
//
// Suppose one must test a function, 'myIntSort', having the signature and
// contract:
//..
//  void myIntSort(int *begin, int *end);
//      // Efficiently sort in place the values in the specified range
//      // '[start .. end - 1]' into ascending order.
//..
// If the 'myIntSort' function uses some manner of partitioning algorithm the
// implementation will involve considerable pointer arithmetic, recursion,
// etc., then a reasonable test concern would be:
//..
//      // Concerns:
//      //: 1 The implementation never modifies or even reads data outside of
//      //:   the given input range.
//      //:
//      //: 2 Some other concern.
//      //:
//      //: 3 Yet another concern.
//      //:
//      //: 4 ...
//..
// Addressing that test concern is ordinarily challenging.  One approach is to
// bracket the data for each test with data having a distinctive value (e.g.,
// '0x0BADCAFE') and then check that the test does not corrupt that pattern
// (any overwrite being *very* unlikely to preserve the special value).  Tests
// of reads past the given range are harder to prove.  One could argue that
// incorporating that data into the sort would corrupt the result but one
// cannot prove that it was never accessed.  Alternatively, using
// 'bdlma::GuardingAllocator' provides a stronger proof from a simpler test
// case.  Thus, our test plan would include:
//..
//      // Plan:
//      //: 1 Test for range overflow and underflow by positioning test data in
//      //:   memory obtained from 'bdlma::GuardingAllocator' objects.  Each
//      //:   test is run twice, once with the guard page below the test data,
//      //:   and again with the guard page above the test data.
//..
// First, create a set of test data for thoroughly testing all concerns of
// 'myIntSort', and a framework for running through those tests:
//..
//  void testMyIntSort()
//      // Thoroughly test the 'myIntSort' function using a table-driven
//      // framework.  Note that the testing concerns were listed above.
//  {
//      const bsl::size_t MAX_NUM_INPUTS = 5;
//      struct {
//          int         d_line;
//          bsl::size_t d_numInputs;
//          int         d_input[MAX_NUM_INPUTS];
//      } DATA [] = {
//          { __LINE__, 1, { 0       } }
//        , { __LINE__, 2, { 2, 1    } }
//
//        // ...
//
//        , { __LINE__, 3, { 2, 1, 3 } }
//
//        // ...
//
//      };
//      const bsl::size_t NUM_DATA = sizeof DATA / sizeof *DATA;
//
//      const int pageSize = myGetPageSize();
//      assert(myIsPowerOfTwo(pageSize));
//
//      for (bsl::size_t ti = 0; ti < NUM_DATA; ++ti) {
//          const int         LINE       = DATA[ti].d_line;  (void) LINE;
//          const bsl::size_t NUM_INPUTS = DATA[ti].d_numInputs;
//          const int *const  INPUT      = DATA[ti].d_input;
//..
// Then, create a 'bdlma::GuardingAllocator to that will be used to test for
// under-runs of the given range and, for each data point, run the test on data
// that will segfault if there is any reference to an address in the page below
// 'begin', even by a single byte:
//..
//          bdlma::GuardingAllocator underRun(
//                              bdlma::GuardingAllocator::e_BEFORE_USER_BLOCK);
//
//          const bsl::size_t  numBytes = NUM_INPUTS * sizeof(int);
//          void              *block    = underRun.allocate(numBytes);
//
//          assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
//                                                                  block,
//                                                                  pageSize));
//
//          bsl::memcpy(block, INPUT, numBytes);
//
//          int *begin = static_cast<int *>(block);
//          int *end   = begin + NUM_INPUTS;
//
//          myIntSort(begin, end);                                      // TEST
//
//          assert(myIsIntSorted(begin, end));  // oracle
//
//          underRun.deallocate(block);
//..
// Notice that, for expository purposes, we confirmed that the 'block' is page
// aligned.
//
// Next, we will *rerun* the test using data positioned in memory to catch
// over-runs of the input range.
//..
//          bdlma::GuardingAllocator overRun(
//                               bdlma::GuardingAllocator::e_AFTER_USER_BLOCK);
//..
// The step would be to allocate memory and initialize memory as we did
// before.  The problem is that memory returned from the
// 'bdlma::GuardingAllocator' may not abut the following guard page.
//
// Consider a platform where:
//: o Maximal alignment is 8 bytes.
//: o 'sizeof(int)' is 4 bytes.
//
// For the data point above consisting of 3 values, the required space is 12
// bytes (3 * 4) but the maximally aligned address closest to the top of the
// returned page is 16 bytes (2 * 8) below the page boundary -- a gap of 4
// bytes.
//
// We handle this situation by padding our allocation size to the nearest
// multiple of maximal alignment -- 16 bytes in this case.  That gives us
// allocated memory that abuts the page boundary.  This allows us to position
// our test data into the allocated memory so that last element fits in the
// upper bytes of the returned bytes (i.e., the first 4 bytes of the returned
// block are not used by this test).
//
// Now, we calculate the padded allocation size and allocate a block that abuts
// the page boundary:
//..
//          const bsl::size_t paddedSize =
//                    bsls::AlignmentUtil::roundUpToMaximalAlignment(numBytes);
//
//          block = overRun.allocate(paddedSize);
//
//          int *firstProtectedAddress = static_cast<int *>(
//               static_cast<void *>(static_cast<char *>(block) + paddedSize));
//
//          begin = firstProtectedAddress - NUM_INPUTS;
//          end   = firstProtectedAddress;
//
//          assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
//                                   block,
//                                   bsls::AlignmentUtil::BSLS_MAX_ALIGNMENT));
//
//          assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
//                                                               begin,
//                                                               sizeof(int)));
//
//          assert(0 == bsls::AlignmentUtil::calculateAlignmentOffset(
//                                                                  end,
//                                                                  pageSize));
//..
// Notice that again, for purposes of exposition, we have checked the returned
// addresses and confirmed:
//: o The returned address, 'block', is maximally aligned.
//: o The calculated 'begin' is correctly aligned to hold the data value.
//: o The upper end of the returned block, 'end', is page aligned.
//
// Finally, we load the test data into the carefully positioned memory and
// rerun the test:
//..
//          bsl::memcpy(begin, INPUT, numBytes);
//
//          myIntSort(begin, end);                                      // TEST
//          assert(myIsIntSorted(begin, end));  // oracle
//
//          overRun.deallocate(block);
//      }
//  }
//..

#include <bdlscm_version.h>

#include <bslma_allocator.h>

#include <bsls_types.h>

namespace BloombergLP {
namespace bdlma {

                         // -----------------------
                         // class GuardingAllocator
                         // -----------------------

class GuardingAllocator : public bslma::Allocator {
    // This class defines a concrete thread-safe "guarding" allocator mechanism
    // that implements the 'bslma::Allocator' protocol, and adjoins a
    // read/write protected guard page to each block of memory returned by the
    // 'allocate' method.  The guard page is placed immediately before or
    // immediately following the block returned from 'allocate' according to
    // the 'GuardPageLocation' enumerator value (optionally) supplied at
    // construction.  Note that, unlike many other allocators, an allocator
    // cannot be (optionally) supplied at construction; instead, a system
    // facility is used that allocates blocks of memory in multiples of the
    // system page size.  Also note that this allocator is intended for
    // debugging purposes *only*.

  public:
    // TYPES
    enum GuardPageLocation {
        // Enumerate the configuration options for 'GuardingAllocator' that may
        // be (optionally) supplied at construction.

        e_AFTER_USER_BLOCK,  // locate the guard page after the user block
        e_BEFORE_USER_BLOCK  // locate the guard page before the user block
    };

  private:
    // DATA
    GuardPageLocation d_guardPageLocation;  // if 'e_AFTER_USER_BLOCK', place
                                            // the read/write protected guard
                                            // page after the user block;
                                            // otherwise, place it before the
                                            // block ('e_BEFORE_USER_BLOCK')

  private:
    // NOT IMPLEMENTED
    GuardingAllocator(const GuardingAllocator&);
    GuardingAllocator& operator=(const GuardingAllocator&);

  public:
    // CREATORS
    explicit
    GuardingAllocator(GuardPageLocation guardLocation = e_AFTER_USER_BLOCK);
        // Create a guarding allocator.  Optionally specify a 'guardLocation'
        // indicating where read/write protected guard pages should be placed
        // with respect to the memory blocks returned by the 'allocate' method.
        // If 'guardLocation' is not specified, guard pages are placed
        // immediately following the memory blocks returned by 'allocate'.

    virtual ~GuardingAllocator();
        // Destroy this allocator object.  Note that destroying this allocator
        // has no effect on any outstanding allocated memory.

    // MANIPULATORS
    virtual void *allocate(bsls::Types::size_type size);
        // Return a newly-allocated maximally-aligned block of memory of the
        // specified 'size' (in bytes) that has a read/write protected guard
        // page located immediately before or after it according to the
        // 'GuardPageLocation' indicated at construction.  If 'size' is 0, no
        // memory is allocated and 0 is returned.  Note that a multiple of the
        // platform's memory page size is allocated for *every* call to this
        // method.

    virtual void deallocate(void *address);
        // Return the memory block at the specified 'address' back to this
        // allocator.  If 'address' is 0, this method has no effect.
        // Otherwise, the guard page associated with 'address' is unprotected
        // and also deallocated.  The behavior is undefined unless 'address'
        // was returned by 'allocate' and has not already been deallocated.
};

// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

                         // -----------------------
                         // class GuardingAllocator
                         // -----------------------

// CREATORS
inline
GuardingAllocator::GuardingAllocator(GuardPageLocation guardLocation)
: d_guardPageLocation(guardLocation)
{
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2016 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------