From 994a410b4478eef496bd230f6d95f576d4aff6d7 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Wed, 22 May 2024 15:11:38 +0200 Subject: [PATCH] [browser] fix marshaling reject(null) (#102549) --- .../JavaScript/JSImportTest.cs | 21 +++++++++++++++++++ .../JavaScript/JavaScriptTestHelper.cs | 3 +++ .../JavaScript/JavaScriptTestHelper.mjs | 4 ++++ .../browser/runtime/cancelable-promise.ts | 5 ++++- 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs index 140fd8f0248f8..86f4712f97bce 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportTest.cs @@ -127,6 +127,27 @@ public unsafe void OutOfRange() Assert.Contains("Overflow: value 9007199254740991 is out of -2147483648 2147483647 range", ex.Message); } + [Fact] + public async Task RejectString() + { + var ex = await Assert.ThrowsAsync(() => JavaScriptTestHelper.Reject("noodles")); + Assert.Contains("noodles", ex.Message); + } + + [Fact] + public async Task RejectException() + { + var expected = new Exception("noodles"); + var actual = await Assert.ThrowsAsync(() => JavaScriptTestHelper.Reject(expected)); + Assert.Equal(expected, actual); + } + + [Fact] + public async Task RejectNull() + { + var ex = await Assert.ThrowsAsync(() => JavaScriptTestHelper.Reject(null)); + } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWasmThreadingSupported))] public unsafe void OptimizedPaths() { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index f78a4105e05ab..aa0c3f4cb86c4 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -37,6 +37,9 @@ public static void ConsoleWriteLine([JSMarshalAs] string message) [JSImport("delay", "JavaScriptTestHelper")] public static partial Task Delay(int ms); + [JSImport("reject", "JavaScriptTestHelper")] + public static partial Task Reject([JSMarshalAs] object what); + [JSImport("intentionallyMissingImport", "JavaScriptTestHelper")] public static partial void IntentionallyMissingImport(); diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs index 9d4851575bf34..266017afdb2d5 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs @@ -448,3 +448,7 @@ export async function setup() { export function delay(ms) { return new Promise(resolve => globalThis.setTimeout(resolve, ms)); } + +export function reject(what) { + return new Promise((_, reject) => globalThis.setTimeout(() => reject(what), 0)); +} diff --git a/src/mono/browser/runtime/cancelable-promise.ts b/src/mono/browser/runtime/cancelable-promise.ts index 6964bee80dc53..fa4e11fe07ee0 100644 --- a/src/mono/browser/runtime/cancelable-promise.ts +++ b/src/mono/browser/runtime/cancelable-promise.ts @@ -111,9 +111,12 @@ export class PromiseHolder extends ManagedObject { mono_log_debug("This promise rejection can't be propagated to managed code, mono runtime already exited."); return; } + if (!reason) { + reason = new Error() as any; + } mono_assert(!this.isResolved, "reject could be called only once"); mono_assert(!this.isDisposed, "resolve is already disposed."); - const isCancelation = reason && reason[promise_holder_symbol] === this; + const isCancelation = reason[promise_holder_symbol] === this; if (WasmEnableThreads && !isCancelation && !this.setIsResolving()) { // we know that cancelation is in flight // because we need to keep the GCHandle alive until until the cancelation arrives