Commit 5ec483c3 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[wasm][fuzzer] Reuse more logic across fuzzers

This removes the {InterpretWasmModuleForTesting} function in favor of
{InterpretWasmModule}, and uses that in {InterpretAndExecuteModule}.
The latter again is reused in {WasmExecutionFuzzer::FuzzWasmModule},
such that all fuzzers execute the same checks now.

R=ahaas@chromium.org

Bug: chromium:1112099, chromium:1113681
Change-Id: Ia8818b93e9274266a81573edd6852e4e4734b150
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2346283
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69331}
parent 28133adc
......@@ -649,7 +649,7 @@ class WasmExportedFunction : public JSFunction {
Address GetWasmCallTarget();
const wasm::FunctionSig* sig();
V8_EXPORT_PRIVATE const wasm::FunctionSig* sig();
DECL_CAST(WasmExportedFunction)
OBJECT_CONSTRUCTORS(WasmExportedFunction, JSFunction);
......
......@@ -41,54 +41,14 @@ MaybeHandle<WasmInstanceObject> CompileAndInstantiateForTesting(
isolate, thrower, module.ToHandleChecked(), {}, {});
}
WasmInterpretationResult GetInterpretationResult(
Isolate* isolate, const WasmInterpreter& interpreter,
WasmInterpreter::State interpreter_result) {
bool stack_overflow = isolate->has_pending_exception();
isolate->clear_pending_exception();
if (stack_overflow) return WasmInterpretationResult::Failed();
if (interpreter.state() == WasmInterpreter::TRAPPED) {
return WasmInterpretationResult::Trapped(
interpreter.PossibleNondeterminism());
}
if (interpreter_result == WasmInterpreter::FINISHED) {
return WasmInterpretationResult::Finished(
interpreter.GetReturnValue().to<int32_t>(),
interpreter.PossibleNondeterminism());
}
// The interpreter did not finish within the limited number of steps, so it
// might execute an infinite loop or infinite recursion. Return "failed"
// status in that case.
return WasmInterpretationResult::Failed();
}
WasmInterpretationResult InterpretWasmModuleForTesting(
Isolate* isolate, Handle<WasmInstanceObject> instance, size_t argc,
WasmValue* args) {
HandleScope handle_scope(isolate); // Avoid leaking handles.
WasmCodeRefScope code_ref_scope;
Handle<WasmExportedFunction> function;
if (!GetExportedFunction(isolate, instance, "main").ToHandle(&function)) {
return WasmInterpretationResult::Failed();
}
int function_index = function->function_index();
const FunctionSig* signature =
instance->module()->functions[function_index].sig;
size_t param_count = signature->parameter_count();
std::unique_ptr<WasmValue[]> arguments(new WasmValue[param_count]);
size_t arg_count = std::min(param_count, argc);
if (arg_count > 0) {
memcpy(arguments.get(), args, arg_count);
}
std::unique_ptr<WasmValue[]> MakeDefaultArguments(Isolate* isolate,
const FunctionSig* sig) {
size_t param_count = sig->parameter_count();
auto arguments = std::make_unique<WasmValue[]>(param_count);
// Fill the parameters up with default values.
for (size_t i = argc; i < param_count; ++i) {
switch (signature->GetParam(i).kind()) {
for (size_t i = 0; i < param_count; ++i) {
switch (sig->GetParam(i).kind()) {
case ValueType::kI32:
arguments[i] = WasmValue(int32_t{0});
break;
......@@ -116,20 +76,7 @@ WasmInterpretationResult InterpretWasmModuleForTesting(
}
}
// Don't execute more than 16k steps.
constexpr int kMaxNumSteps = 16 * 1024;
Zone zone(isolate->allocator(), ZONE_NAME);
WasmInterpreter interpreter{
isolate, instance->module(),
ModuleWireBytes{instance->module_object().native_module()->wire_bytes()},
instance};
interpreter.InitFrame(&instance->module()->functions[function_index],
arguments.get());
WasmInterpreter::State interpreter_result = interpreter.Run(kMaxNumSteps);
return GetInterpretationResult(isolate, interpreter, interpreter_result);
return arguments;
}
int32_t CompileAndRunWasmModule(Isolate* isolate, const byte* module_start,
......@@ -161,7 +108,26 @@ WasmInterpretationResult InterpretWasmModule(
interpreter.InitFrame(&instance->module()->functions[function_index], args);
WasmInterpreter::State interpreter_result = interpreter.Run(kMaxNumSteps);
return GetInterpretationResult(isolate, interpreter, interpreter_result);
bool stack_overflow = isolate->has_pending_exception();
isolate->clear_pending_exception();
if (stack_overflow) return WasmInterpretationResult::Failed();
if (interpreter.state() == WasmInterpreter::TRAPPED) {
return WasmInterpretationResult::Trapped(
interpreter.PossibleNondeterminism());
}
if (interpreter_result == WasmInterpreter::FINISHED) {
return WasmInterpretationResult::Finished(
interpreter.GetReturnValue().to<int32_t>(),
interpreter.PossibleNondeterminism());
}
// The interpreter did not finish within the limited number of steps, so it
// might execute an infinite loop or infinite recursion. Return "failed"
// status in that case.
return WasmInterpretationResult::Failed();
}
MaybeHandle<WasmExportedFunction> GetExportedFunction(
......
......@@ -97,13 +97,9 @@ WasmInterpretationResult InterpretWasmModule(
Isolate* isolate, Handle<WasmInstanceObject> instance,
int32_t function_index, WasmValue* args);
// Interprets the exported wasm function "main". Returns a "failed" result if it
// was not possible to execute the function (e.g. because it does not exist), or
// if the interpretation does not finish after kMaxNumSteps. The arguments array
// is extended with default values if necessary.
WasmInterpretationResult InterpretWasmModuleForTesting(
Isolate* isolate, Handle<WasmInstanceObject> instance, size_t argc,
WasmValue* args);
// Generate an array of default arguments for the given signature.
std::unique_ptr<WasmValue[]> MakeDefaultArguments(Isolate* isolate,
const FunctionSig* sig);
// Install function map, module symbol for testing
void SetupIsolateForWasmModule(Isolate* isolate);
......
......@@ -32,27 +32,40 @@ void InterpretAndExecuteModule(i::Isolate* isolate,
// start function can contain an infinite loop which we cannot handle.
if (module_object->module()->start_function_index >= 0) return;
ErrorThrower thrower(isolate, "WebAssembly Instantiation");
HandleScope handle_scope(isolate); // Avoid leaking handles.
MaybeHandle<WasmInstanceObject> maybe_instance;
Handle<WasmInstanceObject> instance;
// Try to instantiate and interpret the module_object.
maybe_instance = isolate->wasm_engine()->SyncInstantiate(
isolate, &thrower, module_object,
Handle<JSReceiver>::null(), // imports
MaybeHandle<JSArrayBuffer>()); // memory
if (!maybe_instance.ToHandle(&instance)) {
isolate->clear_pending_exception();
thrower.Reset(); // Ignore errors.
// Try to instantiate, return if it fails.
{
ErrorThrower thrower(isolate, "WebAssembly Instantiation");
maybe_instance = isolate->wasm_engine()->SyncInstantiate(
isolate, &thrower, module_object,
Handle<JSReceiver>::null(), // imports
MaybeHandle<JSArrayBuffer>()); // memory
if (!maybe_instance.ToHandle(&instance)) {
isolate->clear_pending_exception();
thrower.Reset(); // Ignore errors.
return;
}
}
// Get the "main" exported function. Do nothing if it does not exist.
Handle<WasmExportedFunction> main_function;
if (!testing::GetExportedFunction(isolate, instance, "main")
.ToHandle(&main_function)) {
return;
}
std::unique_ptr<WasmValue[]> arguments =
testing::MakeDefaultArguments(isolate, main_function->sig());
// Now interpret.
testing::WasmInterpretationResult interpreter_result =
testing::InterpretWasmModuleForTesting(isolate, instance, 0, nullptr);
testing::InterpretWasmModule(
isolate, instance, main_function->function_index(), arguments.get());
if (interpreter_result.failed()) return;
// TODO(clemensb): Use this function in {WasmExecutionFuzzer::FuzzWasmModule},
// which currently duplicates the logic.
// The WebAssembly spec allows the sign bit of NaN to be non-deterministic.
// This sign bit can make the difference between an infinite loop and
// terminating code. With possible non-determinism we cannot guarantee that
......@@ -62,14 +75,17 @@ void InterpretAndExecuteModule(i::Isolate* isolate,
if (interpreter_result.possible_nondeterminism()) return;
// Try to instantiate and execute the module_object.
maybe_instance = isolate->wasm_engine()->SyncInstantiate(
isolate, &thrower, module_object,
Handle<JSReceiver>::null(), // imports
MaybeHandle<JSArrayBuffer>()); // memory
if (!maybe_instance.ToHandle(&instance)) {
isolate->clear_pending_exception();
thrower.Reset(); // Ignore errors.
return;
{
ErrorThrower thrower(isolate, "InterpretAndExecuteModule");
maybe_instance = isolate->wasm_engine()->SyncInstantiate(
isolate, &thrower, module_object,
Handle<JSReceiver>::null(), // imports
MaybeHandle<JSArrayBuffer>()); // memory
if (!maybe_instance.ToHandle(&instance)) {
isolate->clear_pending_exception();
thrower.Reset(); // Ignore errors.
return;
}
}
int32_t result_compiled = testing::CallWasmFunctionForTesting(
......@@ -367,58 +383,7 @@ void WasmExecutionFuzzer::FuzzWasmModule(Vector<const uint8_t> data,
if (!compiles) return;
MaybeHandle<WasmInstanceObject> interpreter_instance =
i_isolate->wasm_engine()->SyncInstantiate(
i_isolate, &interpreter_thrower, compiled_module.ToHandleChecked(),
MaybeHandle<JSReceiver>(), MaybeHandle<JSArrayBuffer>());
// Ignore instantiation failure.
if (interpreter_thrower.error()) return;
testing::WasmInterpretationResult interpreter_result =
testing::InterpretWasmModule(i_isolate,
interpreter_instance.ToHandleChecked(), 0,
interpreter_args.get());
// Do not execute the generated code if the interpreter did not finished after
// a bounded number of steps.
if (interpreter_result.failed()) return;
// The WebAssembly spec allows the sign bit of NaN to be non-deterministic.
// This sign bit can make the difference between an infinite loop and
// terminating code. With possible non-determinism we cannot guarantee that
// the generated code will not go into an infinite loop and cause a timeout in
// Clusterfuzz. Therefore we do not execute the generated code if the result
// may be non-deterministic.
if (interpreter_result.possible_nondeterminism()) return;
int32_t result_compiled;
{
ErrorThrower compiler_thrower(i_isolate, "Compile");
MaybeHandle<WasmInstanceObject> compiled_instance =
i_isolate->wasm_engine()->SyncInstantiate(
i_isolate, &compiler_thrower, compiled_module.ToHandleChecked(),
MaybeHandle<JSReceiver>(), MaybeHandle<JSArrayBuffer>());
DCHECK(!compiler_thrower.error());
result_compiled = testing::CallWasmFunctionForTesting(
i_isolate, compiled_instance.ToHandleChecked(), "main", num_args,
compiler_args.get());
}
if (interpreter_result.trapped() != i_isolate->has_pending_exception()) {
const char* exception_text[] = {"no exception", "exception"};
FATAL("interpreter: %s; compiled: %s",
exception_text[interpreter_result.trapped()],
exception_text[i_isolate->has_pending_exception()]);
}
if (!interpreter_result.trapped()) {
CHECK_EQ(interpreter_result.result(), result_compiled);
}
// Cleanup any pending exception.
i_isolate->clear_pending_exception();
InterpretAndExecuteModule(i_isolate, compiled_module.ToHandleChecked());
}
} // namespace fuzzer
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment