diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2022-02-07 08:39:44 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2022-02-07 11:45:25 +0300 |
commit | 4a5c9217b48ae3d491de88dd2c6998a055a31284 (patch) | |
tree | 7c588de7a4ee14e9c6977859e14acdab9e342942 /tests/cpp.cc | |
parent | 5c1625c8e60d7de2cde59708b16f2a330a78b0c3 (diff) | |
download | bdwgc-4a5c9217b48ae3d491de88dd2c6998a055a31284.tar.gz |
Name all tests consistently
(refactoring)
In brief, the tests naming as follows: all test executable files end
with "test" (not "_test"); all test source files do not have "test"
suffix (except for gctest); test.c is named now as gctest.c.
* CMakeLists.txt: Rename leak_test.c to leak.c; rename huge_test.c to
huge.c; rename leak_test.c to leak.c; rename realloc_test.c to
realloc.c; rename smash_test.c to smash.c; rename staticrootslib.c to
staticroots_lib.c; rename trace_test.c to trace.c; rename
thread_leak_test.c to threadleak.c; rename threadkey_test to
threadkey_test; rename threadkey_test.c to threadkey.c; rename
subthreadcreate_test to subthreadcreatetest; rename subthread_create.c
to subthreadcreate.c; rename initsecondarythread_test to
initfromthreadtest; rename initsecondarythread.c to initfromthread.c;
rename disclaim_test to disclaimtest; rename disclaim_test.c to
disclaim.c; rename disclaim_weakmap_test to weakmaptest; rename
disclaim_weakmap_test.c to weakmap.c.
* tests/tests.am: Likewise.
* CMakeLists.txt: Rename test.c to gctest.c; rename test_cpp to
cpptest; rename test_cpp.cc to cpp.cc.
* Makefile.direct: Likewise.
* NT_MAKEFILE: Likewise.
* README.md (Installation and Portability): Likewise.
* WCC_MAKEFILE: Likewise.
* digimars.mak: Likewise.
* doc/README.Mac: Likewise.
* tests/tests.am: Likewise.
* CMakeLists.txt: rename test_atomic_ops.c to atomicops.c; rename
test_atomic_ops to atomicopstest.
* configure.ac [$with_libatomic_ops=check]: Likewise.
* ChangeLog (8.3.0): Rename threadkey_test to threadkeytest; rename
test_atomic_ops to atomicopstest; rename test_cpp to cpptest.
* Makefile.direct: Rename test.o to gctest.o.
* NT_MAKEFILE: Rename test_cpp.exe to cpptest.exe; rename test.obj to
gctest.obj.
* WCC_MAKEFILE: Likewise.
* digimars.mak: Likewise.
* doc/README.win64: Likewise.
* configure.ac: Rename test_cpp to cpptest in comment.
* doc/leak.md: Rename leak_test.c to leak.c.
* tests/test_atomic_ops.c: Rename to atomicops.c; remove test name in
"skipped" message.
* tests/test_cpp.cc: Rename to cpp.cc; rename test_cpp to cpptest.
* tests/disclaim_test.c: Rename to disclaim.c.
* tests/test.c: Rename to gctest.c.
* tests/huge_test.c: Rename to huge.c.
* tests/initsecondarythread.c: Rename to initfromthread.c.
* tests/leak_test.c: Rename to leak.c.
* tests/realloc_test.c: Rename to realloc.c.
* tests/smash_test.c: Rename to smash.c.
* tests/staticrootstest.c: Rename to staticroots.c.
* tests/staticrootslib.c: Rename to staticroots_lib.c.
* tests/subthread_create.c: Rename to subthreadcreate.c; remove test
name in printed messages.
* tests/threadkey_test.c: Rename to threadkey.c; remove test name in
"skipped" message.
* tests/thread_leak_test.c: Rename to threadleak.c.
* tests/trace_test.c: Rename to trace.c.
* tests/disclaim_weakmap_test.c: Rename to weakmap.c; rename
disclaim_test.c to disclaim.c in comment.
Diffstat (limited to 'tests/cpp.cc')
-rw-r--r-- | tests/cpp.cc | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/tests/cpp.cc b/tests/cpp.cc new file mode 100644 index 00000000..05abc29e --- /dev/null +++ b/tests/cpp.cc @@ -0,0 +1,405 @@ +/* + * Copyright (c) 1994 by Xerox Corporation. All rights reserved. + * + * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED + * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. + * + * Permission is hereby granted to use or copy this program + * for any purpose, provided the above notices are retained on all copies. + * Permission to modify the code and to distribute modified code is granted, + * provided the above notices are retained, and a notice that the code was + * modified is included with the above copyright notice. + */ + +// This program tries to test the specific C++ functionality provided by +// gc_cpp.h that isn't tested by the more general test routines of the +// collector. + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#undef GC_BUILD + +#define GC_DONT_INCL_WINDOWS_H +#include "gc_cpp.h" + +#include <stdlib.h> +#include <string.h> + +#include "gc/gc_allocator.h" + +# include "private/gcconfig.h" + +# ifndef GC_API_PRIV +# define GC_API_PRIV GC_API +# endif +extern "C" { + GC_API_PRIV void GC_printf(const char * format, ...); + /* Use GC private output to reach the same log file. */ + /* Don't include gc_priv.h, since that may include Windows system */ + /* header files that don't take kindly to this context. */ +} + +#ifdef MSWIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif +# define NOSERVICE +# include <windows.h> +#endif + +#ifdef GC_NAME_CONFLICT +# define USE_GC GC_NS_QUALIFY(UseGC) + struct foo * GC; +#else +# define USE_GC GC_NS_QUALIFY(GC) +#endif + +#define my_assert( e ) \ + if (! (e)) { \ + GC_printf( "Assertion failure in " __FILE__ ", line %d: " #e "\n", \ + __LINE__ ); \ + exit( 1 ); } + +class A {public: + /* An uncollectible class. */ + + GC_ATTR_EXPLICIT A( int iArg ): i( iArg ) {} + void Test( int iArg ) { + my_assert( i == iArg );} + virtual ~A() {} + int i;}; + + +class B: public GC_NS_QUALIFY(gc), public A { public: + /* A collectible class. */ + + GC_ATTR_EXPLICIT B( int j ): A( j ) {} + virtual ~B() { + my_assert( deleting );} + static void Deleting( int on ) { + deleting = on;} + static int deleting;}; + +int B::deleting = 0; + +#define C_INIT_LEFT_RIGHT(arg_l, arg_r) \ + { \ + C *l = new C(arg_l); \ + C *r = new C(arg_r); \ + left = l; \ + right = r; \ + if (GC_is_heap_ptr(this)) { \ + GC_END_STUBBORN_CHANGE(this); \ + GC_reachable_here(l); \ + GC_reachable_here(r); \ + } \ + } + +class C: public GC_NS_QUALIFY(gc_cleanup), public A { public: + /* A collectible class with cleanup and virtual multiple inheritance. */ + + // The class uses dynamic memory/resource allocation, so provide both + // a copy constructor and an assignment operator to workaround a cppcheck + // warning. + C(const C& c) : A(c.i), level(c.level), left(0), right(0) { + if (level > 0) + C_INIT_LEFT_RIGHT(*c.left, *c.right); + } + + C& operator=(const C& c) { + if (this != &c) { + delete left; + delete right; + i = c.i; + level = c.level; + left = 0; + right = 0; + if (level > 0) + C_INIT_LEFT_RIGHT(*c.left, *c.right); + } + return *this; + } + + GC_ATTR_EXPLICIT C( int levelArg ): A( levelArg ), level( levelArg ) { + nAllocated++; + if (level > 0) { + C_INIT_LEFT_RIGHT(level - 1, level - 1); + } else { + left = right = 0;}} + ~C() { + this->A::Test( level ); + nFreed++; + my_assert( level == 0 ? + left == 0 && right == 0 : + level == left->level + 1 && level == right->level + 1 ); + left = right = 0; + level = -123456;} + static void Test() { + if (GC_is_incremental_mode() && nFreed < (nAllocated / 5) * 4) { + // An explicit GC might be needed to reach the expected number + // of the finalized objects. + GC_gcollect(); + } + my_assert(nFreed <= nAllocated); + my_assert(nFreed >= (nAllocated / 5) * 4 || GC_get_find_leak()); + } + + static int nFreed; + static int nAllocated; + int level; + C* left; + C* right;}; + +int C::nFreed = 0; +int C::nAllocated = 0; + + +class D: public GC_NS_QUALIFY(gc) { public: + /* A collectible class with a static member function to be used as + an explicit clean-up function supplied to ::new. */ + + GC_ATTR_EXPLICIT D( int iArg ): i( iArg ) { + nAllocated++;} + static void CleanUp( void* obj, void* data ) { + D* self = static_cast<D*>(obj); + nFreed++; + my_assert( (GC_word)self->i == (GC_word)data );} + static void Test() { + my_assert(nFreed >= (nAllocated / 5) * 4 || GC_get_find_leak()); + } + + int i; + static int nFreed; + static int nAllocated;}; + +int D::nFreed = 0; +int D::nAllocated = 0; + + +class E: public GC_NS_QUALIFY(gc_cleanup) { public: + /* A collectible class with clean-up for use by F. */ + + E() { + nAllocated++;} + ~E() { + nFreed++;} + + static int nFreed; + static int nAllocated;}; + +int E::nFreed = 0; +int E::nAllocated = 0; + + +class F: public E {public: + /* A collectible class with clean-up, a base with clean-up, and a + member with clean-up. */ + + F() { + nAllocatedF++; + } + + ~F() { + nFreedF++; + } + + static void Test() { + my_assert(nFreedF >= (nAllocatedF / 5) * 4 || GC_get_find_leak()); + my_assert(2 * nFreedF == nFreed); + } + + E e; + static int nFreedF; + static int nAllocatedF; +}; + +int F::nFreedF = 0; +int F::nAllocatedF = 0; + + +GC_word Disguise( void* p ) { + return ~ (GC_word) p;} + +void* Undisguise( GC_word i ) { + return (void*) ~ i;} + +#define GC_CHECKED_DELETE(p) \ + { \ + size_t freed_before = GC_get_expl_freed_bytes_since_gc(); \ + delete p; /* the operator should invoke GC_FREE() */ \ + size_t freed_after = GC_get_expl_freed_bytes_since_gc(); \ + my_assert(freed_before != freed_after); \ + } + +#define N_TESTS 7 + +#if ((defined(MSWIN32) && !defined(__MINGW32__)) || defined(MSWINCE)) \ + && !defined(NO_WINMAIN_ENTRY) + int APIENTRY WinMain( HINSTANCE /* instance */, HINSTANCE /* prev */, + LPSTR cmd, int /* cmdShow */) + { + int argc = 0; + char* argv[ 3 ]; + +# if defined(CPPCHECK) + GC_noop1((GC_word)&WinMain); +# endif + if (cmd != 0) + for (argc = 1; argc < (int)(sizeof(argv) / sizeof(argv[0])); argc++) { + // Parse the command-line string. Non-reentrant strtok() is not used + // to avoid complains of static analysis tools. (And, strtok_r() is + // not available on some platforms.) The code is equivalent to: + // if (!(argv[argc] = strtok(argc == 1 ? cmd : 0, " \t"))) break; + if (NULL == cmd) { + argv[argc] = NULL; + break; + } + for (; *cmd != '\0'; cmd++) { + if (*cmd != ' ' && *cmd != '\t') + break; + } + if ('\0' == *cmd) { + argv[argc] = NULL; + break; + } + argv[argc] = cmd; + while (*(++cmd) != '\0') { + if (*cmd == ' ' || *cmd == '\t') + break; + } + if (*cmd != '\0') { + *(cmd++) = '\0'; + } else { + cmd = NULL; + } + } +#elif defined(MACOS) + int main() { + char* argv_[] = {"cpptest", "7"}; // MacOS doesn't have a command line + argv = argv_; + argc = sizeof(argv_)/sizeof(argv_[0]); +#else + int main( int argc, char* argv[] ) { +#endif + + GC_set_all_interior_pointers(1); + /* needed due to C++ multiple inheritance used */ + +# ifdef TEST_MANUAL_VDB + GC_set_manual_vdb_allowed(1); +# endif + GC_INIT(); +# ifndef NO_INCREMENTAL + GC_enable_incremental(); +# endif + if (GC_get_find_leak()) + GC_printf("This test program is not designed for leak detection mode\n"); + + int i, iters, n; + int *x = gc_allocator<int>().allocate(1); + int *xio; + xio = gc_allocator_ignore_off_page<int>().allocate(1); + (void)xio; + int **xptr = traceable_allocator<int *>().allocate(1); + *x = 29; + if (!xptr) { + GC_printf("Out of memory!\n"); + exit(3); + } + GC_PTR_STORE_AND_DIRTY(xptr, x); + x = 0; + if (argc != 2 + || (n = atoi(argv[1])) <= 0) { + GC_printf("usage: cpptest <number-of-iterations>\n" + "Assuming %d iterations\n", N_TESTS); + n = N_TESTS; + } +# ifdef LINT2 + if (n > 100 * 1000) n = 100 * 1000; +# endif + + for (iters = 1; iters <= n; iters++) { + GC_printf( "Starting iteration %d\n", iters ); + + /* Allocate some uncollectible As and disguise their pointers. + Later we'll check to see if the objects are still there. We're + checking to make sure these objects really are uncollectible. */ + GC_word as[ 1000 ]; + GC_word bs[ 1000 ]; + for (i = 0; i < 1000; i++) { + as[ i ] = Disguise( new (GC_NS_QUALIFY(NoGC)) A(i) ); + bs[ i ] = Disguise( new (GC_NS_QUALIFY(NoGC)) B(i) ); } + + /* Allocate a fair number of finalizable Cs, Ds, and Fs. + Later we'll check to make sure they've gone away. */ + for (i = 0; i < 1000; i++) { + C* c = new C( 2 ); + C c1( 2 ); /* stack allocation should work too */ + D* d; + F* f; + d = ::new (USE_GC, D::CleanUp, (void*)(GC_word)i) D( i ); + (void)d; + f = new F; + F** fa = new F*[1]; + fa[0] = f; + (void)fa; + delete[] fa; + if (0 == i % 10) + GC_CHECKED_DELETE(c); + } + + /* Allocate a very large number of collectible As and Bs and + drop the references to them immediately, forcing many + collections. */ + for (i = 0; i < 1000000; i++) { + A* a; + a = new (USE_GC) A( i ); + (void)a; + B* b; + b = new B( i ); + (void)b; + b = new (USE_GC) B( i ); + if (0 == i % 10) { + B::Deleting( 1 ); + GC_CHECKED_DELETE(b); + B::Deleting( 0 );} +# ifdef FINALIZE_ON_DEMAND + GC_invoke_finalizers(); +# endif + } + + /* Make sure the uncollectible As and Bs are still there. */ + for (i = 0; i < 1000; i++) { + A* a = static_cast<A*>(Undisguise(as[i])); + B* b = static_cast<B*>(Undisguise(bs[i])); + a->Test( i ); +# if defined(ADDRESS_SANITIZER) || defined(MEMORY_SANITIZER) + // Workaround for ASan/MSan: the linker uses operator delete + // implementation from libclang_rt instead of gc_cpp (thus + // causing incompatible alloc/free). + GC_FREE(a); +# else + GC_CHECKED_DELETE(a); +# endif + b->Test( i ); + B::Deleting( 1 ); + GC_CHECKED_DELETE(b); + B::Deleting( 0 ); +# ifdef FINALIZE_ON_DEMAND + GC_invoke_finalizers(); +# endif + } + + /* Make sure most of the finalizable Cs, Ds, and Fs have + gone away. */ + C::Test(); + D::Test(); + F::Test();} + + x = *xptr; + my_assert (29 == x[0]); + GC_printf( "The test appears to have succeeded.\n" ); + return( 0 ); +} |