[test] Regression test for #58950
authorAleksey Kliger <aleksey@xamarin.com>
Fri, 8 Sep 2017 19:18:20 +0000 (15:18 -0400)
committerAleksey Kliger (λgeek) <akliger@gmail.com>
Tue, 12 Sep 2017 17:11:20 +0000 (13:11 -0400)
If a reflection only assembly resolve event handler throws an exception, catch
the exception in the runtime to ensure that no coop handles leak.

mono/tests/Makefile.am
mono/tests/assemblyresolve_Test.cs
mono/tests/assemblyresolve_asm.cs
mono/tests/assemblyresolve_event6.cs [new file with mode: 0644]

index 4e4de8f0db8ea40e7395e7fbf32f6551863f0b1c..6088c5220d352a5cc132c96c52d9f84493360b71 100755 (executable)
@@ -128,6 +128,7 @@ TESTS_CS_SRC=               \
        assemblyresolve_event3.cs       \
        assemblyresolve_event4.cs       \
        assemblyresolve_event5.cs       \
+       assemblyresolve_event6.cs       \
        checked.cs              \
        char-isnumber.cs        \
        field-layout.cs         \
@@ -800,6 +801,7 @@ PROFILE_DISABLED_TESTS += \
        appdomain-unload-doesnot-raise-pending-events.exe       \
        unload-appdomain-on-shutdown.exe        \
        assemblyresolve_event2.2.exe    \
+       assemblyresolve_event6.exe      \
        bug-544446.exe  \
        bug-36848.exe   \
        generic-marshalbyref.2.exe      \
@@ -1719,9 +1721,9 @@ module-cctor-loader.2.exe: module-cctor.exe
 reference-loader.exe$(PLATFORM_AOT_SUFFIX): TestingReferenceAssembly.dll$(PLATFORM_AOT_SUFFIX) TestingReferenceReferenceAssembly.dll$(PLATFORM_AOT_SUFFIX)
 reference-loader.exe: TestingReferenceAssembly.dll TestingReferenceReferenceAssembly.dll
 
-assemblyresolve_asm.dll$(PLATFORM_AOT_SUFFIX): assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX)
+assemblyresolve_asm.dll$(PLATFORM_AOT_SUFFIX): assemblyresolve_asm.dll assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX)
        MONO_PATH="assemblyresolve_deps:$(CLASS)" $(top_builddir)/runtime/mono-wrapper $(AOT_BUILD_FLAGS) assemblyresolve_asm.dll
-assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX): assemblyresolve_deps/TestBase.dll$(PLATFORM_AOT_SUFFIX)
+assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX): assemblyresolve_deps/Test.dll assemblyresolve_deps/TestBase.dll$(PLATFORM_AOT_SUFFIX)
 
 EXTRA_DIST += assemblyresolve_TestBase.cs assemblyresolve_Test.cs assemblyresolve_asm.cs 
 assemblyresolve_deps:
@@ -1746,6 +1748,9 @@ assemblyresolve_event5_helper.dll: assemblyresolve_event5_helper.cs assemblyreso
        $(MCS) -target:library -out:assemblyresolve_event5_helper.dll -r:assemblyresolve_deps/assemblyresolve_event5_label.dll $(srcdir)/assemblyresolve_event5_helper.cs
 assemblyresolve_event5.exe: assemblyresolve_event5_helper.dll
 
+assemblyresolve_event6.exe$(PLATFORM_AOT_SUFFIX): assemblyresolve_asm.dll$(PLATFORM_AOT_SUFFIX) assemblyresolve_deps/Test.dll$(PLATFORM_AOT_SUFFIX) assemblyresolve_deps/TestBase.dll$(PLATFORM_AOT_SUFFIX)
+assemblyresolve_event6.exe: assemblyresolve_asm.dll assemblyresolve_deps/Test.dll assemblyresolve_deps/TestBase.dll
+
 # We use 'test-support-files' to handle an ordering issue between the 'mono/' and 'runtime/' directories
 bug-80307.exe: $(srcdir)/bug-80307.cs
        $(MCS) -r:$(CLASS)/System.Web.dll -out:$@ $(srcdir)/bug-80307.cs
index bba53165e983f6a9267dc2d24856d389c8e3c6b5..d86bbbab3c21ea2e78a722805b1ceae35fd11355 100644 (file)
@@ -4,5 +4,11 @@ using TestBase;
 namespace Test
 {
   public class Test : TestBase.TestBase
-  {}
+  {
+
+  }
+
+       public class ReturnsTestBase {
+               public TestBase.TestBase M () { return null; }
+       }
 }
index dd2cc47b6e9022261c8852836ad33a7cd71f25c1..a72e7619636e68896914d1c1771d91de4367dc29 100644 (file)
@@ -10,3 +10,7 @@ public class Asm : Test.Test
     t = new Test.Test ();
   }
 }
+
+public class Asm2 : Test.ReturnsTestBase
+{
+}
diff --git a/mono/tests/assemblyresolve_event6.cs b/mono/tests/assemblyresolve_event6.cs
new file mode 100644 (file)
index 0000000..9afb71c
--- /dev/null
@@ -0,0 +1,64 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Reflection;
+
+public class App
+{
+       public static int Main ()
+       {
+               /* Regression test for #58950: When the
+                * ReflectionOnlyAssemblyResolve event handler throws an
+                * exception, mono would unwind native code in the loader,
+                * which left stale coop handles on the coop handle stack.
+                * Then, the domain unload, asserted in
+                * mono_handle_stack_free_domain (). */
+               var d = AppDomain.CreateDomain ("TestDomain");
+               var o = d.CreateInstanceAndUnwrap (typeof (App).Assembly.FullName, "App/Work") as Work;
+               var r = o.DoSomething ();
+               if (r != 0)
+                       return r;
+               AppDomain.Unload (d);
+               return 0;
+       }
+
+       public class MyExn : Exception {
+               public MyExn () : base ("MyReflectionResolveEventHandler threw") {}
+       }
+
+       public class Work : MarshalByRefObject {
+               public Work () { }
+
+               public int DoSomething ()
+               {
+                       AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += new ResolveEventHandler (MyReflectionResolveEventHandler);
+                       bool caught = false;
+                       try {
+                               Assembly a = Assembly.ReflectionOnlyLoadFrom ("assemblyresolve_asm.dll");
+                               var t = a.GetType ("Asm2");
+                               var m = t.GetMethod ("M"); // This triggers a load of TestBase
+                               Console.Error.WriteLine ("got '{0}'", m);
+                       } catch (FileNotFoundException e) {
+                               Console.WriteLine ("caught FNFE {0}", e);
+                               caught = true;
+                       } catch (MyExn ) {
+                               Console.Error.WriteLine ("caught MyExn, should've been a FNFE");
+                               return 2;
+                       }
+                       if (!caught) {
+                               Console.Error.WriteLine ("expected to catch a FNFE");
+                               return 3;
+                       }
+                       return 0;
+               }
+
+               static Assembly MyReflectionResolveEventHandler (object sender, ResolveEventArgs args) {
+                       Console.Error.WriteLine ($"Load event for: {args.Name}");
+                       if (args.Name == "Test, Version=0.0.0.0, Culture=neutral" || args.Name == "Test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")
+                               return Assembly.ReflectionOnlyLoadFrom (Path.Combine (Directory.GetCurrentDirectory (), "assemblyresolve_deps", "Test.dll"));
+                       // a request to load TestBase will throw here, which
+                       // should be caught in the runtime
+                       throw new MyExn ();
+               }
+       }
+}