summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/asm_v_wasm.h1
-rw-r--r--src/wasm-interpreter.h72
-rw-r--r--test/passes/Oz_fuzz-exec_all-features.txt52
-rw-r--r--test/passes/Oz_fuzz-exec_all-features.wast30
4 files changed, 127 insertions, 28 deletions
diff --git a/src/asm_v_wasm.h b/src/asm_v_wasm.h
index 9b2ee7695..d2089b569 100644
--- a/src/asm_v_wasm.h
+++ b/src/asm_v_wasm.h
@@ -26,7 +26,6 @@ namespace wasm {
AsmType wasmToAsmType(Type type);
char getSig(Type type);
-std::string getSig(Function* func);
std::string getSig(Type results, Type params);
template<typename ListType>
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 26764c304..ba6f5d6ee 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -157,6 +157,10 @@ public:
template<typename SubType>
class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
protected:
+ // Optional module context to search for globals and called functions. NULL if
+ // we are not interested in any context.
+ Module* module = nullptr;
+
// Maximum depth before giving up.
Index maxDepth;
Index depth = 0;
@@ -183,9 +187,11 @@ public:
// Indicates no limit of maxDepth or maxLoopIterations.
static const Index NO_LIMIT = 0;
- ExpressionRunner(Index maxDepth = NO_LIMIT,
+ ExpressionRunner(Module* module = nullptr,
+ Index maxDepth = NO_LIMIT,
Index maxLoopIterations = NO_LIMIT)
- : maxDepth(maxDepth), maxLoopIterations(maxLoopIterations) {}
+ : module(module), maxDepth(maxDepth), maxLoopIterations(maxLoopIterations) {
+ }
Flow visit(Expression* curr) {
depth++;
@@ -210,6 +216,9 @@ public:
return ret;
}
+ // Gets the module this runner is operating on.
+ Module* getModule() { return module; }
+
Flow visitBlock(Block* curr) {
NOTE_ENTER("Block");
// special-case Block, because Block nesting (in their first element) can be
@@ -1426,24 +1435,38 @@ public:
cast.outcome = cast.Null;
return cast;
}
- // The input may not be a struct or an array; for example it could be an
+ // The input may not be GC data or a function; for example it could be an
// anyref of null (already handled above) or anything else (handled here,
// but this is for future use as atm the binaryen interpreter cannot
// represent external references).
- if (!cast.originalRef.isData()) {
+ if (!cast.originalRef.isData() && !cast.originalRef.isFunction()) {
cast.outcome = cast.Failure;
return cast;
}
- auto gcData = cast.originalRef.getGCData();
- auto refRtt = gcData->rtt;
- auto intendedRtt = rtt.getSingleValue();
- if (!refRtt.isSubRtt(intendedRtt)) {
- cast.outcome = cast.Failure;
+ Literal seenRtt;
+ Literal intendedRtt = rtt.getSingleValue();
+ if (cast.originalRef.isFunction()) {
+ // Function casts are simple in that they have no RTT hierarchies; instead
+ // each reference has the canonical RTT for the signature.
+ // We must have a module in order to perform the cast, to get the type.
+ assert(module);
+ auto* func = module->getFunction(cast.originalRef.getFunc());
+ seenRtt = Literal(Type(Rtt(0, func->sig)));
+ cast.castRef =
+ Literal(func->name, Type(intendedRtt.type.getHeapType(), Nullable));
} else {
- cast.outcome = cast.Success;
+ // GC data store an RTT in each instance.
+ assert(cast.originalRef.isData());
+ auto gcData = cast.originalRef.getGCData();
+ seenRtt = gcData->rtt;
cast.castRef =
Literal(gcData, Type(intendedRtt.type.getHeapType(), Nullable));
}
+ if (!seenRtt.isSubRtt(intendedRtt)) {
+ cast.outcome = cast.Failure;
+ } else {
+ cast.outcome = cast.Success;
+ }
return cast;
}
@@ -1788,10 +1811,6 @@ public:
static const Index NO_LIMIT = 0;
protected:
- // Optional module context to search for globals and called functions. NULL if
- // we are not interested in any context.
- Module* module = nullptr;
-
// Flags indicating special requirements. See FlagValues.
Flags flags = FlagValues::DEFAULT;
@@ -1808,12 +1827,9 @@ public:
Flags flags,
Index maxDepth,
Index maxLoopIterations)
- : ExpressionRunner<SubType>(maxDepth, maxLoopIterations), module(module),
+ : ExpressionRunner<SubType>(module, maxDepth, maxLoopIterations),
flags(flags) {}
- // Gets the module this runner is operating on.
- Module* getModule() { return module; }
-
// Sets a known local value to use.
void setLocalValue(Index index, Literals& values) {
assert(values.isConcrete());
@@ -1858,8 +1874,8 @@ public:
Flow visitGlobalGet(GlobalGet* curr) {
NOTE_ENTER("GlobalGet");
NOTE_NAME(curr->name);
- if (module != nullptr) {
- auto* global = module->getGlobal(curr->name);
+ if (this->module != nullptr) {
+ auto* global = this->module->getGlobal(curr->name);
// Check if the global has an immutable value anyway
if (!global->imported() && !global->mutable_) {
return ExpressionRunner<SubType>::visit(global->init);
@@ -1875,10 +1891,11 @@ public:
Flow visitGlobalSet(GlobalSet* curr) {
NOTE_ENTER("GlobalSet");
NOTE_NAME(curr->name);
- if (!(flags & FlagValues::PRESERVE_SIDEEFFECTS) && module != nullptr) {
+ if (!(flags & FlagValues::PRESERVE_SIDEEFFECTS) &&
+ this->module != nullptr) {
// If we are evaluating and not replacing the expression, remember the
// constant value set, if any, for subsequent gets.
- auto* global = module->getGlobal(curr->name);
+ auto* global = this->module->getGlobal(curr->name);
assert(global->mutable_);
auto setFlow = ExpressionRunner<SubType>::visit(curr->value);
if (!setFlow.breaking()) {
@@ -1895,8 +1912,8 @@ public:
// when replacing as long as the function does not have any side effects.
// Might yield something useful for simple functions like `clamp`, sometimes
// even if arguments are only partially constant or not constant at all.
- if ((flags & FlagValues::TRAVERSE_CALLS) != 0 && module != nullptr) {
- auto* func = module->getFunction(curr->target);
+ if ((flags & FlagValues::TRAVERSE_CALLS) != 0 && this->module != nullptr) {
+ auto* func = this->module->getFunction(curr->target);
if (!func->imported()) {
if (func->sig.results.isConcrete()) {
auto numOperands = curr->operands.size();
@@ -2023,7 +2040,8 @@ class InitializerExpressionRunner
public:
InitializerExpressionRunner(GlobalManager& globals, Index maxDepth)
- : ExpressionRunner<InitializerExpressionRunner<GlobalManager>>(maxDepth),
+ : ExpressionRunner<InitializerExpressionRunner<GlobalManager>>(nullptr,
+ maxDepth),
globals(globals) {}
Flow visitGlobalGet(GlobalGet* curr) { return Flow(globals[curr->name]); }
@@ -2384,8 +2402,8 @@ private:
RuntimeExpressionRunner(ModuleInstanceBase& instance,
FunctionScope& scope,
Index maxDepth)
- : ExpressionRunner<RuntimeExpressionRunner>(maxDepth), instance(instance),
- scope(scope) {}
+ : ExpressionRunner<RuntimeExpressionRunner>(&instance.wasm, maxDepth),
+ instance(instance), scope(scope) {}
Flow visitCall(Call* curr) {
NOTE_ENTER("Call");
diff --git a/test/passes/Oz_fuzz-exec_all-features.txt b/test/passes/Oz_fuzz-exec_all-features.txt
index 48c9ecb5e..60d593b45 100644
--- a/test/passes/Oz_fuzz-exec_all-features.txt
+++ b/test/passes/Oz_fuzz-exec_all-features.txt
@@ -25,6 +25,13 @@
[LoggingExternalInterface logging 0]
[fuzz-exec] calling br_on_data
[LoggingExternalInterface logging 1]
+[fuzz-exec] calling $rtt-and-cast-on-func
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 2]
+[LoggingExternalInterface logging 1337]
+[LoggingExternalInterface logging 3]
+[trap cast error]
(module
(type ${mut:i32} (struct (field (mut i32))))
(type $none_=>_none (func))
@@ -32,6 +39,7 @@
(type $[mut:i8] (array (mut i8)))
(type $i32_=>_none (func (param i32)))
(type $anyref_=>_none (func (param anyref)))
+ (type $none_=>_i32 (func (result i32)))
(import "fuzzing-support" "log-i32" (func $log (param i32)))
(export "structs" (func $0))
(export "arrays" (func $1))
@@ -39,6 +47,7 @@
(export "br_on_cast" (func $3))
(export "cast-null-anyref-to-gc" (func $4))
(export "br_on_data" (func $5))
+ (export "$rtt-and-cast-on-func" (func $7))
(func $0 (; has Stack IR ;)
(local $0 (ref null ${mut:i32}))
(call $log
@@ -187,6 +196,42 @@
)
)
)
+ (func $a-void-func (; has Stack IR ;)
+ (call $log
+ (i32.const 1337)
+ )
+ )
+ (func $7 (; has Stack IR ;)
+ (call $log
+ (i32.const 0)
+ )
+ (call $log
+ (i32.const 1)
+ )
+ (call $log
+ (i32.const 2)
+ )
+ (call_ref
+ (ref.cast $none_=>_none
+ (ref.func $a-void-func)
+ (rtt.canon $none_=>_none)
+ )
+ )
+ (call $log
+ (i32.const 3)
+ )
+ (drop
+ (call_ref
+ (ref.cast $none_=>_i32
+ (ref.func $a-void-func)
+ (rtt.canon $none_=>_i32)
+ )
+ )
+ )
+ (call $log
+ (i32.const 4)
+ )
+ )
)
[fuzz-exec] calling structs
[LoggingExternalInterface logging 0]
@@ -215,3 +260,10 @@
[LoggingExternalInterface logging 0]
[fuzz-exec] calling br_on_data
[LoggingExternalInterface logging 1]
+[fuzz-exec] calling $rtt-and-cast-on-func
+[LoggingExternalInterface logging 0]
+[LoggingExternalInterface logging 1]
+[LoggingExternalInterface logging 2]
+[LoggingExternalInterface logging 1337]
+[LoggingExternalInterface logging 3]
+[trap cast error]
diff --git a/test/passes/Oz_fuzz-exec_all-features.wast b/test/passes/Oz_fuzz-exec_all-features.wast
index a33f02fb5..44ea8625b 100644
--- a/test/passes/Oz_fuzz-exec_all-features.wast
+++ b/test/passes/Oz_fuzz-exec_all-features.wast
@@ -2,7 +2,12 @@
(type $struct (struct (mut i32)))
(type $extendedstruct (struct i32 f64))
(type $bytes (array (mut i8)))
+
+ (type $void_func (func))
+ (type $int_func (func (result i32)))
+
(import "fuzzing-support" "log-i32" (func $log (param i32)))
+
(func "structs"
(local $x (ref null $struct))
(local $y (ref null $struct))
@@ -196,4 +201,29 @@
)
)
)
+ (func $a-void-func
+ (call $log (i32.const 1337))
+ )
+ (func "$rtt-and-cast-on-func"
+ (call $log (i32.const 0))
+ (drop
+ (rtt.canon $void_func)
+ )
+ (call $log (i32.const 1))
+ (drop
+ (rtt.canon $int_func)
+ )
+ (call $log (i32.const 2))
+ ;; a valid cast
+ (call_ref
+ (ref.cast $void_func (ref.func $a-void-func) (rtt.canon $void_func))
+ )
+ (call $log (i32.const 3))
+ ;; an invalid cast
+ (drop (call_ref
+ (ref.cast $int_func (ref.func $a-void-func) (rtt.canon $int_func))
+ ))
+ ;; will never be reached
+ (call $log (i32.const 4))
+ )
)