summaryrefslogtreecommitdiff
path: root/tests/cpp.cc
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2022-02-07 08:39:44 +0300
committerIvan Maidanski <ivmai@mail.ru>2022-02-07 11:45:25 +0300
commit4a5c9217b48ae3d491de88dd2c6998a055a31284 (patch)
tree7c588de7a4ee14e9c6977859e14acdab9e342942 /tests/cpp.cc
parent5c1625c8e60d7de2cde59708b16f2a330a78b0c3 (diff)
downloadbdwgc-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.cc405
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 );
+}