Commit ea08828b authored by Eric Holk's avatar Eric Holk Committed by Commit Bot

[wasm fuzzer] Require AST fuzzer modules to validate

The Wasm AST-based fuzzer is supposed to create valid modules by
construction. This change adds a CHECK to enforce this property.

Additionally, this change exposed several cases where we were not generating
valid modules before:
  * Block types did not match up correctly
  * Memory operations could have invalid alignments
  * Storing an i64 could generate an i32 argument incorrectly.
This CL includes fixes for these issues as well.

Bug: 
Change-Id: I1aef5532bc880367ec46dc6e79b2d4dbacf2f84b
Reviewed-on: https://chromium-review.googlesource.com/757129
Commit-Queue: Eric Holk <eholk@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49241}
parent a4d96612
...@@ -101,15 +101,51 @@ class WasmGenerator { ...@@ -101,15 +101,51 @@ class WasmGenerator {
const ValueType break_type = blocks_[target_block]; const ValueType break_type = blocks_[target_block];
Generate(break_type, data); Generate(break_type, data);
builder_->EmitWithI32V(kExprBr, target_block); builder_->EmitWithI32V(
kExprBr, static_cast<uint32_t>(blocks_.size()) - 1 - target_block);
builder_->Emit(kExprEnd); builder_->Emit(kExprEnd);
blocks_.pop_back(); blocks_.pop_back();
} }
// TODO(eholk): make this function constexpr once gcc supports it
static uint8_t max_alignment(WasmOpcode memop) {
switch (memop) {
case kExprI64LoadMem:
case kExprF64LoadMem:
case kExprI64StoreMem:
case kExprF64StoreMem:
return 3;
case kExprI32LoadMem:
case kExprI64LoadMem32S:
case kExprI64LoadMem32U:
case kExprF32LoadMem:
case kExprI32StoreMem:
case kExprI64StoreMem32:
case kExprF32StoreMem:
return 2;
case kExprI32LoadMem16S:
case kExprI32LoadMem16U:
case kExprI64LoadMem16S:
case kExprI64LoadMem16U:
case kExprI32StoreMem16:
case kExprI64StoreMem16:
return 1;
case kExprI32LoadMem8S:
case kExprI32LoadMem8U:
case kExprI64LoadMem8S:
case kExprI64LoadMem8U:
case kExprI32StoreMem8:
case kExprI64StoreMem8:
return 0;
default:
return 0;
}
}
template <WasmOpcode memory_op, ValueType... arg_types> template <WasmOpcode memory_op, ValueType... arg_types>
void memop(DataRange data) { void memop(DataRange data) {
const auto align = data.get<uint32_t>(); const uint8_t align = data.get<uint8_t>() % (max_alignment(memory_op) + 1);
const auto offset = data.get<uint32_t>(); const uint32_t offset = data.get<uint32_t>();
// Generate the index and the arguments, if any. // Generate the index and the arguments, if any.
Generate<kWasmI32, arg_types...>(data); Generate<kWasmI32, arg_types...>(data);
...@@ -435,7 +471,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer { ...@@ -435,7 +471,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
}; };
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
return WasmCompileFuzzer().FuzzWasmModule(data, size); constexpr bool require_valid = true;
return WasmCompileFuzzer().FuzzWasmModule(data, size, require_valid);
} }
} // namespace fuzzer } // namespace fuzzer
......
...@@ -91,8 +91,8 @@ void InterpretAndExecuteModule(i::Isolate* isolate, ...@@ -91,8 +91,8 @@ void InterpretAndExecuteModule(i::Isolate* isolate,
testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr); testing::RunWasmModuleForTesting(isolate, instance, 0, nullptr);
} }
int WasmExecutionFuzzer::FuzzWasmModule( int WasmExecutionFuzzer::FuzzWasmModule(const uint8_t* data, size_t size,
const uint8_t* data, size_t size) { bool require_valid) {
// Save the flag so that we can change it and restore it later. // Save the flag so that we can change it and restore it later.
bool generate_test = FLAG_wasm_code_fuzzer_gen_test; bool generate_test = FLAG_wasm_code_fuzzer_gen_test;
if (generate_test) { if (generate_test) {
...@@ -174,6 +174,7 @@ int WasmExecutionFuzzer::FuzzWasmModule( ...@@ -174,6 +174,7 @@ int WasmExecutionFuzzer::FuzzWasmModule(
bool validates = SyncValidate(i_isolate, wire_bytes); bool validates = SyncValidate(i_isolate, wire_bytes);
CHECK_EQ(compiles, validates); CHECK_EQ(compiles, validates);
CHECK_IMPLIES(require_valid, validates);
if (!compiles) return 0; if (!compiles) return 0;
......
...@@ -29,7 +29,8 @@ void InterpretAndExecuteModule(Isolate* isolate, ...@@ -29,7 +29,8 @@ void InterpretAndExecuteModule(Isolate* isolate,
class WasmExecutionFuzzer { class WasmExecutionFuzzer {
public: public:
virtual ~WasmExecutionFuzzer() {} virtual ~WasmExecutionFuzzer() {}
int FuzzWasmModule(const uint8_t* data, size_t size); int FuzzWasmModule(const uint8_t* data, size_t size,
bool require_valid = false);
protected: protected:
virtual bool GenerateModule( virtual bool GenerateModule(
......
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