From 4e2d627b4df04bd0bc7f02b65351e7a8e7733a6d Mon Sep 17 00:00:00 2001 From: chicoxyzzy Date: Mon, 5 Oct 2026 11:53:20 +0200 Subject: [PATCH 1/2] [js-api] Reject a mutable global import before allocating Fixes #2253. A non-Global value for a var import was passed to global_alloc as a const global. module_instantiate then rejected the mutability mismatch and left that global in the store. Throw a LinkError before allocating. A const import of a var Global is the same mismatch. Throw before appending that global. A fresh global is allocated with the import's mut, which is const once the var case has been rejected. --- document/js-api/index.bs | 14 +++++++++++--- test/js-api/bad-imports.js | 12 ++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 0348c193eb..43816014ae 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -520,10 +520,17 @@ To instantiate imported strings with module |module| and |importedStr 1. Let |index| be the number of external functions in |imports|. This value |index| is known as the index of the host function |funcaddr|. 1. Let |externfunc| be the [=external value=] [=external value/func=] |funcaddr|. 1. [=list/Append=] |externfunc| to |imports|. - 1. If |externtype| is of the form [=external-type/global=] mut |valtype|, + 1. If |externtype| is of the form [=external-type/global=] |mut| |valtype|, 1. If |v| [=implements=] {{Global}}, 1. Let |globaladdr| be |v|.\[[Global]]. + 1. If |mut| is empty, + 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. + 1. Let |globalmut| |globalvaltype| be [=global_type=](|store|, |globaladdr|). + 1. If |globalmut| is [=mut=], + 1. Throw a {{LinkError}} exception. 1. Otherwise, + 1. If |mut| is [=mut=], + 1. Throw a {{LinkError}} exception. 1. If |valtype| is [=i64=] and |v| [=is not a BigInt=], 1. Throw a {{LinkError}} exception. 1. If |valtype| is one of [=i32=], [=f32=] or [=f64=] and |v| [=is not a Number=], @@ -552,8 +559,9 @@ To instantiate imported strings with module |module| and |importedStr 1. [=list/Append=] |externtag| to |imports|. 1. Return |imports|. -Note: This algorithm only verifies the right kind of JavaScript values are passed. -The verification of WebAssembly type requirements is deferred to the +Note: This algorithm verifies the right kind of JavaScript values are passed. +A value that does not [=implement=] {{Global}} can only initialize an immutable global, and an immutable import cannot be a mutable {{Global}}. +The remaining WebAssembly type requirements are deferred to the "[=instantiate the core of a WebAssembly module=]" algorithm. diff --git a/test/js-api/bad-imports.js b/test/js-api/bad-imports.js index 786fc650e3..c56f21dffa 100644 --- a/test/js-api/bad-imports.js +++ b/test/js-api/bad-imports.js @@ -123,6 +123,18 @@ function test_bad_imports(t) { "global": global, }, }); + + const mutableGlobal = new WebAssembly.Global({ "value": type, "mutable": true }, value); + t(`Importing an ${type} global with a mutable Global object`, + WebAssembly.LinkError, + builder => { + builder.addImportedGlobal("module", "global", value_type(type)); + }, + { + "module": { + "global": mutableGlobal, + }, + }); } const nonMemories = [ From 2d1268d4c0b5c2da50c019fb22a2baec85eb3b1c Mon Sep 17 00:00:00 2001 From: chicoxyzzy Date: Mon, 12 Oct 2026 15:04:39 +0200 Subject: [PATCH 2/2] [js-api] Leave a const import of a var Global to instantiation read the imports does not call global_type. A const import of a var Global allocates nothing, and module_instantiate already rejects both mutability mismatches. The LinkError before global_alloc stays when a var import's value is not a Global. --- document/js-api/index.bs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 43816014ae..f5325c4a42 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -523,11 +523,6 @@ To instantiate imported strings with module |module| and |importedStr 1. If |externtype| is of the form [=external-type/global=] |mut| |valtype|, 1. If |v| [=implements=] {{Global}}, 1. Let |globaladdr| be |v|.\[[Global]]. - 1. If |mut| is empty, - 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. - 1. Let |globalmut| |globalvaltype| be [=global_type=](|store|, |globaladdr|). - 1. If |globalmut| is [=mut=], - 1. Throw a {{LinkError}} exception. 1. Otherwise, 1. If |mut| is [=mut=], 1. Throw a {{LinkError}} exception. @@ -560,7 +555,7 @@ To instantiate imported strings with module |module| and |importedStr 1. Return |imports|. Note: This algorithm verifies the right kind of JavaScript values are passed. -A value that does not [=implement=] {{Global}} can only initialize an immutable global, and an immutable import cannot be a mutable {{Global}}. +A value that does not [=implement=] {{Global}} can only initialize an immutable global. The remaining WebAssembly type requirements are deferred to the "[=instantiate the core of a WebAssembly module=]" algorithm.