30#define _RWSTD_TEST_SRC
42#ifndef _RWSTD_BAD_ALLOC
46# if !defined (_RWSTD_NO_STD_BAD_ALLOC) \
47 || !defined (_RWSTD_NO_RUNTIME_IN_STD)
48# define _RWSTD_BAD_ALLOC _STD::bad_alloc
52# if !defined (__GNUG__) || __GNUG__ > 2
54# define _RWSTD_BAD_ALLOC _STD::bad_alloc
56# define _RWSTD_BAD_ALLOC ::bad_alloc
61#ifndef _RWSTD_BAD_ALLOC
62# ifndef _RWSTD_NO_RUNTIME_IN_STD
63# define _RWSTD_BAD_ALLOC std::bad_alloc
65# define _RWSTD_BAD_ALLOC bad_alloc
72static size_t static_dtors;
74static size_t throw_at_calls [2] = { _RWSTD_SIZE_MAX, _RWSTD_SIZE_MAX };
75static size_t throw_at_blocks [2] = { _RWSTD_SIZE_MAX, _RWSTD_SIZE_MAX };
76static size_t throw_at_bytes [2] = { _RWSTD_SIZE_MAX, _RWSTD_SIZE_MAX };
77static size_t break_at_seqno = _RWSTD_SIZE_MAX;
80static size_t trace_sequence [2] = { 0, 0 };
91 { throw_at_calls, throw_at_calls + 1 },
92 { throw_at_blocks, throw_at_blocks + 1 },
93 { throw_at_bytes, throw_at_bytes + 1 },
116static const char Guard [8] = {
117 '\xf8',
'\xf9',
'\xfa',
'\xfb',
'\xfc',
'\xfd',
'\xfe',
'\xff'
126_rw_find_block (
void *
ptr,
bool check_heap,
const char *caller)
136 nbytes += hdr->
size_;
140 if (hdr->self_ != hdr) {
142 "%s:%d: header guard corruption at %#p: "
143 "expected %#p, got %#p",
144 hdr->ptr_, (
const void*)hdr, hdr->self_);
149 if (hdr->ptr_ != hdr + 1) {
151 "%s:%d: block address mismatch: "
152 "expected %#p, got %#p",
154 (
const void*)(hdr + 1), hdr->ptr_);
160 const char*
const grd = (
char*)hdr->ptr_ + hdr->size_;
162 if (memcmp (grd, Guard,
sizeof Guard)) {
165 while (grd [
off] == Guard [
off])
168 typedef unsigned char UChar;
171 "%s:%d: trailing guard corruption at %#p "
172 "+ %zu of a %zu byte block: '0x%02x' != '0x%x'",
173 __FILE__, __LINE__, hdr->ptr_,
174 hdr->size_ +
off + 1, hdr->size_,
181 if (
ptr == hdr->ptr_) {
192 const size_t sum_bytes = pst->
bytes_ [0] + pst->
bytes_ [1];
194 if (sum_blocks != nblocks || sum_bytes != nbytes) {
196 "%s:%d: counts mismatch: found %zu "
197 "bytes in %zu blocks, expected "
198 "%zu in %zu", __FILE__, __LINE__,
199 nbytes, nblocks, sum_bytes, sum_blocks);
205 if (caller &&
ptr && !
res) {
207#if !defined (__DECCXX_VER) || __DECCXX_VER >= 60600000
210 "%s:%d: %s (%#p): invalid pointer",
211 __FILE__, __LINE__, caller,
ptr);
224 "%s:%d: %s (%#p): invalid pointer",
225 __FILE__, __LINE__, caller,
ptr);
235 rw_warn (0 < warned++, 0, __LINE__,
236 "%s:%d: %s (%#p): warning: invalid pointer; "
237 "ignoring memory errors from here on out",
238 __FILE__, __LINE__, caller,
ptr);
254 "%s:%d: heap dump:\n%zu bytes in %zu blocks%s",
255 __FILE__, __LINE__, pst->
bytes_, pst->
blocks_, last ?
":" :
"");
259 const size_t seq = hdr->id_;
260 const bool array = !!(seq >> (_RWSTD_CHAR_BIT *
sizeof (size_t) - 1));
263 "%zu: %zu bytes at %#p allocated by operator new%s()",
264 hdr->id_, hdr->size_, hdr->ptr_,
array ?
"[]" :
"");
269 _rw_find_block (last,
true, 0);
273static size_t seq_gen;
279 if (0 == trace_sequence [0] && trace_sequence [0] == trace_sequence [1]) {
288 static const char* envvar = getenv (
"RWSTD_NEW_FLAGS");
295 trace_sequence [0] = 0;
299 trace_sequence [0] = strtoul (
end, &
end, 10);
305 trace_sequence [1] = strtoul (
end, &
end, 10);
309 trace_sequence [1] = _RWSTD_SIZE_MAX;
320 static const char*
const name[] = {
321 "operator new",
"operator new[]"
330 const bool reached_call_limit =
332 const bool reached_block_limit =
334 const bool reached_size_limit =
339 if (reached_breakpoint) {
342 "%s (%zu): breakpoint at sequence number %zu",
346 _RW::__rw_assert_fail (
buffer, __FILE__, __LINE__, 0);
352 if ( reached_call_limit
353 || reached_block_limit
354 || reached_size_limit) {
356#ifndef _RWSTD_NO_EXCEPTIONS
359 const char * threw =
"threw bad_alloc:";
361 if (reached_call_limit)
364 "(%zu) %s reached call limit of %zu",
367 else if (reached_block_limit)
370 "(%zu) %s reached block limit of %zu: %zu",
374 else if (reached_size_limit)
377 "(%zu) %s reached size limit of %zu: %zu",
382 if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
390 if (reached_breakpoint) {
396 _RW::__rw_assert_fail (
buf, __FILE__, __LINE__,
name [
array]);
399 if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
409 const size_t block_size = nbytes +
sizeof (
Header) +
sizeof (Guard);
412 if (nbytes < block_size)
413 ptr = malloc (block_size);
417#ifndef _RWSTD_NO_EXCEPTIONS
422 "(%zu): malloc() returned 0", nbytes);
425 if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
437 memset (
ptr, -1, block_size);
456 memcpy ((
char*)
ptr +
sizeof (
Header) + nbytes, Guard,
sizeof (Guard));
462 hdr->
id_ =
array ? ~seq_gen : seq_gen;
477 if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
479 "%s:%d: %3zi. %s (%zu) --> %#p",
480 __FILE__, __LINE__, seq_gen,
485 _rw_find_block (hdr->
ptr_,
true, 0);
494 static const char*
const name[] = {
495 "operator delete",
"operator delete[]"
518 const size_t nbytes = hdr->
size_;
522 size_t seq = hdr->
id_;
523 if (seq >> (_RWSTD_CHAR_BIT *
sizeof (
size_t) - 1)) {
537 if (trace_sequence [0] <= seq && seq < trace_sequence [1]) {
539 rw_error (0, 0, __LINE__,
"%s:%d: %3zi. %s (%#p); size = %zu"
540 ": array form mismatch",
543 rw_note (0, 0, __LINE__,
"%s:%d: %3zi. %s (%#p); size = %zu",
548 const size_t ord = (seq + 1) % 10;
550 const char*
const ord_sfx =
551 1 == ord ?
"st" : 2 == ord ?
"nd" : 3 == ord ?
"rd" :
"th";
554 "%s:%d: deallocation mismatch: "
555 "pointer allocated %zu%s in the program "
556 "with a call to operator new%s(%zu) "
557 "being deallocated with the wrong form of %s(%#p)",
559 seq + 1, ord_sfx,
array ?
"" :
"[]",
580 const size_t block_size = nbytes +
sizeof (
Header) +
sizeof (Guard);
583 memset (hdr, -1, block_size);
590 if (trace_sequence [0] <= seq_gen && seq_gen < trace_sequence [1])
591 rw_note (0, 0, __LINE__,
"%s:%d: %s (0)",
608rwt_checkpoint_compare (
size_t* diffs,
size_t n,
609 const size_t* st0,
const size_t* st1,
612 for (
size_t i = 0;
i !=
n; ++
i) {
613 diffs [
i] = st1 [
i] - st0 [
i];
630 memset (&diff, 0,
sizeof diff);
634#define EXTENT(array) (sizeof (array) / sizeof(*array))
635#define COMPARE(member) \
636 rwt_checkpoint_compare (diff.member, EXTENT(diff.member), \
637 st0->member, st1->member, diff_0)
659 _rw_find_block (0,
true, 0);
663 memcpy (&checkpoint, pst,
sizeof checkpoint);
void(* operator_delete)(void *, void *)
void *(* operator_new)(size_t, void *)
#define _RWSTD_CONST_CAST(T, x)
_TEST_EXPORT _RWSTD_SIZE_T rwt_check_leaks(_RWSTD_SIZE_T *bytes, const rwt_free_store *st)
_TEST_EXPORT rwt_free_store * rwt_get_free_store(rwt_free_store *st)
_TEST_EXPORT rwt_free_store * rwt_checkpoint(const rwt_free_store *st0, const rwt_free_store *st1)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
_TEST_EXPORT int rw_note(int, const char *, int, const char *,...)
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)
_TEST_EXPORT int rw_warn(int, const char *, int, const char *,...)
_TEST_EXPORT void rw_throw(ExceptionId exid, const char *file, int line, const char *function, const char *fmt,...)
_TEST_EXPORT rw_file *const rw_stderr
_TEST_EXPORT char * rw_snprintfa(char *buf, _RWSTD_SIZE_T bufsize, const char *fmt,...)
_TEST_EXPORT int rw_fprintf(rw_file *, const char *,...)
_RWSTD_SIZE_T delete_calls_[2]
_RWSTD_SIZE_T * throw_at_bytes_[2]
_RWSTD_SIZE_T max_blocks_[2]
_RWSTD_SIZE_T max_bytes_[2]
_RWSTD_SIZE_T delete_0_calls_[2]
_RWSTD_SIZE_T * throw_at_calls_[2]
_RWSTD_SIZE_T max_block_size_[2]
_RWSTD_SIZE_T * break_at_seqno_
_RWSTD_SIZE_T new_calls_[2]
_RWSTD_SIZE_T * throw_at_blocks_[2]