From d32dd808b38efc56020aadc4e38e501fc613dc62 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 3 Jun 2026 15:53:23 -0500 Subject: [PATCH] [tests] Use Android.Util.Log in JnienvTest.ThreadReuse callback Build 14271469 / APKs 1 / Mono.Android.NET_Tests-Release reproduced the exact NRE first diagnosed in 09acb6d67: E DOTNET: Unhandled exception. System.NullReferenceException at NUnit.Framework.Internal.MethodWrapper.get_Name() at NUnit.Framework.Internal.TestExecutionContext.AdhocContext..ctor() at NUnit.Framework.Internal.Execution.TextCapture.WriteLine(String) at System.Console.WriteLine(...) at Java.InteropTests.JnienvTest.<>c.b__7_0(IntPtr, IntPtr) F libc: Fatal signal 6 (SIGABRT) in tid 5229 (Thread-14) The 'minimize the diff' commit 4d924c493 reverted both the Console-to-Log conversion and the try/catch -- but only the try/catch needed to go. NUnit 3's Console.Out redirection is unsafe on a raw native pthread that has no TestExecutionContext, so route the diagnostics through Android.Util.Log to bypass the redirect entirely. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Mono.Android-Tests/Java.Interop/JnienvTest.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs index e74745ec73e..7bfdda32dd3 100644 --- a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs +++ b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs @@ -79,14 +79,23 @@ public void ThreadReuse () { Java.Lang.JavaSystem.LoadLibrary ("reuse-threads"); CB cb = (env, instance) => { - Console.WriteLine ("CrossThreadObjectInteractions: JNIEnv.Handle={0} env={1}, instance={2}", + // NOTE: this callback runs on a raw native pthread spawned by + // libreuse-threads.so and attached to the JVM. NUnit 3 replaces + // Console.Out with a TextCapture that resolves the current + // TestExecutionContext on every write; from a thread NUnit doesn't + // know about it tries to manufacture an AdhocContext and NREs in + // MethodWrapper.get_Name, which SIGABRTs the entire process and + // causes the test host to report "0 tests ran" for the assembly. + // Route diagnostics through Android.Util.Log instead. + Android.Util.Log.Info ("ThreadReuse", + "CrossThreadObjectInteractions: JNIEnv.Handle={0} env={1}, instance={2}", JNIEnv.Handle.ToString ("x"), env.ToString ("x"), instance.ToString ("x")); if (env != JNIEnv.Handle) - Console.WriteLine ("GOOD: they should differ (on the second call)...."); + Android.Util.Log.Info ("ThreadReuse", "GOOD: they should differ (on the second call)...."); if (instance == IntPtr.Zero) return; using (var o = Java.Lang.Object.GetObject(env, instance, JniHandleOwnership.DoNotTransfer)) { - Console.WriteLine ("CrossThreadObjectInteractions: o.Handle={0}", o.Handle.ToString ("x")); + Android.Util.Log.Info ("ThreadReuse", "CrossThreadObjectInteractions: o.Handle={0}", o.Handle.ToString ("x")); } }; rt_invoke_callback_on_new_thread (cb);