stdcxx-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From se...@apache.org
Subject svn commit: r370708 - in /incubator/stdcxx/trunk/tests: include/rw_new.h src/new.cpp
Date Fri, 20 Jan 2006 02:55:24 GMT
Author: sebor
Date: Thu Jan 19 18:55:19 2006
New Revision: 370708

URL: http://svn.apache.org/viewcvs?rev=370708&view=rev
Log:
2006-01-19  Martin Sebor  <sebor@roguewave.com>

	STDCXX-3
	* rw_new.h: New header with definitions of replacement operator new.
	* new.cpp: Implementation of replacement operator new with error and
	memory corruption detection.

Added:
    incubator/stdcxx/trunk/tests/include/rw_new.h   (with props)
    incubator/stdcxx/trunk/tests/src/new.cpp   (with props)

Added: incubator/stdcxx/trunk/tests/include/rw_new.h
URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/include/rw_new.h?rev=370708&view=auto
==============================================================================
--- incubator/stdcxx/trunk/tests/include/rw_new.h (added)
+++ incubator/stdcxx/trunk/tests/include/rw_new.h Thu Jan 19 18:55:19 2006
@@ -0,0 +1,193 @@
+/************************************************************************
+ *
+ * rw_new.h - definitions of replacement operator new and delete
+ *
+ * $Id$
+ *
+ ***************************************************************************
+ *
+ * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
+ * Software division. 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.
+ * 
+ **************************************************************************/
+
+#ifndef RW_NEW_H_INCLUDED
+#define RW_NEW_H_INCLUDED
+
+
+// this file must be #included in at most one translation unit in a program
+// (replacement operators new and delete must be defined in at most one
+// translation unit in order not to violate the ODR)
+
+#include <new>          // for bad_alloc
+
+#include <testdefs.h>   // for test config macros
+
+
+struct rwt_free_store
+{
+    // cumulative number of all calls to the ordinary operator new
+    // and the array form of the operator, respectively, regardless
+    // of whether they exited successfully or by throwing an exception
+    _RWSTD_SIZE_T new_calls_ [2];
+
+    // cumulative number of calls to the ordinary operator delete
+    // and the array form of the operator, respectively, regardless
+    // of whether they exited successfully or by throwing an exception
+    _RWSTD_SIZE_T delete_calls_ [2];
+
+    // cumulative number of calls to the ordinary operator delete
+    // and the array form of the operator, respectively, with the
+    // argument of 0
+    _RWSTD_SIZE_T delete_0_calls_ [2];
+
+    // number of blocks currently allocated by the ordinary operator new,
+    // and the array form of the operator, respectively
+    _RWSTD_SIZE_T blocks_ [2];
+
+    // number of bytes currently allocated by the ordinary operator new,
+    // and the array form of the operator, respectively
+    _RWSTD_SIZE_T bytes_ [2];
+
+    // the maximum number of blocks allocated so far by the ordinary
+    // operator new, and the array form of the operator, respectively
+    _RWSTD_SIZE_T max_blocks_ [2];
+
+    // the maximum total amount of storage allocated so far by the ordinary
+    // operator new, and the array form of the operator, respectively
+    _RWSTD_SIZE_T max_bytes_ [2];
+
+    // the size of the largest block allocated so far by the ordinary
+    // operator new, and the array form of the operator, respectively
+    _RWSTD_SIZE_T max_block_size_ [2];
+
+    // pointer to a value which, when equal to new_calls_ [i],
+    // the ordinary operator new (for i == 0) or the array form
+    // of the operator (for i == 1), respectively, will throw
+    // a std::bad_alloc exception
+    _RWSTD_SIZE_T* throw_at_calls_ [2];
+
+    // pointer to a value which, when less than or equal to blocks_ [i]
+    // during the next call to the ordinary operator new (for i == 0) or
+    // the array form of the operator (for i == 1), respectively, will
+    // throw a std::bad_alloc exception
+    _RWSTD_SIZE_T* throw_at_blocks_ [2];
+
+    // pointer to a value which, when less than or equal to bytes_ [i]
+    // during the next call to the ordinary operator new (for i == 0) or
+    // the array form of the operator (for i == 1), respectively, will
+    // throw a std::bad_alloc exception
+    _RWSTD_SIZE_T* throw_at_bytes_ [2];
+
+    // pointer to a value which, when equal to the next block's sequence
+    // number operator new will break or abort
+    _RWSTD_SIZE_T* break_at_seqno_;
+};
+
+
+// returns a pointer to the global rwt_free_store object
+// with a non-zero argument sets the global pointer to the rwt_free_store
+// object to the value of the argument
+_TEST_EXPORT rwt_free_store*
+rwt_get_free_store (rwt_free_store*);
+
+// computes the difference between two states of the free store
+// returns 0 when no difference exists, otherwise a pointer to
+// a rwt_free_store structure describing the differences
+// when both arguments are 0, returns  the difference between
+// the last checkpoint and the current states of the free store,
+// and establishes a new checkpoint
+// when the first argument is 0, returns  the difference between
+// the last checkpoint and the current states of the free store
+// when the second argument is 0, returns the difference between
+// the state specified by the first argument and the current state
+// of the free store
+_TEST_EXPORT rwt_free_store*
+rwt_checkpoint (const rwt_free_store*, const rwt_free_store*);
+
+// returns the number of blocks allocated and not freed since
+// the checkpoint specified by the second argument
+// when the second argument is 0, returns the number of blocks
+// allocated and not freed since the last established checkpoint
+// and establishes a new checkpoint
+_TEST_EXPORT _RWSTD_SIZE_T
+rwt_check_leaks (_RWSTD_SIZE_T*, const rwt_free_store*);
+
+
+// define replacement operator new and delete to keep track
+// of allocated memory and allow for exceptions to be thrown
+
+_TEST_EXPORT void* operator_new (_RWSTD_SIZE_T, bool);
+_TEST_EXPORT void  operator_delete (void*, bool);
+
+#  ifndef _RWSTD_BAD_ALLOC
+     // #define if not #defined by <new> (SunPro #includes its
+     // own <new> regardless of the preprocessor search path)
+#    define _RWSTD_BAD_ALLOC _STD::bad_alloc
+#  endif   // _RWSTD_BAD_ALLOC
+
+
+struct _TEST_EXPORT MyNewInit
+{
+    MyNewInit ();
+    ~MyNewInit ();
+
+private:
+
+    // not defined
+    MyNewInit (const MyNewInit&);
+    void operator= (const MyNewInit&);
+};
+
+// keeps track of dynamic intiatlization
+static MyNewInit mynew_init_tracker;
+
+
+#  ifndef _RWSTD_TEST_SRC
+
+// prevent defining the replacement operator
+// when compiling in the test suite framework
+
+void* operator new (_RWSTD_SIZE_T n) _THROWS ((_RWSTD_BAD_ALLOC))
+{
+    return operator_new (n, false);
+}
+
+void operator delete (void *ptr) _THROWS (())
+{
+    operator_delete (ptr, false);
+}
+
+
+#    if    !defined (_RWSTD_NO_OPERATOR_NEW_ARRAY) \
+        || defined (_RWSTD_NO_EXT_OPERATOR_NEW)
+
+// replaceable only if we don't provide a definition in <new>
+void* operator new[] (_RWSTD_SIZE_T n) _THROWS ((_RWSTD_BAD_ALLOC))
+{
+    return operator_new (n, true);
+}
+
+#    endif   // !_RWSTD_NO_OPERATOR_NEW_ARRAY || _RWSTD_NO_EXT_OPERATOR_NEW
+
+#    if   !defined (_RWSTD_NO_OPERATOR_DELETE_ARRAY) \
+        || defined (_RWSTD_NO_EXT_OPERATOR_NEW)
+
+// replaceable only if we don't provide a definition in <new>
+void operator delete[] (void *ptr) _THROWS (())
+{
+    operator_delete (ptr, true);
+}
+
+
+#    endif   // !_RWSTD_NO_OPERATOR_DELETE_ARRAY || _RWSTD_NO_EXT_OPERATOR_NEW
+#  endif   // !_RWSTD_TEST_SRC
+#endif   // RW_NEW_H_INCLUDED

