Skip to content

Commit 99a2a60

Browse files
committed
Forward extra arguments and guard buffer registration
1 parent 5ae3418 commit 99a2a60

2 files changed

Lines changed: 61 additions & 21 deletions

File tree

packages/wasm/src/patchWebAssembly.ts

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function registerFromBufferSource(
6868
): void {
6969
const url = getWasmSourceUrl(source);
7070
if (url) {
71-
registerModule(module, url);
71+
registerSafely(registerModule, module, url);
7272
}
7373
}
7474

@@ -82,34 +82,26 @@ function patchNonStreamingWebAssembly(registerModule: RegisterModuleCallback): v
8282

8383
nonStreamingPatched = true;
8484

85-
const origInstantiate = WebAssembly.instantiate;
86-
WebAssembly.instantiate = function instantiate(
87-
source: BufferSource | WebAssembly.Module,
88-
importObject?: WebAssembly.Imports,
89-
) {
85+
// Double-cast, because the overloaded native signature (buffer vs. module
86+
// first argument) cannot be widened to a pass-through shape in one step.
87+
const origInstantiate = WebAssembly.instantiate as unknown as (
88+
source: unknown,
89+
...rest: unknown[]
90+
) => Promise<WebAssembly.WebAssemblyInstantiatedSource>;
91+
WebAssembly.instantiate = function instantiate(source: BufferSource | WebAssembly.Module, ...rest: unknown[]) {
9092
if (source instanceof WebAssembly.Module) {
91-
return (
92-
origInstantiate as (
93-
moduleObject: WebAssembly.Module,
94-
importObject?: WebAssembly.Imports,
95-
) => Promise<WebAssembly.Instance>
96-
)(source, importObject);
93+
return origInstantiate(source, ...rest);
9794
}
9895

99-
return (
100-
origInstantiate as (
101-
bytes: BufferSource,
102-
importObject?: WebAssembly.Imports,
103-
) => Promise<WebAssembly.WebAssemblyInstantiatedSource>
104-
)(source, importObject).then(result => {
96+
return origInstantiate(source, ...rest).then(result => {
10597
registerFromBufferSource(registerModule, result.module, source);
10698
return result;
10799
});
108100
} as typeof WebAssembly.instantiate;
109101

110-
const origCompile = WebAssembly.compile;
111-
WebAssembly.compile = function compile(source: BufferSource): Promise<WebAssembly.Module> {
112-
return origCompile(source).then(module => {
102+
const origCompile = WebAssembly.compile as (source: unknown, ...rest: unknown[]) => Promise<WebAssembly.Module>;
103+
WebAssembly.compile = function compile(source: BufferSource, ...rest: unknown[]): Promise<WebAssembly.Module> {
104+
return origCompile(source, ...rest).then(module => {
113105
registerFromBufferSource(registerModule, module, source);
114106
return module;
115107
});

packages/wasm/test/patchWebAssembly.test.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,51 @@ describe('patchWebAssembly() non-streaming registration', () => {
154154
expect(IMAGES).toHaveLength(0);
155155
});
156156
});
157+
158+
describe('patchWebAssembly() non-streaming argument forwarding', () => {
159+
const savedGlobals = saveWasmGlobals();
160+
161+
afterEach(() => {
162+
restoreWasmGlobals(savedGlobals);
163+
});
164+
165+
it('forwards every argument to instantiate', async () => {
166+
const orig = vi.fn().mockResolvedValue({ module: MODULE, instance: {} });
167+
WebAssembly.instantiate = orig as unknown as typeof WebAssembly.instantiate;
168+
169+
patchWebAssembly(registerModule);
170+
171+
const bytes = new Uint8Array(8);
172+
const compileOptions = { builtins: ['js-string'] };
173+
await (WebAssembly.instantiate as unknown as (...args: unknown[]) => Promise<unknown>)(
174+
bytes,
175+
WASM_IMPORTS,
176+
compileOptions,
177+
);
178+
179+
expect(orig).toHaveBeenCalledWith(bytes, WASM_IMPORTS, compileOptions);
180+
});
181+
182+
it('forwards every argument to compile', async () => {
183+
const orig = vi.fn().mockResolvedValue(MODULE);
184+
WebAssembly.compile = orig as unknown as typeof WebAssembly.compile;
185+
186+
patchWebAssembly(registerModule);
187+
188+
const bytes = new Uint8Array(8);
189+
const compileOptions = { builtins: ['js-string'] };
190+
await (WebAssembly.compile as unknown as (...args: unknown[]) => Promise<unknown>)(bytes, compileOptions);
191+
192+
expect(orig).toHaveBeenCalledWith(bytes, compileOptions);
193+
});
194+
195+
it('resolves the original result even if registration throws', async () => {
196+
patchWebAssembly(() => {
197+
throw new Error('registration failed');
198+
});
199+
200+
const buffer = await fetchWasmBytes();
201+
202+
await expect(WebAssembly.compile(buffer)).resolves.toBeInstanceOf(WebAssembly.Module);
203+
});
204+
});

0 commit comments

Comments
 (0)