57b14b0606
The wasm specification does not fully specify the binary representation of NaN: the sign bit can be non-deterministic. The wasm-code fuzzer found a test case where the wasm interpreter and the compiled code produce a different sign bit for a NaN, and as a consequence they produce different results. With this CL the interpreter tracks whether it executed an instruction which can produce a NaN, which are div and sqrt instructions. The fuzzer uses this information and compares the result of the interpreter with the result of the compiled code only if there was no instruction which could have produced a NaN. R=titzer@chromium.org TEST=cctest/test-run-wasm-interpreter/TestMayProduceNaN BUG=chromium:657481 Review-Url: https://chromiumcodereview.appspot.com/2438603003 Cr-Commit-Position: refs/heads/master@{#40474}
110 lines
3.9 KiB
C++
110 lines
3.9 KiB
C++
// Copyright 2016 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
#include "include/v8.h"
|
|
#include "src/isolate.h"
|
|
#include "src/objects.h"
|
|
#include "src/wasm/wasm-interpreter.h"
|
|
#include "src/wasm/wasm-module-builder.h"
|
|
#include "src/wasm/wasm-module.h"
|
|
#include "test/common/wasm/test-signatures.h"
|
|
#include "test/common/wasm/wasm-module-runner.h"
|
|
#include "test/fuzzer/fuzzer-support.h"
|
|
|
|
#define WASM_CODE_FUZZER_HASH_SEED 83
|
|
|
|
using namespace v8::internal::wasm;
|
|
|
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
|
v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get();
|
|
v8::Isolate* isolate = support->GetIsolate();
|
|
v8::internal::Isolate* i_isolate =
|
|
reinterpret_cast<v8::internal::Isolate*>(isolate);
|
|
|
|
// Clear any pending exceptions from a prior run.
|
|
if (i_isolate->has_pending_exception()) {
|
|
i_isolate->clear_pending_exception();
|
|
}
|
|
|
|
v8::Isolate::Scope isolate_scope(isolate);
|
|
v8::HandleScope handle_scope(isolate);
|
|
v8::Context::Scope context_scope(support->GetContext());
|
|
v8::TryCatch try_catch(isolate);
|
|
|
|
v8::internal::AccountingAllocator allocator;
|
|
v8::internal::Zone zone(&allocator, ZONE_NAME);
|
|
|
|
TestSignatures sigs;
|
|
|
|
WasmModuleBuilder builder(&zone);
|
|
|
|
v8::internal::wasm::WasmFunctionBuilder* f =
|
|
builder.AddFunction(sigs.i_iii());
|
|
f->EmitCode(data, static_cast<uint32_t>(size));
|
|
f->ExportAs(v8::internal::CStrVector("main"));
|
|
|
|
ZoneBuffer buffer(&zone);
|
|
builder.WriteTo(buffer);
|
|
|
|
v8::internal::wasm::testing::SetupIsolateForWasmModule(i_isolate);
|
|
|
|
v8::internal::HandleScope scope(i_isolate);
|
|
|
|
ErrorThrower interpreter_thrower(i_isolate, "Interpreter");
|
|
std::unique_ptr<const WasmModule> module(testing::DecodeWasmModuleForTesting(
|
|
i_isolate, &interpreter_thrower, buffer.begin(), buffer.end(),
|
|
v8::internal::wasm::ModuleOrigin::kWasmOrigin));
|
|
|
|
if (module == nullptr) {
|
|
return 0;
|
|
}
|
|
int32_t result_interpreted;
|
|
bool possible_nondeterminism = false;
|
|
{
|
|
WasmVal args[] = {WasmVal(1), WasmVal(2), WasmVal(3)};
|
|
result_interpreted = testing::InterpretWasmModule(
|
|
i_isolate, &interpreter_thrower, module.get(), 0, args,
|
|
&possible_nondeterminism);
|
|
}
|
|
|
|
ErrorThrower compiler_thrower(i_isolate, "Compiler");
|
|
v8::internal::Handle<v8::internal::JSObject> instance =
|
|
testing::InstantiateModuleForTesting(i_isolate, &compiler_thrower,
|
|
module.get());
|
|
|
|
if (!interpreter_thrower.error()) {
|
|
CHECK(!instance.is_null());
|
|
} else {
|
|
return 0;
|
|
}
|
|
int32_t result_compiled;
|
|
{
|
|
v8::internal::Handle<v8::internal::Object> arguments[] = {
|
|
v8::internal::handle(v8::internal::Smi::FromInt(1), i_isolate),
|
|
v8::internal::handle(v8::internal::Smi::FromInt(2), i_isolate),
|
|
v8::internal::handle(v8::internal::Smi::FromInt(3), i_isolate)};
|
|
result_compiled = testing::CallWasmFunctionForTesting(
|
|
i_isolate, instance, &compiler_thrower, "main", arraysize(arguments),
|
|
arguments, v8::internal::wasm::ModuleOrigin::kWasmOrigin);
|
|
}
|
|
if (result_interpreted == 0xdeadbeef) {
|
|
CHECK(i_isolate->has_pending_exception());
|
|
i_isolate->clear_pending_exception();
|
|
} else {
|
|
// The WebAssembly spec allows the sign bit of NaN to be non-deterministic.
|
|
// This sign bit may cause result_interpreted to be different than
|
|
// result_compiled. Therefore we do not check the equality of the results
|
|
// if the execution may have produced a NaN at some point.
|
|
if (!possible_nondeterminism && (result_interpreted != result_compiled)) {
|
|
V8_Fatal(__FILE__, __LINE__, "WasmCodeFuzzerHash=%x",
|
|
v8::internal::StringHasher::HashSequentialString(
|
|
data, static_cast<int>(size), WASM_CODE_FUZZER_HASH_SEED));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|