[sgen] Add regression test for the interaction between the bridge and handles.
authorRodrigo Kumpera <kumpera@gmail.com>
Wed, 20 Apr 2016 22:15:18 +0000 (15:15 -0700)
committerRodrigo Kumpera <kumpera@gmail.com>
Wed, 20 Apr 2016 22:15:18 +0000 (15:15 -0700)
The bridge code was triggering handles to be considered deallocated thus leading
them to be overwritten.

mono/metadata/sgen-bridge.c
mono/tests/Makefile.am
mono/tests/sgen-bridge-gchandle.cs [new file with mode: 0644]

index 3b0487c9243afe496a0f5d842a592cdf5e7dd459..74630b2c973afd4027dae0aac1c84b2515fe747f 100644 (file)
@@ -526,6 +526,30 @@ bridge_test_cross_reference2 (int num_sccs, MonoGCBridgeSCC **sccs, int num_xref
                sccs [i]->is_alive = TRUE;
 }
 
+/* This bridge keeps all peers with __test > 0 */
+static void
+bridge_test_positive_status (int num_sccs, MonoGCBridgeSCC **sccs, int num_xrefs, MonoGCBridgeXRef *xrefs)
+{
+       int i;
+
+       if (!mono_bridge_test_field) {
+               mono_bridge_test_field = mono_class_get_field_from_name (mono_object_get_class (sccs[0]->objs [0]), "__test");
+               g_assert (mono_bridge_test_field);
+       }
+
+       /*We mark all objects in a scc with live objects as reachable by scc*/
+       for (i = 0; i < num_sccs; ++i) {
+               int j;
+               for (j = 0; j < sccs [i]->num_objs; ++j) {
+                       if (test_scc (sccs [i], j)) {
+                               sccs [i]->is_alive = TRUE;
+                               break;
+                       }
+               }
+       }
+}
+
+
 static void
 register_test_bridge_callbacks (const char *bridge_class_name)
 {
@@ -533,9 +557,21 @@ register_test_bridge_callbacks (const char *bridge_class_name)
        callbacks.bridge_version = SGEN_BRIDGE_VERSION;
        callbacks.bridge_class_kind = bridge_test_bridge_class_kind;
        callbacks.is_bridge_object = bridge_test_is_bridge_object;
-       callbacks.cross_references = bridge_class_name[0] == '2' ? bridge_test_cross_reference2 : bridge_test_cross_reference;
+
+       switch (bridge_class_name [0]) {
+       case '2':
+               bridge_class = bridge_class_name + 1;
+               callbacks.cross_references = bridge_test_cross_reference2;
+               break;
+       case '3':
+               bridge_class = bridge_class_name + 1;
+               callbacks.cross_references = bridge_test_positive_status;
+               break;
+       default:
+               bridge_class = bridge_class_name;
+               callbacks.cross_references = bridge_test_cross_reference;
+       }
        mono_gc_register_bridge_callbacks (&callbacks);
-       bridge_class = bridge_class_name + (bridge_class_name[0] == '2' ? 1 : 0);
 }
 
 gboolean
index 03bae54e17a22799cc20b98346b97d18dac1af84..86a740ca0579e5dc75f60f5025acf3b457ca0959 100644 (file)
@@ -964,7 +964,7 @@ debug-casts:
        @$(MCS) -r:TestDriver.dll $(srcdir)/debug-casts.cs
        @$(RUNTIME) --debug=casts debug-casts.exe
 
-EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs sgen-domain-unload.cs sgen-weakref-stress.cs sgen-cementing-stress.cs sgen-case-23400.cs     finalizer-wait.cs critical-finalizers.cs sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.cs
+EXTRA_DIST += sgen-bridge.cs sgen-descriptors.cs sgen-gshared-vtype.cs sgen-bridge-major-fragmentation.cs sgen-domain-unload.cs sgen-weakref-stress.cs sgen-cementing-stress.cs sgen-case-23400.cs     finalizer-wait.cs critical-finalizers.cs sgen-domain-unload-2.cs sgen-suspend.cs sgen-new-threads-dont-join-stw.cs sgen-bridge-xref.cs bug-17590.cs sgen-toggleref.cs sgen-bridge-gchandle.cs
 
 
 sgen-tests:
@@ -1105,6 +1105,38 @@ sgen-bridge2-tests-plain-tarjan-bridge: $(SGEN_BRIDGE2_TESTS) test-runner.exe
 sgen-bridge2-tests-ms-split-tarjan-bridge: $(SGEN_BRIDGE2_TESTS) test-runner.exe
        MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=2Bridge" MONO_GC_PARAMS="bridge-implementation=tarjan,minor=split" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE2_TESTS)
 
