Skip to content

[EH] Fuzzer: Add WebAssembly.JSTag fuzzing #7283

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 30 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions scripts/fuzz_shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ var imports = {
if (!which) {
throw 'some JS error';
} else {
throw new WebAssembly.Exception(jsTag, [which]);
throw new WebAssembly.Exception(wasmTag, [which]);
}
},

Expand Down Expand Up @@ -333,10 +333,13 @@ var imports = {
// If Tags are available, add some.
if (typeof WebAssembly.Tag !== 'undefined') {
// A tag for general use in the fuzzer.
var jsTag = imports['fuzzing-support']['tag'] = new WebAssembly.Tag({
var wasmTag = imports['fuzzing-support']['wasmtag'] = new WebAssembly.Tag({
'parameters': ['i32']
});

// The JSTag that represents a JS tag.
imports['fuzzing-support']['jstag'] = WebAssembly.JSTag;

// This allows j2wasm content to run in the fuzzer.
imports['imports'] = {
'j2wasm.ExceptionUtils.tag': new WebAssembly.Tag({
Expand Down
10 changes: 5 additions & 5 deletions src/tools/execution-results.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ struct LoggingExternalInterface : public ShellExternalInterface {
Name exportedTable;
Module& wasm;

// The name of the imported fuzzing tag.
Name fuzzTag;
// The name of the imported fuzzing tag for wasm.
Name wasmTag;

// The ModuleRunner and this ExternalInterface end up needing links both ways,
// so we cannot init this in the constructor.
Expand All @@ -60,8 +60,8 @@ struct LoggingExternalInterface : public ShellExternalInterface {
}

for (auto& tag : wasm.tags) {
if (tag->module == "fuzzing-support" && tag->base == "tag") {
fuzzTag = tag->name;
if (tag->module == "fuzzing-support" && tag->base == "wasmtag") {
wasmTag = tag->name;
break;
}
}
Expand Down Expand Up @@ -98,7 +98,7 @@ struct LoggingExternalInterface : public ShellExternalInterface {
if (arguments[0].geti32() == 0) {
throwEmptyException();
} else {
auto payload = std::make_shared<ExnData>(fuzzTag, arguments);
auto payload = std::make_shared<ExnData>(wasmTag, arguments);
throwException(WasmException{Literal(payload)});
}
} else if (import->base == "table-get") {
Expand Down
19 changes: 13 additions & 6 deletions src/tools/fuzzing/fuzzing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -648,13 +648,20 @@ void TranslateToFuzzReader::setupTags() {
addTag();
}

// Add the fuzzing support tag manually sometimes.
// Add the fuzzing support tags manually sometimes.
if (oneIn(2)) {
auto tag = builder.makeTag(Names::getValidTagName(wasm, "tag"),
Signature(Type::i32, Type::none));
tag->module = "fuzzing-support";
tag->base = "tag";
wasm.addTag(std::move(tag));
auto wasmTag = builder.makeTag(Names::getValidTagName(wasm, "wasmtag"),
Signature(Type::i32, Type::none));
wasmTag->module = "fuzzing-support";
wasmTag->base = "wasmtag";
wasm.addTag(std::move(wasmTag));

auto externref = Type(HeapType::ext, Nullable);
auto jsTag = builder.makeTag(Names::getValidTagName(wasm, "jstag"),
Signature(externref, Type::none));
jsTag->module = "fuzzing-support";
jsTag->base = "jstag";
wasm.addTag(std::move(jsTag));
}
}

Expand Down
6 changes: 5 additions & 1 deletion test/lit/d8/fuzz_shell_exceptions.wast
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
(module
(import "fuzzing-support" "throw" (func $throw (param i32)))

;; Verify that fuzz_shell.js provides these imports for the wasm.
(import "fuzzing-support" "wasmtag" (tag $imported-wasm-tag (param i32)))
(import "fuzzing-support" "jstag" (tag $imported-js-tag (param externref)))

(func $throwing-js (export "throwing-js")
;; Telling JS to throw with arg 0 leads to a JS exception thrown.
(call $throw
Expand All @@ -20,7 +24,7 @@

;; Build to a binary wasm.
;;
;; RUN: wasm-opt %s -o %t.wasm -q
;; RUN: wasm-opt %s -o %t.wasm -q -all

;; Run in node.
;;
Expand Down
7 changes: 4 additions & 3 deletions test/lit/exec/fuzzing-api.wast
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

(import "fuzzing-support" "sleep" (func $sleep (param i32 i32) (result i32)))

(import "fuzzing-support" "tag" (tag $imported-tag (param i32)))
(import "fuzzing-support" "wasmtag" (tag $imported-wasm-tag (param i32)))
(import "fuzzing-support" "jstag" (tag $imported-js-tag (param externref)))

(table $table 10 20 funcref)

Expand Down Expand Up @@ -51,7 +52,7 @@
)

;; CHECK: [fuzz-exec] calling throwing-tag
;; CHECK-NEXT: [exception thrown: imported-tag 42]
;; CHECK-NEXT: [exception thrown: imported-wasm-tag 42]
(func $throwing-tag (export "throwing-tag")
;; Throwing non-0 throws using the tag we imported.
(call $throw
Expand Down Expand Up @@ -330,7 +331,7 @@
;; CHECK-NEXT: [exception thrown: __private ()]

;; CHECK: [fuzz-exec] calling throwing-tag
;; CHECK-NEXT: [exception thrown: imported-tag 42]
;; CHECK-NEXT: [exception thrown: imported-wasm-tag 42]

;; CHECK: [fuzz-exec] calling table.setting
;; CHECK-NEXT: [exception thrown: __private ()]
Expand Down
51 changes: 27 additions & 24 deletions test/passes/translate-to-fuzz_all-features_metrics_noprint.txt
Original file line number Diff line number Diff line change
@@ -1,42 +1,45 @@
Metrics
total
[exports] : 15
[funcs] : 17
[exports] : 14
[funcs] : 18
[globals] : 4
[imports] : 11
[imports] : 12
[memories] : 1
[memory-data] : 112
[table-data] : 4
[table-data] : 3
[tables] : 1
[tags] : 0
[total] : 688
[vars] : 15
[total] : 626
[vars] : 49
ArrayNew : 1
ArrayNewFixed : 5
Binary : 70
Block : 77
Call : 43
Const : 166
Drop : 8
GlobalGet : 43
ArraySet : 1
AtomicCmpxchg : 1
AtomicFence : 1
Binary : 74
Block : 79
Call : 40
Const : 138
Drop : 9
GlobalGet : 42
GlobalSet : 38
If : 19
If : 20
Load : 16
LocalGet : 45
LocalSet : 21
Loop : 3
Nop : 3
LocalGet : 46
LocalSet : 22
Loop : 2
Nop : 4
RefAs : 2
RefFunc : 28
RefNull : 8
Return : 5
RefFunc : 8
RefNull : 4
Return : 3
Select : 1
Store : 1
StringConst : 2
StructNew : 37
StringConst : 3
StructNew : 18
StructSet : 1
Throw : 1
TryTable : 3
TryTable : 2
TupleMake : 3
Unary : 19
Unary : 21
Unreachable : 19