From 808be8a27f7adf00f2410219507b649cdab4aa99 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 25 May 2022 10:09:57 -0700 Subject: [Wasm GC] Fix CFG traversal of call_ref and add missing validation check (#4690) We were missing CallRef in the CFG traversal code in a place where we note possible exceptions. As a result we thought CallRef cannot throw, and were missing some control flow edges. To actually detect the problem, we need to validate non-nullable locals properly, which we were not doing. This adds that as well. --- src/wasm/wasm-validator.cpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'src/wasm/wasm-validator.cpp') diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index c74d95fdd..9845da72c 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -23,6 +23,7 @@ #include "ir/features.h" #include "ir/global-utils.h" #include "ir/intrinsics.h" +#include "ir/local-graph.h" #include "ir/module-utils.h" #include "ir/stack-utils.h" #include "ir/utils.h" @@ -2779,6 +2780,37 @@ void FunctionValidator::visitFunction(Function* curr) { Name name = pair.second; shouldBeTrue(seen.insert(name).second, name, "local names must be unique"); } + + if (getModule()->features.hasGCNNLocals()) { + // If we have non-nullable locals, verify that no local.get can read a null + // default value. + // TODO: this can be fairly slow due to the LocalGraph. writing more code to + // do a more specific analysis (we don't need to know all sets, just + // if there is a set of a null default value that is read) could be a + // lot faster. + bool hasNNLocals = false; + for (const auto& var : curr->vars) { + if (var.isNonNullable()) { + hasNNLocals = true; + break; + } + } + if (hasNNLocals) { + LocalGraph graph(curr); + for (auto& [get, sets] : graph.getSetses) { + auto index = get->index; + // It is always ok to read nullable locals, and it is always ok to read + // params even if they are non-nullable. + if (!curr->getLocalType(index).isNonNullable() || + curr->isParam(index)) { + continue; + } + for (auto* set : sets) { + shouldBeTrue(!!set, index, "non-nullable local must not read null"); + } + } + } + } } static bool checkSegmentOffset(Expression* curr, -- cgit v1.2.3