+
+SGEN_BRIDGE3_TESTS=    \
+       sgen-bridge-gchandle.exe
+
+sgen-bridge3-tests: $(SGEN_BRIDGE3_TESTS)
+       $(MAKE) sgen-bridge3-tests-plain
+       $(MAKE) sgen-bridge3-tests-ms-conc
+       $(MAKE) sgen-bridge3-tests-ms-split
+       $(MAKE) sgen-bridge3-tests-plain-new-bridge
+       $(MAKE) sgen-bridge3-tests-ms-conc-new-bridge
+       $(MAKE) sgen-bridge3-tests-ms-split-new-bridge
+       $(MAKE) sgen-bridge3-tests-plain-tarjan-bridge
+       $(MAKE) sgen-bridge3-tests-ms-split-tarjan-bridge
+
+sgen-bridge3-tests-plain: $(SGEN_bridge3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-conc: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="major=marksweep-conc" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-split: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="minor=split" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-plain-new-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=new" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-conc-new-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=new,major=marksweep-conc" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-split-new-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=new,minor=split" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-plain-tarjan-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=tarjan" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+sgen-bridge3-tests-ms-split-tarjan-bridge: $(SGEN_BRIDGE3_TESTS) test-runner.exe
+       MONO_ENV_OPTIONS="--gc=sgen" MONO_GC_DEBUG="bridge=3Bridge" MONO_GC_PARAMS="bridge-implementation=tarjan,minor=split" $(RUNTIME) ./test-runner.exe --testsuite-name $@ --timeout 900 $(SGEN_BRIDGE3_TESTS)
+
+
 AOT_CONFIGURATIONS=    \
        "|regular"      \
        "--gc=boehm|boehm"
diff --git a/mono/tests/sgen-bridge-gchandle.cs b/mono/tests/sgen-bridge-gchandle.cs
new file mode 100644 (file)
index 0000000..c9a7064
--- /dev/null
@@ -0,0 +1,78 @@
+using System;
+using System.Collections;
+using System.Threading;
+using System.Runtime.InteropServices;
+
+
+public class Bridge {
+       public int __test;
+       public string id;
+       
+       ~Bridge () {
+               try {Console.WriteLine ("bridge {0} gone", id);} catch (Exception) {}
+       }
+}
+
+
+/*
+Test scenario:
+       Alloc a bridge and create a gc handle to it
+       Get it collected.
+       Create another one and see it steal the handle of the previous one.
+
+
+*/
+class Driver {
+       public static GCHandle weak_track_handle;
+       public static GCHandle weak_track_handle2;
+
+       static void CreateFirstBridge () {
+               Bridge b = new Bridge() {
+                       __test = 0,
+                       id = "first",
+               };
+               weak_track_handle = GCHandle.Alloc (b, GCHandleType.WeakTrackResurrection);
+       }
+
+       static void CreateSecondBridge () {
+               Bridge b = new Bridge() {
+                       __test = 1,
+                       id = "second",
+               };
+               weak_track_handle2 = GCHandle.Alloc (b, GCHandleType.WeakTrackResurrection);
+       }
+
+       static void DumpHandle (GCHandle h, string name) {
+               Console.WriteLine ("{0}:{1:X} alloc:{2} hasValue:{2}", name, (IntPtr)h, h.IsAllocated, h.Target == null);
+       }
+
+       static int Main () {
+               var t = new Thread (CreateFirstBridge);
+               t.Start ();
+               t.Join ();
+
+               GC.Collect ();
+               GC.WaitForPendingFinalizers ();
+               Console.WriteLine ("GC DONE");
+
+               DumpHandle (weak_track_handle, "weak-track1");
+
+               t = new Thread (CreateSecondBridge);
+               t.Start ();
+               t.Join ();
+
+               GC.Collect ();
+               GC.WaitForPendingFinalizers ();
+               Console.WriteLine ("GC DONE");
+               DumpHandle (weak_track_handle, "weak-track1");
+               DumpHandle (weak_track_handle2, "weak-track2");
+               Console.WriteLine ("DONE");
+
+               if ((IntPtr)weak_track_handle == (IntPtr)weak_track_handle2) {
+                       Console.WriteLine ("FIRST HANDLE GOT DEALLOCATED!");
+                       return 1;
+               }
+
+               return 0;
+       }
+}