cpp.cc raw
1 /*
2 * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
3 *
4 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
5 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
6 *
7 * Permission is hereby granted to use or copy this program
8 * for any purpose, provided the above notices are retained on all copies.
9 * Permission to modify the code and to distribute modified code is granted,
10 * provided the above notices are retained, and a notice that the code was
11 * modified is included with the above copyright notice.
12 */
13
14 // This program tries to test the specific C++ functionality provided by
15 // `gc_cpp.h` file that is not tested by the more general test routines
16 // of the collector.
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21
22 #undef GC_BUILD
23
24 #define GC_DONT_INCL_WINDOWS_H
25 #include "gc_cpp.h"
26
27 #include <stdlib.h>
28 #include <string.h>
29
30 #define GC_NAMESPACE_ALLOCATOR
31 #include "gc/gc_allocator.h"
32 using boehmgc::gc_allocator;
33 using boehmgc::gc_allocator_ignore_off_page;
34 using boehmgc::traceable_allocator;
35
36 #include "private/gcconfig.h"
37
38 #ifndef GC_API_PRIV
39 # define GC_API_PRIV GC_API
40 #endif
41 extern "C" {
42 // Use the collector private output to reach the same log file.
43 // Do not include `gc_priv.h` file, since that may include Windows
44 // system header files that do not take kindly to this context.
45 GC_API_PRIV void GC_printf(const char *format, ...);
46 }
47
48 #ifdef MSWIN32
49 # ifndef WIN32_LEAN_AND_MEAN
50 # define WIN32_LEAN_AND_MEAN 1
51 # endif
52 # define NOSERVICE
53 # include <windows.h>
54 #endif
55
56 #ifdef GC_NAME_CONFLICT
57 # define USE_GC GC_NS_QUALIFY(UseGC)
58 struct foo *GC;
59 #else
60 # define USE_GC GC_NS_QUALIFY(GC)
61 #endif
62
63 #if __cplusplus >= 201103L
64 # define GC_OVERRIDE override
65 #else
66 # define GC_OVERRIDE /*< empty */
67 #endif
68
69 #define my_assert(e) \
70 if (!(e)) { \
71 GC_printf("Assertion failure in " __FILE__ ", line %d: " #e "\n", \
72 __LINE__); \
73 exit(1); \
74 }
75
76 #if defined(__powerpc64__) && !defined(__clang__) && GC_GNUC_PREREQ(10, 0)
77 // Suppress "layout of aggregates ... has changed" GCC note.
78 # define A_I_TYPE short
79 #else
80 # define A_I_TYPE int
81 #endif
82
83 #define LARGE_CPP_ITER_CNT 1000000
84
85 // An uncollectible class.
86 class A
87 {
88 public:
89 GC_ATTR_EXPLICIT
90 A(int iArg) : i(static_cast<A_I_TYPE>(iArg)) {}
91 void
92 Test(int iArg)
93 {
94 my_assert(i == iArg);
95 }
96 virtual ~A() {}
97 A_I_TYPE i;
98 };
99
100 // A collectible class.
101 class B : public GC_NS_QUALIFY(gc), public A
102 {
103 public:
104 GC_ATTR_EXPLICIT
105 B(int j) : A(j) {}
106 virtual ~B() GC_OVERRIDE { my_assert(deleting); }
107 static void
108 Deleting(int on)
109 {
110 deleting = on;
111 }
112 static int deleting;
113 };
114
115 int B::deleting = 0;
116
117 #define C_INIT_LEFT_RIGHT(arg_l, arg_r) \
118 { \
119 C *l = new C(arg_l); \
120 C *r = new C(arg_r); \
121 left = l; \
122 right = r; \
123 if (GC_is_heap_ptr(this)) { \
124 GC_END_STUBBORN_CHANGE(this); \
125 GC_reachable_here(l); \
126 GC_reachable_here(r); \
127 } \
128 }
129
130 // A collectible class with cleanup and virtual multiple inheritance.
131 class C : public GC_NS_QUALIFY(gc_cleanup), public A
132 {
133 public:
134 // The class uses dynamic memory/resource allocation, so provide both
135 // a copy constructor and an assignment operator to workaround a cppcheck
136 // warning.
137 C(const C &c) : A(c.i), level(c.level), left(0), right(0)
138 {
139 if (level > 0)
140 C_INIT_LEFT_RIGHT(*c.left, *c.right);
141 }
142
143 C &
144 operator=(const C &c)
145 {
146 if (this != &c) {
147 delete left;
148 delete right;
149 i = c.i;
150 level = c.level;
151 left = 0;
152 right = 0;
153 if (level > 0)
154 C_INIT_LEFT_RIGHT(*c.left, *c.right);
155 }
156 return *this;
157 }
158
159 GC_ATTR_EXPLICIT
160 C(int levelArg) : A(levelArg), level(levelArg)
161 {
162 nAllocated++;
163 if (level > 0) {
164 C_INIT_LEFT_RIGHT(level - 1, level - 1);
165 } else {
166 left = right = 0;
167 }
168 }
169 ~C() GC_OVERRIDE
170 {
171 this->A::Test(level);
172 nFreed++;
173 my_assert(level == 0
174 ? left == 0 && right == 0
175 : level == left->level + 1 && level == right->level + 1);
176 left = right = 0;
177 level = -32456;
178 }
179 static void
180 Test()
181 {
182 if (GC_is_incremental_mode() && nFreed < (nAllocated / 5) * 4) {
183 // An explicit garbage collection might be needed to reach the expected
184 // number of the finalized objects.
185 GC_gcollect();
186 }
187 my_assert(nFreed <= nAllocated);
188 #ifndef GC_NO_FINALIZATION
189 my_assert(nFreed >= (nAllocated / 5) * 4 || GC_get_find_leak());
190 #endif
191 }
192
193 static int nFreed;
194 static int nAllocated;
195 int level;
196 C *left;
197 C *right;
198 };
199
200 int C::nFreed = 0;
201 int C::nAllocated = 0;
202
203 // A collectible class with a static member function to be used as
204 // an explicit cleanup function supplied to operator `::new`.
205 class D : public GC_NS_QUALIFY(gc)
206 {
207 public:
208 GC_ATTR_EXPLICIT
209 D(int iArg) : i(iArg) { nAllocated++; }
210 static void
211 CleanUp(void *obj, void *data)
212 {
213 const D *self = static_cast<D *>(obj);
214 nFreed++;
215 my_assert(static_cast<GC_uintptr_t>(self->i)
216 == reinterpret_cast<GC_uintptr_t>(data));
217 }
218 static void
219 Test()
220 {
221 #ifndef GC_NO_FINALIZATION
222 my_assert(nFreed >= (nAllocated / 5) * 4 || GC_get_find_leak());
223 #endif
224 }
225
226 int i;
227 static int nFreed;
228 static int nAllocated;
229 };
230
231 int D::nFreed = 0;
232 int D::nAllocated = 0;
233
234 // A collectible class with cleanup for use by `F`.
235 class E : public GC_NS_QUALIFY(gc_cleanup)
236 {
237 public:
238 E() { nAllocated++; }
239 ~E() GC_OVERRIDE { nFreed++; }
240
241 static int nFreed;
242 static int nAllocated;
243 };
244
245 int E::nFreed = 0;
246 int E::nAllocated = 0;
247
248 // A collectible class with cleanup, a base with cleanup, and
249 // a member with cleanup.
250 class F : public E
251 {
252 public:
253 F() { nAllocatedF++; }
254
255 ~F() GC_OVERRIDE { nFreedF++; }
256
257 static void
258 Test()
259 {
260 #ifndef GC_NO_FINALIZATION
261 my_assert(nFreedF >= (nAllocatedF / 5) * 4 || GC_get_find_leak());
262 #endif
263 my_assert(2 * nFreedF == nFreed);
264 }
265
266 E e;
267 static int nFreedF;
268 static int nAllocatedF;
269 };
270
271 int F::nFreedF = 0;
272 int F::nAllocatedF = 0;
273
274 GC_uintptr_t
275 Disguise(void *p)
276 {
277 return GC_HIDE_NZ_POINTER(p);
278 }
279
280 void *
281 Undisguise(GC_uintptr_t v)
282 {
283 return GC_REVEAL_NZ_POINTER(v);
284 }
285
286 // Note: `delete p` should invoke `GC_FREE()`.
287 #define GC_CHECKED_DELETE(p) \
288 { \
289 size_t freed_before = GC_get_expl_freed_bytes_since_gc(); \
290 delete p; \
291 size_t freed_after = GC_get_expl_freed_bytes_since_gc(); \
292 my_assert(freed_before != freed_after); \
293 }
294
295 #define N_TESTS 7
296
297 #if ((defined(MSWIN32) && !defined(__MINGW32__)) || defined(MSWINCE)) \
298 && !defined(NO_WINMAIN_ENTRY)
299 int APIENTRY
300 WinMain(HINSTANCE /* `instance` */, HINSTANCE /* `prev` */, LPSTR cmd,
301 int /* `cmdShow` */)
302 {
303 int argc = 0;
304 char *argv[3];
305
306 # if defined(CPPCHECK)
307 GC_noop1(static_cast<GC_word>(reinterpret_cast<GC_uintptr_t>(&WinMain)));
308 # endif
309 if (cmd != 0)
310 for (argc = 1; argc < static_cast<int>(sizeof(argv) / sizeof(argv[0]));
311 argc++) {
312 // Parse the command-line string. Non-reentrant `strtok()` is not used
313 // to avoid complains of static analysis tools. (And, `strtok_r()` is
314 // not available on some platforms.) The code is equivalent to:
315 // `if (!(argv[argc] = strtok(argc == 1 ? cmd : 0, " \t"))) break;`.
316 if (NULL == cmd) {
317 argv[argc] = NULL;
318 break;
319 }
320 for (; *cmd != '\0'; cmd++) {
321 if (*cmd != ' ' && *cmd != '\t')
322 break;
323 }
324 if ('\0' == *cmd) {
325 argv[argc] = NULL;
326 break;
327 }
328 argv[argc] = cmd;
329 while (*(++cmd) != '\0') {
330 if (*cmd == ' ' || *cmd == '\t')
331 break;
332 }
333 if (*cmd != '\0') {
334 *(cmd++) = '\0';
335 } else {
336 cmd = NULL;
337 }
338 }
339 #else
340 int
341 main(int argc, const char *argv[])
342 {
343 #endif
344
345 // This is needed due to C++ multiple inheritance used.
346 GC_set_all_interior_pointers(1);
347
348 #ifdef TEST_MANUAL_VDB
349 GC_set_manual_vdb_allowed(1);
350 #endif
351 #if !defined(CPPCHECK)
352 GC_INIT();
353 #endif
354 #ifndef NO_INCREMENTAL
355 GC_enable_incremental();
356 #endif
357 if (GC_get_find_leak())
358 GC_printf("This test program is not designed for leak detection mode\n");
359
360 int i, iters, n;
361 int *x = gc_allocator<int>().allocate(1);
362 const int *xio;
363 xio = gc_allocator_ignore_off_page<int>().allocate(1);
364 GC_reachable_here(xio);
365 int **xptr = traceable_allocator<int *>().allocate(1);
366 *x = 29;
367 GC_PTR_STORE_AND_DIRTY(xptr, x);
368 x = 0;
369 if (argc != 2 || (n = atoi(argv[1])) <= 0) {
370 GC_printf("usage: cpptest <number-of-iterations>\n"
371 "Assuming %d iterations\n",
372 N_TESTS);
373 n = N_TESTS;
374 }
375 #ifdef LINT2
376 if (n > 30 * 1000)
377 n = 30 * 1000;
378 #endif
379
380 for (iters = 1; iters <= n; iters++) {
381 GC_printf("Starting iteration %d\n", iters);
382
383 // Allocate some uncollectible objects and disguise their pointers.
384 // Later we will check to see if the objects are still there.
385 // We are checking to make sure these objects are uncollectible really.
386 GC_uintptr_t as[1000];
387 GC_uintptr_t bs[1000];
388 for (i = 0; i < 1000; i++) {
389 as[i] = Disguise(new (GC_NS_QUALIFY(NoGC)) A(i));
390 bs[i] = Disguise(new (GC_NS_QUALIFY(NoGC)) B(i));
391 }
392
393 // Allocate a fair number of finalizable objects.
394 // Later we will check to make sure they have gone away.
395 for (i = 0; i < 1000; i++) {
396 C *c = new C(2);
397 // Stack allocation should work too.
398 C c1(2);
399 F *f;
400 #if !defined(CPPCHECK)
401 D *d;
402 d = ::new (USE_GC, D::CleanUp,
403 reinterpret_cast<void *>(static_cast<GC_uintptr_t>(i))) D(i);
404 GC_reachable_here(d);
405 #endif
406 f = new F;
407 F **fa = new F *[1];
408 fa[0] = f;
409 (void)fa;
410 delete[] fa;
411 if (0 == i % 10)
412 GC_CHECKED_DELETE(c);
413 }
414
415 // Allocate a very large number of collectible objects and drop
416 // the references to them immediately, forcing many collections.
417 for (i = 0; i < LARGE_CPP_ITER_CNT; i++) {
418 const A *a;
419 a = new (USE_GC) A(i);
420 GC_reachable_here(a);
421 B *b;
422 b = new B(i);
423 (void)b;
424 b = new (USE_GC) B(i);
425 if (0 == i % 10) {
426 B::Deleting(1);
427 GC_CHECKED_DELETE(b);
428 B::Deleting(0);
429 }
430 #if defined(FINALIZE_ON_DEMAND) && !defined(GC_NO_FINALIZATION)
431 GC_invoke_finalizers();
432 #endif
433 }
434
435 // Make sure the uncollectible objects are still there.
436 for (i = 0; i < 1000; i++) {
437 A *a = static_cast<A *>(Undisguise(as[i]));
438 B *b = static_cast<B *>(Undisguise(bs[i]));
439 a->Test(i);
440 #if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER)
441 // Workaround for ASan/MSan: the linker uses operator `delete`
442 // implementation from `libclang_rt` instead of `gccpp` library (thus
443 // causing incompatible `alloc`/`free`).
444 GC_FREE(a);
445 #else
446 GC_CHECKED_DELETE(a);
447 #endif
448 b->Test(i);
449 B::Deleting(1);
450 GC_CHECKED_DELETE(b);
451 B::Deleting(0);
452 #if defined(FINALIZE_ON_DEMAND) && !defined(GC_NO_FINALIZATION)
453 GC_invoke_finalizers();
454 #endif
455 }
456
457 // Make sure most of the finalizable objects have gone away.
458 C::Test();
459 D::Test();
460 F::Test();
461 }
462
463 x = *xptr;
464 my_assert(29 == x[0]);
465 GC_printf("The test appears to have succeeded.\n");
466 return 0;
467 }
468