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 <[EMAIL PROTECTED]>
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