Propchange: incubator/stdcxx/trunk/tests/include/rw_new.h
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/stdcxx/trunk/tests/include/rw_new.h
------------------------------------------------------------------------------
    svn:keywords = Id

Added: incubator/stdcxx/trunk/tests/src/new.cpp
URL: http://svn.apache.org/viewcvs/incubator/stdcxx/trunk/tests/src/new.cpp?rev=370708&view=auto
==============================================================================
--- incubator/stdcxx/trunk/tests/src/new.cpp (added)
+++ incubator/stdcxx/trunk/tests/src/new.cpp Thu Jan 19 18:55:19 2006
@@ -0,0 +1,698 @@
+/************************************************************************
+ *
+ * new.cpp - definitions of replacement operator new and delete
+ *
+ * $Id$
+ *
+ ************************************************************************
+ *
+ * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
+ * Software division. 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.
+ * 
+ **************************************************************************/
+
+// expand _TEST_EXPORT macros
+#define _RWSTD_TEST_SRC
+
+#include <new>        // for bad_alloc
+
+#include <assert.h>   // for assert()
+#include <stdio.h>    // for fprintf(), stderr
+#include <stdlib.h>   // for abort(), free(), getenv(), malloc()
+#include <string.h>   // for memset()
+
+#include <testdefs.h>
+#include <driver.h>
+#include <printf.h>
+#include <rw_new.h>
+
+/************************************************************************/
+
+#ifndef _RWSTD_BAD_ALLOC
+   // _RWSTD_BAD_ALLOC is #defined in <new> but some compilers (e.g.,
+   // SunPro) insist on #including their own new no matter what the
+   // preprocessor path or what command line options are used
+#  if    !defined (_RWSTD_NO_STD_BAD_ALLOC) \
+      || !defined (_RWSTD_NO_RUNTIME_IN_STD)
+#    define _RWSTD_BAD_ALLOC _STD::bad_alloc
+  #else   // if _RWSTD_NO_STD_BAD_ALLOC && _RWSTD_NO_RUNTIME_IN_STD
+
+     // working around a gcc 2.x bug (PR #24400)
+#    if !defined (__GNUG__) || __GNUG__ > 2
+
+#      define _RWSTD_BAD_ALLOC _STD::bad_alloc
+#    else
+#      define _RWSTD_BAD_ALLOC ::bad_alloc
+#    endif   // gcc > 2.x
+#  endif   // _RWSTD_NO_STD_BAD_ALLOC || !_RWSTD_NO_RUNTIME_IN_STD
+#endif   // _RWSTD_BAD_ALLOC
+
+#ifndef _RWSTD_BAD_ALLOC
+#  ifndef _RWSTD_NO_RUNTIME_IN_STD
+#    define _RWSTD_BAD_ALLOC std::bad_alloc
+#  else
+#    define _RWSTD_BAD_ALLOC bad_alloc
+#  endif   // _RWSTD_NO_RUNTIME_IN_STD
+#endif   // _RWSTD_BAD_ALLOC
+
+/************************************************************************/
+
+// keeps track of the number of pending calls to global dtors
+static size_t static_dtors;
+
+static size_t throw_at_calls [2] = { _RWSTD_SIZE_MAX, _RWSTD_SIZE_MAX };
+static size_t throw_at_blocks [2] = { _RWSTD_SIZE_MAX, _RWSTD_SIZE_MAX };
+static size_t throw_at_bytes [2] = { _RWSTD_SIZE_MAX, _RWSTD_SIZE_MAX };
+static size_t break_at_seqno = _RWSTD_SIZE_MAX;
+
+// enables tracing to stderr between the two sequence numbers
+static size_t trace_sequence [2] = { 0, 0 };
+
+static rwt_free_store store = {
+    { 0, 0 },
+    { 0, 0 },
+    { 0, 0 },
+    { 0, 0 },
+    { 0, 0 },
+    { 0, 0 },
+    { 0, 0 },
+    { 0, 0 },
+    { throw_at_calls, throw_at_calls + 1 },
+    { throw_at_blocks, throw_at_blocks + 1 },
+    { throw_at_bytes, throw_at_bytes + 1 },
+    &break_at_seqno
+};
+
+static rwt_free_store* pst = &store;
+
+
+struct Header
+{
+    Header *prev_;   // link to the previous allocated block
+    Header *next_;   // link to the next allocated block
+    void   *ptr_;    // pointer to user block (== this + 1)
+    size_t  size_;   // size of user block in bytes
+    size_t  id_;     // unique id
+    void*   self_;   // padded to an even multiple of sizeof(size_t)
+                     // with the value of this
+};
+
+
+static Header *last;   // pointer to the most recently allocated block
+
+
+// guard block stored immediately after the end of the user block
+static const char Guard [8] = {
+    '\xf8', '\xf9', '\xfa', '\xfb', '\xfc', '\xfd', '\xfe', '\xff'
+};
+
+
+static void
+_rw_print_heap ();
+
+// find a block by the user pointer in the list of allocated blocks
+static Header*
+_rw_find_block (void *ptr, bool check_heap, const char *caller)
+{
+    size_t nblocks = 0;
+    size_t nbytes  = 0;
+
+    Header *res = 0;
+
+    for (Header *hdr = last; hdr; hdr = hdr->prev_) {
+
+        nblocks += 1;
+        nbytes  += hdr->size_;
+
+        if (check_heap) {
+            // check the lead guard
+            if (hdr->self_ != hdr) {
+                rw_error (0, 0, __LINE__,
+                          "%s:%d: header guard corruption at %p: "
+                          "expected %p, got %p\n",
+                          hdr->ptr_, (const void*)hdr, hdr->self_);
+                abort ();
+            }
+
+            // check that the stored pointer has the expected value
+            if (hdr->ptr_ != hdr + 1) {
+                rw_error (0, 0, __LINE__,
+                          "%s:%d: block address mismatch: "
+                          "expected %p, got %p\n",
+                          __FILE__, __LINE__,
+                          (const void*)(hdr + 1), hdr->ptr_);
+
+                abort ();
+            }
+
+            // check the trailing guard
+            const char* const grd = (char*)hdr->ptr_ + hdr->size_;
+
+            if (memcmp (grd, Guard, sizeof Guard)) {
+
+                size_t off = 0;
+                while (grd [off] == Guard [off])
+                    ++off;
+
+                typedef unsigned char UChar;
+
+                rw_error (0, 0, __LINE__,
+                          "%s:%d: trailing guard corruption at %p "
+                          "+ %zu of a %zu byte block: '0x%02x' != '0x%x'\n",
+                          __FILE__, __LINE__, hdr->ptr_,
+                          hdr->size_ + off + 1, hdr->size_,
+                          UChar (grd [off]), UChar (Guard [off]));
+
+                abort ();
+            }
+        }
+
+        if (ptr == hdr->ptr_) {
+            res = hdr;
+
+            if (!check_heap)
+                return res;
+        }
+    }
+
+    if (check_heap) {
+        // check that block and byte counters match the totals computed above
+        const size_t sum_blocks = pst->blocks_ [0] + pst->blocks_ [1];
+        const size_t sum_bytes  = pst->bytes_ [0] + pst->bytes_ [1];
+
+        if (sum_blocks != nblocks || sum_bytes != nbytes) {
+            rw_error (0, 0, __LINE__,
+                      "%s:%d: counts mismatch: found %zu "
+                      "bytes in %zu blocks, expected "
+                      "%zu in %zu\n", __FILE__, __LINE__, 
+                      nbytes, nblocks, sum_bytes, sum_blocks);
+
+            abort ();
+        }
+    }
+
+    if (caller && ptr && !res) {
+
+#if !defined (__DECCXX_VER) || __DECCXX_VER >= 60600000
+
+        rw_error (0, 0, __LINE__,  
+                  "%s:%d: %s (%p): invalid pointer\n",
+                  __FILE__, __LINE__, caller, ptr);
+
+        _rw_print_heap ();
+
+        abort ();
+
+#else
+
+        // working around a bug in Compaq C++ libcxx
+        // Classic Iostreams library (see bug #359)
+        if (static_dtors) {
+
+            rw_error (0, 0, __LINE__, 
+                      "%s:%d: %s (%p): invalid pointer\n",
+                      __FILE__, __LINE__, caller, ptr);
+
+            print_heap ();
+
+            abort ();
+        }
+        else {
+
+            static int warned;
+
+            if (!warned++) {
+                rw_warning (0, 0, __LINE__,
+                            "%s:%d: %s (%p): warning: invalid pointer; "
+                            "ignoring memory errors from here on out\n",
+                            __FILE__, __LINE__, caller, ptr);
+            }
+        }
+
+#endif   // Compaq C++ >= 6.6
+
+    }
+
+    return res;
+}
+
+
+// print the list of allocated blocks and check heap consistency
+static void
+_rw_print_heap ()
+{
+    rw_info (0, 0, __LINE__,
+             "%s:%d: heap dump:\n%zu bytes in %zu blocks%s\n",
+             __FILE__, __LINE__, pst->bytes_, pst->blocks_, last ? ":" : "");
+
+    for (Header *hdr = last; hdr; hdr = hdr->prev_) {
+
+        const size_t seq = hdr->id_;
+        const bool array = !!(seq >> (_RWSTD_CHAR_BIT * sizeof (size_t) - 1));
+
+        rw_info (0, 0, __LINE__, 
+                 "%zu: %zu bytes at %p allocated by operator new%s()\n",
+                 hdr->id_, hdr->size_, hdr->ptr_, array ? "[]" : "");
+    }
+
+    if (last) 
+        // check heap consistency
+        _rw_find_block (last, true, 0);
+}
+
+
+struct BadAlloc: _RWSTD_BAD_ALLOC
+{
+    char what_ [4096];
+
+    /* virtual */ const char* what () const _THROWS (()) {
+        return what_;
+    }
+};
+
+
+static size_t seq_gen;   // sequence number generator
+
+
+_TEST_EXPORT void*
+operator_new (size_t nbytes, bool array)
+{
+    if (0 == trace_sequence [0] && trace_sequence [0] == trace_sequence [1]) {
+
+        // the first time opetato new is called try to get options
+        // from the environment by checking the RWSTD_NEW_FLAGS
+        // environment variable in the following format:
+        //
+        // RWSTD_NEW_FLAGS=[<seqrange>][:<break-seqno>]
+        // seqrange ::= <start-seqno>[-<end-seqno>]
+
+        static const char* envvar = getenv ("RWSTD_NEW_FLAGS");
+
+        if (envvar) {
+            char *end = _RWSTD_CONST_CAST (char*, envvar);
+
+            if ('-' == *end) {
+                // begin tracing with the sequence number 0
+                trace_sequence [0] = 0;
+            }
+            else {
+                // begin tracing with the given sequence number
+                trace_sequence [0] = strtoul (end, &end, 10);
+            }
+
+            if ('-' == *end) {
+                // end tracing with the given sequence number
+                ++end;
+                trace_sequence [1] = strtoul (end, &end, 10);
+            }
+            else {
+                // continue tracing indefinitely
+                trace_sequence [1] = _RWSTD_SIZE_MAX;
+            }
+
+            if (':' == *end) {
+                // break at the given seuqence number
+                ++end;
+                *pst->break_at_seqno_ = strtoul (end, &end, 10);
+            }
+        }
+    }
+
+    static const char* const name[] = {
+        "operator new", "operator new[]"
+    };
+
+    // increment the call counter regardless of success
+    ++pst->new_calls_ [array];
+
+    // prevent warnings about unused variable and/or unreachable statement
+    void *ptr = 0;
+
+    const bool reached_call_limit =
+        pst->new_calls_ [array] == *pst->throw_at_calls_ [array];
+    const bool reached_block_limit =
+        pst->blocks_ [array] >= *pst->throw_at_blocks_ [array];
+    const bool reached_size_limit =
+        pst->bytes_ [array] + nbytes >= *pst->throw_at_bytes_ [array];
+
+    const bool reached_breakpoint = seq_gen == *pst->break_at_seqno_;
+
+    if (reached_breakpoint) {
+        char buffer [128];
+        rw_snprintfa (buffer, 128, 
+                      "%s (%zu): breakpoint at sequence number %zu",
+                      name [array], nbytes, *pst->break_at_seqno_);
+
+        // abort() when a breakpoint has been reached
+        _RW::__rw_assert_fail (buffer, __FILE__, __LINE__, 0);
+
+        // should not get here except when the program handles
+        // SIGABRT and returns from the handler
+    }
+
+    if (   reached_call_limit
+        || reached_block_limit
+        || reached_size_limit) {
+
+        BadAlloc ex;
+
+#ifndef _RWSTD_NO_EXCEPTIONS
+
+        rw_snprintfa (ex.what_, 4096U, "%s:%d: %s (%zu) ",
+                      __FILE__, __LINE__, name [array], nbytes);
+
+        strcat (ex.what_, "threw bad_alloc: ");
+
+        if (reached_call_limit)
+
+            rw_snprintfa (
+                ex.what_ + strlen (ex.what_), 4096U - strlen (ex.what_),
+                "reached call limit of %zu", pst->new_calls_ [array]);
+
+        else if (reached_block_limit)
+
+            rw_snprintfa (
+                ex.what_ + strlen (ex.what_), 4096U - strlen (ex.what_),
+                "reached block limit of %zu: %zu", 
+                *pst->throw_at_blocks_ [array], pst->blocks_ [array]);
+
+        else if (reached_size_limit)
+
+            rw_snprintfa (
+                ex.what_ + strlen (ex.what_), 4096U - strlen (ex.what_),
+                "reached size limit of %zu: %zu",
+                *pst->throw_at_bytes_ [array], pst->bytes_ [array]);
+
+        if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
+            rw_fprintf (rw_stderr, "%s\n", ex.what ());
+
+        throw ex;
+
+#else   // if defined (_RWSTD_NO_EXCEPTIONS)
+
+        if (reached_breakpoint) {
+            rw_snprintfa (
+                ex.what_ + strlen (ex.what_), 4096U - strlen (ex.what_),
+                "reached a breakpoint at of %zu calls", *pst->break_at_seqno_);
+
+            _RW::__rw_assert_fail (ex.what_, __FILE__, __LINE__, name [array]);
+        }
+
+        if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
+            rw_fprintf (rw_stderr, "%s:%d: %s (%zi) --> %p\n",
+                        __FILE__, __LINE__, name [array], nbytes, ptr);
+
+        return 0;
+
+#endif   // _RWSTD_NO_EXCEPTIONS
+
+    }
+
+    const size_t block_size = nbytes + sizeof (Header) + sizeof (Guard);
+
+    // prevent arithmetic overflow
+    if (nbytes < block_size)
+        ptr = malloc (block_size);
+
+    if (!ptr) {
+        BadAlloc ex;
+        rw_snprintfa (ex.what_, 4096U, 
+                      "%s:%d: %s (%zu) threw bad_alloc: malloc() returned 0",
+                      __FILE__, __LINE__, name [array], nbytes);
+        
+        if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
+            rw_fprintf (rw_stderr, "%s\n", ex.what ());
+
+#ifndef _RWSTD_NO_EXCEPTIONS
+        throw ex;
+#else   // if defined (_RWSTD_NO_EXCEPTIONS)
+        return ptr;
+#endif   // _RWSTD_NO_EXCEPTIONS
+    }
+
+    // invalidate storage
+    memset (ptr, -1, block_size);
+
+    // increment counters
+    pst->blocks_ [array] += 1;
+    pst->bytes_ [array]  += nbytes;
+
+    // adjust the maximum total number of blocks ever allocated
+    if (pst->blocks_ [array] > pst->max_blocks_ [array])
+        pst->max_blocks_ [array] = pst->blocks_ [array];
+
+    // adjust the maximum total number of bytes ever allocated
+    if (pst->bytes_ [array] > pst->max_bytes_ [array])
+        pst->max_bytes_ [array] = pst->bytes_ [array];
+
+    // adjust the size of the single largest block ever allocated
+    if (nbytes > pst->max_block_size_ [array])
+        pst->max_block_size_ [array] = nbytes;
+
+    // copy guard to the end of the allocated block
+    memcpy ((char*)ptr + sizeof (Header) + nbytes, Guard, sizeof (Guard));
+
+    Header* const hdr = (Header*)ptr;
+
+    hdr->ptr_  = (Header*)ptr + 1;
+    hdr->size_ = nbytes;
+    hdr->id_   = array ? ~seq_gen : seq_gen;
+    hdr->self_ = hdr;
+
+    if (0 == last) {
+        hdr->prev_ = 0;
+        hdr->next_ = 0;
+    }
+    else {
+        hdr->next_  = 0;
+        hdr->prev_  = last;
+        last->next_ = hdr;
+    }
+
+    last = hdr;
+
+    if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
+        rw_error (0, 0, __LINE__,
+                  "%s:%d: %3zi. %s (%zi) --> %p\n", 
+                  __FILE__, __LINE__, seq_gen, 
+                  name [array], nbytes, hdr->ptr_);
+
+    ++seq_gen;
+
+    _rw_find_block (hdr->ptr_, true, 0);
+
+    return hdr->ptr_;
+}
+
+
+_TEST_EXPORT void
+operator_delete (void *ptr, bool array)
+{
+    static const char* const name[] = {
+        "operator delete", "operator delete[]"
+    };
+
+    // increment the call counter regardless of success
+    ++pst->delete_calls_ [array];
+
+    if (ptr) {
+
+        // find the block of memory that `ptr' was allocated from
+        // and check the whole heap in the process; the call will
+        // abort if any block has been corrupted
+        Header* const hdr = _rw_find_block (ptr, true, name [array]);
+
+        if (!hdr) {
+
+            // hdr should never be 0 except under special circumstances
+            // such as when the compiler's runtime library itself passes
+            // the wrong argument to operator delete (such as libcxx
+            // on True64 with Compaq C++ -- see bug #359)
+            free (ptr);
+
+            return;
+        }
+
+        const size_t nbytes = hdr->size_;
+        
+        bool mismatch;
+
+        size_t seq = hdr->id_;
+        if (seq >> (_RWSTD_CHAR_BIT * sizeof (size_t) - 1)) {
+
+            // the MSB of the stored sequence number is set
+            // for blocks allocated with the array form of
+            // operator new and must be deallocated with
+            // the corresponding array form of operator
+            // delete
+            mismatch = !array;
+            seq      = ~seq;
+        }
+        else {
+            mismatch = array;
+        }
+
+        if (trace_sequence [0] <= seq && seq < trace_sequence [1]) {
+            rw_error (0, 0, __LINE__, "%s:%d: %3zi. %s (%p); size = %zi%s\n",
+                      __FILE__, __LINE__, seq, name [array], ptr, nbytes,
+                      mismatch ? ": array form mismatch" : "");
+        }
+        else if (mismatch) {
+
+            const size_t ord = (seq + 1) % 10;
+
+            const char* const ord_sfx =
+                1 == ord ? "st" : 2 == ord ? "nd" : 3 == ord ? "rd" : "th";
+
+            rw_error (0, 0, __LINE__,
+                      "%s:%d: deallocation mismatch: "
+                      "pointer allocated %zi%s in the program "
+                      "with a call to operator new%s(%zi) "
+                      "being deallocated with the wrong form of %s(%p)\n",
+                      __FILE__, __LINE__,
+                      seq + 1, ord_sfx, array ? "" : "[]",
+                      nbytes, name [array], ptr);
+            abort ();
+        }
+
+        // decrement block and byte counters and remove block
+        // from the list only after all checks have succeeded
+        // so that tests that catch SIGABRT sent by one of the
+        // calls to abort() above and retry the operation may
+        // succeed
+        pst->blocks_ [array] -= 1;
+        pst->bytes_ [array]  -= nbytes;
+
+        if (hdr->prev_)
+            hdr->prev_->next_ = hdr->next_;
+        if (hdr->next_)
+            hdr->next_->prev_ = hdr->prev_;
+
+        if (hdr == last)
+            last = hdr->prev_;
+
+        const size_t block_size = nbytes + sizeof (Header) + sizeof (Guard);
+        
+        // invalidate the entire block including bookkeeping data
+        memset (hdr, -1, block_size);
+
+        free (hdr);
+    }
+    else {
+        ++pst->delete_0_calls_ [array];
+
+        if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
+            rw_error (0, 0, __LINE__, "%s:%d: %s (0)\n", 
+                      __FILE__, __LINE__, name [array]);
+    }
+}
+
+_TEST_EXPORT rwt_free_store*
+rwt_get_free_store (rwt_free_store *st)
+{
+    rwt_free_store* const ret = pst;
+
+    if (st)
+        pst = st;
+
+    return ret;
+}
+
+
+_TEST_EXPORT rwt_free_store*
+rwt_checkpoint (const rwt_free_store *st0, const rwt_free_store *st1)
+{
+    static rwt_free_store checkpoint;
+
+    if (st0 && st1) {
+
+        // compute the difference between the two states
+        // of the free_store specified by the arguments
+
+        static rwt_free_store diff;
+
+        memset (&diff, 0, sizeof diff);
+
+        size_t*       diffs    = diff.new_calls_;
+        const size_t* st0_args = st0->new_calls_;
+        const size_t* st1_args = st1->new_calls_;
+
+        bool diff_0 = true;   // difference of 0 (i.e., none)
+
+        for (size_t i = 0; i != 16; ++i) {
+            diffs [i] = st1_args [i] - st0_args [i];
+            if (diffs [i])
+                diff_0 = false;
+        }
+
+        if (diff_0)
+            return 0;
+
+        return &diff;
+    }
+
+    if (!st0 && !st1) {
+        // compute the difference between the most recent checkpoint
+        // and the current state of the free store; store the current
+        // state as the new checkpoint
+
+        _rw_find_block (0, true, 0);
+
+        rwt_free_store* const ckpt = rwt_checkpoint (&checkpoint, pst);
+
+        memcpy (&checkpoint, pst, sizeof checkpoint);
+
+        return ckpt;
+    }
+
+    if (st0) {
+        // compute the difference between the checkpoint specified by
+        // the first argument and the current state of the free store
+        // store the current state as the last checkpoint
+
+        return rwt_checkpoint (st0, pst);
+    }
+
+    // compute the difference between the most recent checkpoint and
+    // the checkpoint specified by the second argument
+
+    return rwt_checkpoint (&checkpoint, st1);
+}
+
+
+_TEST_EXPORT _RWSTD_SIZE_T
+rwt_check_leaks (_RWSTD_SIZE_T *bytes, const rwt_free_store *st)
+{
+    const rwt_free_store* const ckpt = rwt_checkpoint (st, 0);
+
+    if (ckpt) {
+        if (bytes)
+            *bytes = ckpt->bytes_ [0] + ckpt->bytes_ [1];
+
+        return ckpt->blocks_ [0] + ckpt->blocks_ [1];
+    }
+
+    if (bytes)
+        *bytes = 0;
+
+    return 0;
+}
+
+
+MyNewInit::MyNewInit ()
+{
+    ++static_dtors;
+}
+
+MyNewInit::~MyNewInit ()
+{
+    --static_dtors;
+}

Propchange: incubator/stdcxx/trunk/tests/src/new.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/stdcxx/trunk/tests/src/new.cpp
------------------------------------------------------------------------------
    svn:keywords = Id



Mime
View raw message