Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
0.new.cpp
Go to the documentation of this file.
1
29#include <new> // for bad_alloc
30
31#include <cstddef> // for size_t
32
33#include <setjmp.h> // for longjmp(), setjmp()
34#include <signal.h> // for SIGABRT, signal()
35
36#include <rw_new.h>
37#include <rw_driver.h>
38
39
41// program exit status
42int exit_status /* = 0 */;
43
44extern "C" {
45
46volatile int line; // currently executed line
47volatile int fail; // non-zero when line failed
48
49jmp_buf env;
50
51static void
52handle_ABRT (int)
53{
54 fail = 0;
55
56 longjmp (env, 1);
57}
58
59}
60
61#define FAIL(code) \
62 fail = line = __LINE__; \
63 signal (SIGABRT, handle_ABRT); \
64 if (0 == setjmp (env)) { \
65 code; \
66 exit_status = 1; \
67 rw_assert (0, __FILE__, line, "expected assertion"); \
68 } \
69 else \
70 (void)0
71
72#define PASS(code) \
73 fail = -1; line = __LINE__; \
74 signal (SIGABRT, handle_ABRT); \
75 if (0 == setjmp (env)) { \
76 code; \
77 } \
78 else if (fail != line) { \
79 exit_status = 1; \
80 rw_assert (0, __FILE__, line, "unexpected assertion"); \
81 } (void)0
82
83
86{
87 rw_info (0, __FILE__, __LINE__,
88 "exercising successful allocation and deallocation");
89
90 {
91 void *p = 0;
92 PASS (p = operator new (0));
93 rw_assert (p != 0, __FILE__, __LINE__, "operator new(0) != 0");
94 operator delete (p);
95 }
96
97 {
98 void *p = 0;
99 PASS (p = operator new (1));
100 rw_assert (p != 0, __FILE__, __LINE__, "operator new(1) != 0");
101 operator delete (p);
102 }
103
104 {
105 void *p = 0;
106 PASS (p = operator new (2));
107 rw_assert (p != 0, __FILE__, __LINE__, "operator new(2) != 0");
108 operator delete (p);
109 }
110
111 {
112 void *p = 0;
113 PASS (p = operator new (1024));
114 rw_assert (p != 0, __FILE__, __LINE__, "operator new(1024) != 0");
115 operator delete (p);
116 }
117}
118
119
121#define CATCH(code) \
122 try { code; fail = 1; } \
123 catch (_RWSTD_BAD_ALLOC) { fail = 0; } \
124 catch (...) { fail = 2; } \
125 rw_assert (!fail, __FILE__, __LINE__, \
126 "%s", 1 == fail ? "failed to throw" : \
127 "threw an unknown exception")
128
129#define NOTHROW(code) \
130 try { fail = 0; code; } \
131 catch (...) { fail = 1; } \
132 rw_assert (!fail, __FILE__, __LINE__, \
133 "unexpected exception")
134
136{
137 rw_info (0, __FILE__, __LINE__,
138 "exercising the ability of ordinary "
139 "operator new to throw std::bad_alloc");
140
141 rwt_free_store* const pst = rwt_get_free_store (0);
142
143 *pst->throw_at_blocks_ [0] = pst->blocks_ [0];
144
145 CATCH (operator new (0));
146 CATCH (operator new (1));
147 CATCH (operator new (2));
148 CATCH (operator new (1024));
149
150 {
151 void *p = 0;
152 NOTHROW (p = operator new[](0));
153 operator delete[](p);
154 }
155
156 {
157 void *p = 0;
158 NOTHROW (p = operator new[](1));
159 operator delete[](p);
160 }
161
162 {
163 void *p = 0;
164 NOTHROW (p = operator new[](2));
165 operator delete[](p);
166 }
167
168 {
169 void *p = 0;
170 NOTHROW (p = operator new[](1024));
171 operator delete[](p);
172 }
173
174 rw_info (0, __FILE__, __LINE__,
175 "exercising the ability of the array form "
176 "of operator new to throw std::bad_alloc");
177
178 *pst->throw_at_blocks_ [0] = std::size_t (-1);
179 *pst->throw_at_blocks_ [1] = pst->blocks_ [1];
180
181 CATCH (operator new[](0));
182 CATCH (operator new[](1));
183 CATCH (operator new[](2));
184 CATCH (operator new[](1024));
185
186 {
187 void *p = 0;
188 NOTHROW (p = operator new (0));
189 rw_assert (p != 0, __FILE__, __LINE__, "operator new[](0) != 0");
190 operator delete (p);
191 }
192
193 {
194 void *p = 0;
195 NOTHROW (p = operator new (1));
196 rw_assert (p != 0, __FILE__, __LINE__, "operator new[](1) != 0");
197 operator delete (p);
198 }
199
200 {
201 void *p = 0;
202 NOTHROW (p = operator new (32));
203 rw_assert (p != 0, __FILE__, __LINE__, "operator new[](32) != 0");
204 operator delete (p);
205 }
206
207 {
208 void *p = 0;
209 NOTHROW (p = operator new (4096));
210 rw_assert (p != 0, __FILE__, __LINE__, "operator new[](4096) != 0");
211 operator delete (p);
212 }
213
214 *pst->throw_at_blocks_ [1] = std::size_t (-1);
215}
216
217
220{
221 rw_info (0, __FILE__, __LINE__,
222 "exercising the ability to detect "
223 "allocation/deallocation mismatches");
224
225 {
226 // detect allocations by operator new() deallocated
227 // using (the array form of) operator delete[]
228 void *p = 0;
229 PASS (p = operator new (0));
230 FAIL (operator delete[](p));
231 PASS (operator delete (p));
232 }
233
234 {
235 void *p = 0;
236 PASS (p = operator new (1));
237 FAIL (operator delete[](p));
238 PASS (operator delete (p));
239 }
240
241 {
242 void *p = 0;
243 PASS (p = operator new[](33));
244 FAIL (operator delete (p));
245 PASS (operator delete[] (p));
246 }
247}
248
249
252{
253 rw_info (0, __FILE__, __LINE__,
254 "exercising the ability to detect "
255 "deletion of unallocated storage");
256
257 {
258 char *p = 0;
259 PASS (p = new char);
260
261 FAIL (delete (p - 1));
262 FAIL (delete (p + 1));
263
264 PASS (delete (p));
265 }
266
267 {
268 char *p = 0;
269 PASS (p = new char [4]);
270
271 FAIL (delete (p - 1));
272 FAIL (delete (p + 1));
273 FAIL (delete (p + 2));
274 FAIL (delete (p + 3));
275 FAIL (delete (p + 4));
276
277 FAIL (delete[] (p - 1));
278 FAIL (delete[] (p + 1));
279 FAIL (delete[] (p + 2));
280 FAIL (delete[] (p + 3));
281 FAIL (delete[] (p + 4));
282
283 PASS (delete[] p);
284 }
285}
286
287
290{
291 rw_info (0, __FILE__, __LINE__,
292 "exercising the ability to detect double deletion");
293
294 {
295 char *p = 0;
296 PASS (p = new char);
297
298 PASS (delete (p));
299 FAIL (delete (p));
300 }
301
302 {
303 char *p = 0;
304 PASS (p = new char [32]);
305
306 PASS (delete[] p);
307 FAIL (delete[] p);
308 FAIL (delete p);
309 }
310}
311
312
315{
316 rw_info (0, __FILE__, __LINE__,
317 "exercising the ability to detect memory corruption");
318
319 // corrupt (and restore) memory past the end of the allocated block
320 for (std::size_t i = 1; i != 8; ++i) {
321 char *p = 0;
322 PASS (p = new char);
323
324 // save the value of the byte past the end of the block
325 // and temporarily overwrite it with another value
326 const char save = p [i];
327 p [i] = ~p [i];
328
329 // expect operator delete to diagnose the corruption
330 // and call abort() without actually freeing the block
331 FAIL (delete p);
332
333 // restore the corrupted byte to its original value
334 p [i] = save;
335
336 // expect operator delete not to complain
337 PASS (delete p);
338 }
339}
340
341
343#define LEAK(code, bytes, blks) \
344 do { \
345 /* establish a checkpoint for memory leaks */ \
346 rwt_check_leaks (0, 0); \
347 \
348 code; \
349 \
350 /* find memory leaks since the last checkpoint */ \
351 std::size_t nbytes; \
352 const std::size_t nblocks = rwt_check_leaks (&nbytes, 0); \
353 \
354 rw_assert (blks == nblocks && bytes == nbytes, \
355 __FILE__, __LINE__, \
356 "failed to detect a leak of %d bytes in " \
357 "%d blocks: got %zu bytes in %zu blocks", \
358 bytes, blks, nbytes, nblocks); \
359 } while (0)
360
361
363{
364 rw_info (0, __FILE__, __LINE__,
365 "exercising the ability to detect memory leaks");
366
367 {
368 void *p = 0;
369 LEAK (p = operator new (0), 0, 1);
370 PASS (operator delete (p));
371 }
372
373 {
374 void *p = 0;
375 LEAK (p = operator new (1), 1, 1);
376 PASS (operator delete (p));
377 }
378
379 {
380 void *p = 0;
381 LEAK (p = operator new (1234), 1234, 1);
382 PASS (operator delete (p));
383 }
384
385 {
386 void *p0 = 0;
387 void *p1 = 0;
388 LEAK (p0 = operator new (32);
389 p1 = operator new (64), 96, 2);
390 PASS (operator delete (p0));
391 PASS (operator delete (p1));
392 }
393
394 {
395 void *p = 0;
396 LEAK (p = operator new[] (12345), 12345, 1);
397 PASS (operator delete[] (p));
398 }
399}
400
401
404{
405 rw_info (0, __FILE__, __LINE__,
406 "stress-testing replacement operators new and delete");
407
408 rwt_free_store* const pst = rwt_get_free_store (0);
409
410 std::size_t nblocks = pst->blocks_ [0] + pst->blocks_ [1];
411 std::size_t nbytes = pst->bytes_ [0] + pst->bytes_ [1];
412
413 void* ptrs [1000];
414
415 const std::size_t N = sizeof ptrs / sizeof *ptrs;
416
417 for (std::size_t i = 0; i != N; ++i) {
418 if (i % 2) {
419 PASS (ptrs [i] = operator new[](i));
420 }
421 else {
422 PASS (ptrs [i] = operator new (i));
423 }
424 }
425
426 for (std::size_t i = 0; i < N; ++i) {
427
428 const std::size_t j = (i * (i + 17)) % N;
429
430 if (j % 2) {
431 PASS (operator delete[](ptrs [j]));
432 }
433 else {
434 PASS (operator delete (ptrs [j]));
435 }
436
437 ptrs [j] = 0;
438 }
439
440 for (std::size_t i = 0; i < N; ++i) {
441 if (i % 2) {
442 PASS (operator delete[](ptrs [i]));
443 }
444 else {
445 PASS (operator delete (ptrs [i]));
446 }
447 }
448
449 nblocks = pst->blocks_ [0] + pst->blocks_ [1] - nblocks;
450 nbytes = pst->bytes_ [0] + pst->bytes_ [1] - nbytes;
451
452 rw_assert (0 == nblocks && 0 == nbytes, __FILE__, __LINE__,
453 "false leaks detected: %zu bytes in %zu blocks",
454 nbytes, nblocks);
455}
456
457
459static int rw_opt_no_new_delete; // for --no-new-delete
460static int rw_opt_no_bad_alloc; // for --no-bad_alloc
461static int rw_opt_no_mismatch; // for --no-mismatch
462static int rw_opt_no_bad_delete; // for --no-bad-delete
463static int rw_opt_no_double_delete; // for --no-double-delete
464static int rw_opt_no_corruption; // for --no-corruption
465static int rw_opt_no_leaks; // for --no-leaks
466static int rw_opt_no_stress; // for --no-stress
467
468int run_test (int, char**)
469{
470#ifndef _RWSTD_NO_REPLACEABLE_NEW_DELETE
471
472 // disable diagnostics issued by the replacement operator new
473 // and delete defined by the test driver in response to deliberate
474 // errors caused by this test
475 rw_enable (rw_error, false);
476
477# define TEST(name) \
478 if (rw_opt_no_ ## name) \
479 rw_note (0, 0, __LINE__, "%s test disabled", #name); \
480 else \
481 test_ ## name ()
482
483 TEST (bad_alloc);
484 TEST (mismatch);
485 TEST (double_delete);
486 TEST (bad_delete);
487 TEST (corruption);
488 TEST (leaks);
489 TEST (stress);
490
491#else // _RWSTD_NO_REPLACEABLE_NEW_DELETE
492
493 rw_note (0, 0, __LINE__, "Test disabled");
494
495#endif // _RWSTD_NO_REPLACEABLE_NEW_DELETE
496
497 return 0;
498}
499
500
502int main (int argc, char** argv)
503{
504 return rw_test (argc, argv, __FILE__,
505 0 /* no clause */,
506 0 /* no comment */,
507 run_test,
508 "|-no-new-delete# "
509 "|-no-bad_alloc# "
510 "|-no-mismatch# "
511 "|-no-bad-delete# "
512 "|-no-double-delete# "
513 "|-no-corruption# "
514 "|-no-leaks# "
515 "|-no-stress-test#",
516 &rw_opt_no_new_delete,
517 &rw_opt_no_bad_alloc,
518 &rw_opt_no_mismatch,
519 &rw_opt_no_bad_delete,
520 &rw_opt_no_double_delete,
521 &rw_opt_no_corruption,
522 &rw_opt_no_leaks,
523 &rw_opt_no_stress);
524}
#define NOTHROW(code)
Definition 0.new.cpp:129
void test_bad_alloc()
Definition 0.new.cpp:135
#define LEAK(code, bytes, blks)
Definition 0.new.cpp:343
int run_test(int, char **)
Definition 0.new.cpp:468
volatile int line
Definition 0.new.cpp:46
void test_double_delete()
Definition 0.new.cpp:289
#define TEST(name)
void test_corruption()
Definition 0.new.cpp:314
#define CATCH(code)
Definition 0.new.cpp:121
#define PASS(code)
Definition 0.new.cpp:72
void test_leaks()
Definition 0.new.cpp:362
int exit_status
Definition 0.new.cpp:42
void test_bad_delete()
Definition 0.new.cpp:251
void test_new_delete()
Definition 0.new.cpp:85
#define FAIL(code)
Definition 0.new.cpp:61
void test_mismatch()
Definition 0.new.cpp:219
void test_stress()
Definition 0.new.cpp:403
volatile int fail
Definition 0.new.cpp:47
jmp_buf env
Definition 0.new.cpp:49
#define N
Definition 17.names.cpp:157
#define i
Definition 17.names.cpp:126
#define j
Definition 17.names.cpp:127
#define save
Definition 17.names.cpp:538
#define p1
Definition 17.names.cpp:239
#define p
Definition 17.names.cpp:132
#define main
void handle_ABRT(int)
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT bool rw_enable(int(*fun)(int, const char *, int, const char *,...), bool enable=true)
Definition driver.cpp:1698
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_note(int, const char *, int, const char *,...)
Definition driver.cpp:1664
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)
Definition driver.cpp:1613
_TEST_EXPORT rwt_free_store * rwt_get_free_store(rwt_free_store *)
Definition new.cpp:597
_RWSTD_SIZE_T bytes_[2]
Definition rw_new.h:65
_RWSTD_SIZE_T blocks_[2]
Definition rw_new.h:61
_RWSTD_SIZE_T * throw_at_blocks_[2]
Definition rw_new.h:89