Skip to content

Commit ed5a555

Browse files
committed
wasm: catch and rethrow stack overflows (#3915)
1 parent 11d3196 commit ed5a555

File tree

1 file changed

+30
-11
lines changed

1 file changed

+30
-11
lines changed

lib/npm/browser.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ const startRunningService = async (wasmURL: string | URL, wasmModule: WebAssembl
8888
terminate: () => void
8989
}
9090

91+
let rejectAllWith: (error: unknown) => void
92+
const rejectAllPromise = new Promise(resolve => rejectAllWith = resolve)
93+
9194
if (useWorker) {
9295
// Run esbuild off the main thread
9396
let blob = new Blob([`onmessage=${WEB_WORKER_SOURCE_CODE}(postMessage)`], { type: 'text/javascript' })
@@ -98,7 +101,13 @@ const startRunningService = async (wasmURL: string | URL, wasmModule: WebAssembl
98101
let go: Go | undefined
99102
worker = {
100103
onmessage: null,
101-
postMessage: data => setTimeout(() => go = onmessage({ data })),
104+
postMessage: data => setTimeout(() => {
105+
try {
106+
go = onmessage({ data })
107+
} catch (error) {
108+
rejectAllWith(error) // Catch strange crashes (e.g. stack overflow)
109+
}
110+
}),
102111
terminate() {
103112
if (go)
104113
for (let timeout of go._scheduledTimeouts.values())
@@ -144,29 +153,34 @@ const startRunningService = async (wasmURL: string | URL, wasmModule: WebAssembl
144153

145154
longLivedService = {
146155
build: (options: types.BuildOptions) =>
147-
new Promise<types.BuildResult>((resolve, reject) =>
156+
new Promise<types.BuildResult>((resolve, reject) => {
157+
rejectAllPromise.then(reject)
148158
service.buildOrContext({
149159
callName: 'build',
150160
refs: null,
151161
options,
152162
isTTY: false,
153163
defaultWD: '/',
154164
callback: (err, res) => err ? reject(err) : resolve(res as types.BuildResult),
155-
})),
165+
})
166+
}),
156167

157168
context: (options: types.BuildOptions) =>
158-
new Promise<types.BuildContext>((resolve, reject) =>
169+
new Promise<types.BuildContext>((resolve, reject) => {
170+
rejectAllPromise.then(reject)
159171
service.buildOrContext({
160172
callName: 'context',
161173
refs: null,
162174
options,
163175
isTTY: false,
164176
defaultWD: '/',
165177
callback: (err, res) => err ? reject(err) : resolve(res as types.BuildContext),
166-
})),
178+
})
179+
}),
167180

168181
transform: (input: string | Uint8Array, options?: types.TransformOptions) =>
169-
new Promise<types.TransformResult>((resolve, reject) =>
182+
new Promise<types.TransformResult>((resolve, reject) => {
183+
rejectAllPromise.then(reject)
170184
service.transform({
171185
callName: 'transform',
172186
refs: null,
@@ -178,27 +192,32 @@ const startRunningService = async (wasmURL: string | URL, wasmModule: WebAssembl
178192
writeFile(_, callback) { callback(null); },
179193
},
180194
callback: (err, res) => err ? reject(err) : resolve(res!),
181-
})),
195+
})
196+
}),
182197

183198
formatMessages: (messages, options) =>
184-
new Promise((resolve, reject) =>
199+
new Promise((resolve, reject) => {
200+
rejectAllPromise.then(reject)
185201
service.formatMessages({
186202
callName: 'formatMessages',
187203
refs: null,
188204
messages,
189205
options,
190206
callback: (err, res) => err ? reject(err) : resolve(res!),
191-
})),
207+
})
208+
}),
192209

193210
analyzeMetafile: (metafile, options) =>
194-
new Promise((resolve, reject) =>
211+
new Promise((resolve, reject) => {
212+
rejectAllPromise.then(reject)
195213
service.analyzeMetafile({
196214
callName: 'analyzeMetafile',
197215
refs: null,
198216
metafile: typeof metafile === 'string' ? metafile : JSON.stringify(metafile),
199217
options,
200218
callback: (err, res) => err ? reject(err) : resolve(res!),
201-
})),
219+
})
220+
}),
202221
}
203222
}
204223

0 commit comments

Comments
 (0)