Skip to content

Commit 37e1dc7

Browse files
authored
Handle nullexnref on JS boundary (#8437)
Throw a JSException (modeling a TypeError) when passing nullexnref to JS. We had already handled throwing an error when passing a non-null exnref, but without handling nulls, SignatureRefining could optimize a exnref to a nullexnref on the boundary and change the throwing behavior. This was a bug in the interpreter rather than in the optimization pass.
1 parent a092aef commit 37e1dc7

File tree

2 files changed

+69
-11
lines changed

2 files changed

+69
-11
lines changed

src/tools/execution-results.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,13 @@ struct LoggingExternalInterface : public ShellExternalInterface {
319319
Literals arguments;
320320
for (const auto& param : sig.params) {
321321
// An i64 param can work from JS, but fuzz_shell provides 0, which errors
322-
// on attempts to convert it to BigInt. v128 and exnref are disalloewd.
323-
if (param == Type::i64 || param == Type::v128 || param.isExn()) {
322+
// on attempts to convert it to BigInt. v128 is disallowed.
323+
if (param == Type::i64 || param == Type::v128) {
324+
throwJSException();
325+
}
326+
// Exnref and nullexnref are also disallowed.
327+
if (param.isRef() &&
328+
HeapType(param.getHeapType().getTop()).isMaybeShared(HeapType::exn)) {
324329
throwJSException();
325330
}
326331
if (!param.isDefaultable()) {
@@ -332,9 +337,11 @@ struct LoggingExternalInterface : public ShellExternalInterface {
332337
// Error on illegal results. Note that this happens, as per JS semantics,
333338
// *before* the call.
334339
for (const auto& result : sig.results) {
335-
// An i64 result is fine: a BigInt will be provided. But v128 and exnref
336-
// still error.
337-
if (result == Type::v128 || result.isExn()) {
340+
// An i64 result is fine: a BigInt will be provided. But v128 and
341+
// [null]exnref still error.
342+
if (result == Type::v128 ||
343+
(result.isRef() && HeapType(result.getHeapType().getTop())
344+
.isMaybeShared(HeapType::exn))) {
338345
throwJSException();
339346
}
340347
}

test/lit/exec/fuzzing-api.wast

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -357,23 +357,66 @@
357357
)
358358
)
359359

360-
(func $illegal-result (result v128)
360+
(func $illegal-v128-result (result v128)
361361
;; Helper for the function below. The result is illegal for JS.
362362
(call $log-i32
363363
(i32.const 910)
364364
)
365365
(v128.const i32x4 1 2 3 4)
366366
)
367367

368-
;; CHECK: [fuzz-exec] calling ref.calling.illegal-result
368+
;; CHECK: [fuzz-exec] calling ref.calling.illegal-v128-result
369369
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
370-
(func $ref.calling.illegal-result (export "ref.calling.illegal-result")
370+
(func $ref.calling.illegal-v128-result (export "ref.calling.illegal-v128-result")
371371
;; The v128 result causes an error here, so we will log 1 as an exception. The JS
372372
;; semantics determine that we do that check *before* the call, so the logging
373373
;; of 910 does not go through.
374374
(call $log-i32
375375
(call $call.ref.catch
376-
(ref.func $illegal-result)
376+
(ref.func $illegal-v128-result)
377+
)
378+
)
379+
)
380+
381+
(func $illegal-exnref-result (result exnref)
382+
;; Helper for the function below. The result is illegal for JS.
383+
(call $log-i32
384+
(i32.const 911)
385+
)
386+
(block $l (result exnref)
387+
(try_table (catch_all_ref $l)
388+
(call $throwing)
389+
)
390+
(unreachable)
391+
)
392+
)
393+
394+
;; CHECK: [fuzz-exec] calling ref.calling.illegal-exnref-result
395+
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
396+
(func $ref.calling.illegal-exnref-result (export "ref.calling.illegal-exnref-result")
397+
;; As above with the v128, the exnref cannot be converted to a JS value.
398+
(call $log-i32
399+
(call $call.ref.catch
400+
(ref.func $illegal-exnref-result)
401+
)
402+
)
403+
)
404+
405+
(func $illegal-nullexnref-result (result nullexnref)
406+
;; Helper for the function below. The result is illegal for JS.
407+
(call $log-i32
408+
(i32.const 912)
409+
)
410+
(ref.null noexn)
411+
)
412+
413+
;; CHECK: [fuzz-exec] calling ref.calling.illegal-nullexnref-result
414+
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
415+
(func $ref.calling.illegal-nullexnref-result (export "ref.calling.illegal-nullexnref-result")
416+
;; As above, the nullexnref cannot be converted to a JS value.
417+
(call $log-i32
418+
(call $call.ref.catch
419+
(ref.func $illegal-nullexnref-result)
377420
)
378421
)
379422
)
@@ -564,7 +607,13 @@
564607
;; CHECK: [fuzz-exec] calling ref.calling.illegal-exnref
565608
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
566609

567-
;; CHECK: [fuzz-exec] calling ref.calling.illegal-result
610+
;; CHECK: [fuzz-exec] calling ref.calling.illegal-v128-result
611+
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
612+
613+
;; CHECK: [fuzz-exec] calling ref.calling.illegal-exnref-result
614+
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
615+
616+
;; CHECK: [fuzz-exec] calling ref.calling.illegal-nullexnref-result
568617
;; CHECK-NEXT: [LoggingExternalInterface logging 1]
569618

570619
;; CHECK: [fuzz-exec] calling ref.calling.legal-result
@@ -592,8 +641,10 @@
592641
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.catching
593642
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal
594643
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-exnref
595-
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-result
644+
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-exnref-result
645+
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-nullexnref-result
596646
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-v128
647+
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.illegal-v128-result
597648
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal
598649
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.legal-result
599650
;; CHECK-NEXT: [fuzz-exec] comparing ref.calling.rethrow

0 commit comments

Comments
 (0)