Commit 5da204c8 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] [fuzzer] Avoid reuse of input data

I just fixed an annoying bug where I accidentally used DataRange more
than once, leading to endless recursion.
This CL avoids that by forbidding copying of DataRange. Instead, it's
mostly passed by reference now.

R=ahaas@chromium.org
CC=eholk@chromium.org

Change-Id: I3925548951645d13823ff42d9d833bde76d6cca6
Reviewed-on: https://chromium-review.googlesource.com/839762
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50273}
parent 3ede3487
...@@ -37,21 +37,30 @@ class DataRange { ...@@ -37,21 +37,30 @@ class DataRange {
public: public:
DataRange(const uint8_t* data, size_t size) : data_(data), size_(size) {} DataRange(const uint8_t* data, size_t size) : data_(data), size_(size) {}
size_t size() const { return size_; } // Don't accidentally pass DataRange by value. This will reuse bytes and might
// lead to OOM because the end might not be reached.
std::pair<DataRange, DataRange> split(uint32_t index) const { // Define move constructor and move assignment, disallow copy constructor and
return std::make_pair(DataRange(data_, index), // copy assignment (below).
DataRange(data_ + index, size() - index)); DataRange(DataRange&& other) : DataRange(other.data_, other.size_) {
other.data_ = nullptr;
other.size_ = 0;
}
DataRange& operator=(DataRange&& other) {
data_ = other.data_;
size_ = other.size_;
other.data_ = nullptr;
other.size_ = 0;
return *this;
} }
std::pair<DataRange, DataRange> split() { size_t size() const { return size_; }
uint16_t index = get<uint16_t>();
if (size() > 0) { DataRange split() {
index = index % size(); uint16_t num_bytes = get<uint16_t>() % std::max(size_t{1}, size_);
} else { DataRange split(data_, num_bytes);
index = 0; data_ += num_bytes;
} size_ -= num_bytes;
return split(index); return split;
} }
template <typename T> template <typename T>
...@@ -72,9 +81,11 @@ class DataRange { ...@@ -72,9 +81,11 @@ class DataRange {
return result; return result;
} }
} }
DISALLOW_COPY_AND_ASSIGN(DataRange);
}; };
ValueType GetValueType(DataRange data) { ValueType GetValueType(DataRange& data) {
switch (data.get<uint8_t>() % 4) { switch (data.get<uint8_t>() % 4) {
case 0: case 0:
return kWasmI32; return kWasmI32;
...@@ -90,7 +101,7 @@ ValueType GetValueType(DataRange data) { ...@@ -90,7 +101,7 @@ ValueType GetValueType(DataRange data) {
class WasmGenerator { class WasmGenerator {
template <WasmOpcode Op, ValueType... Args> template <WasmOpcode Op, ValueType... Args>
void op(DataRange data) { void op(DataRange& data) {
Generate<Args...>(data); Generate<Args...>(data);
builder_->Emit(Op); builder_->Emit(Op);
} }
...@@ -115,20 +126,20 @@ class WasmGenerator { ...@@ -115,20 +126,20 @@ class WasmGenerator {
}; };
template <ValueType T> template <ValueType T>
void block(DataRange data) { void block(DataRange& data) {
BlockScope block_scope(this, kExprBlock, T, T); BlockScope block_scope(this, kExprBlock, T, T);
Generate<T>(data); Generate<T>(data);
} }
template <ValueType T> template <ValueType T>
void loop(DataRange data) { void loop(DataRange& data) {
// When breaking to a loop header, don't provide any input value (hence // When breaking to a loop header, don't provide any input value (hence
// kWasmStmt). // kWasmStmt).
BlockScope block_scope(this, kExprLoop, T, kWasmStmt); BlockScope block_scope(this, kExprLoop, T, kWasmStmt);
Generate<T>(data); Generate<T>(data);
} }
void br(DataRange data) { void br(DataRange& data) {
// There is always at least the block representing the function body. // There is always at least the block representing the function body.
DCHECK(!blocks_.empty()); DCHECK(!blocks_.empty());
const uint32_t target_block = data.get<uint32_t>() % blocks_.size(); const uint32_t target_block = data.get<uint32_t>() % blocks_.size();
...@@ -175,7 +186,7 @@ class WasmGenerator { ...@@ -175,7 +186,7 @@ class WasmGenerator {
} }
template <WasmOpcode memory_op, ValueType... arg_types> template <WasmOpcode memory_op, ValueType... arg_types>
void memop(DataRange data) { void memop(DataRange& data) {
const uint8_t align = data.get<uint8_t>() % (max_alignment(memory_op) + 1); const uint8_t align = data.get<uint8_t>() % (max_alignment(memory_op) + 1);
const uint32_t offset = data.get<uint32_t>(); const uint32_t offset = data.get<uint32_t>();
...@@ -187,26 +198,26 @@ class WasmGenerator { ...@@ -187,26 +198,26 @@ class WasmGenerator {
builder_->EmitU32V(offset); builder_->EmitU32V(offset);
} }
void drop(DataRange data) { void drop(DataRange& data) {
Generate(GetValueType(data), data); Generate(GetValueType(data), data);
builder_->Emit(kExprDrop); builder_->Emit(kExprDrop);
} }
template <ValueType T1, ValueType T2> template <ValueType T1, ValueType T2>
void sequence(DataRange data) { void sequence(DataRange& data) {
Generate<T1, T2>(data); Generate<T1, T2>(data);
} }
void current_memory(DataRange data) { void current_memory(DataRange& data) {
builder_->EmitWithU8(kExprMemorySize, 0); builder_->EmitWithU8(kExprMemorySize, 0);
} }
void grow_memory(DataRange data); void grow_memory(DataRange& data);
using generate_fn = void (WasmGenerator::*const)(DataRange); using generate_fn = void (WasmGenerator::*const)(DataRange&);
template <size_t N> template <size_t N>
void GenerateOneOf(generate_fn (&alternates)[N], DataRange data) { void GenerateOneOf(generate_fn (&alternates)[N], DataRange& data) {
static_assert(N < std::numeric_limits<uint8_t>::max(), static_assert(N < std::numeric_limits<uint8_t>::max(),
"Too many alternates. Replace with a bigger type if needed."); "Too many alternates. Replace with a bigger type if needed.");
const auto which = data.get<uint8_t>(); const auto which = data.get<uint8_t>();
...@@ -233,16 +244,17 @@ class WasmGenerator { ...@@ -233,16 +244,17 @@ class WasmGenerator {
blocks_.push_back(fn->signature()->GetReturn(0)); blocks_.push_back(fn->signature()->GetReturn(0));
} }
void Generate(ValueType type, DataRange data); void Generate(ValueType type, DataRange& data);
template <ValueType T> template <ValueType T>
void Generate(DataRange data); void Generate(DataRange& data);
template <ValueType T1, ValueType T2, ValueType... Ts> template <ValueType T1, ValueType T2, ValueType... Ts>
void Generate(DataRange data) { void Generate(DataRange& data) {
const auto parts = data.split(); // TODO(clemensh): Implement a more even split.
Generate<T1>(parts.first); auto first_data = data.split();
Generate<T2, Ts...>(parts.second); Generate<T1>(first_data);
Generate<T2, Ts...>(data);
} }
private: private:
...@@ -258,7 +270,7 @@ class WasmGenerator { ...@@ -258,7 +270,7 @@ class WasmGenerator {
}; };
template <> template <>
void WasmGenerator::Generate<kWasmStmt>(DataRange data) { void WasmGenerator::Generate<kWasmStmt>(DataRange& data) {
GeneratorRecursionScope rec_scope(this); GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() == 0) return; if (recursion_limit_reached() || data.size() == 0) return;
...@@ -283,7 +295,7 @@ void WasmGenerator::Generate<kWasmStmt>(DataRange data) { ...@@ -283,7 +295,7 @@ void WasmGenerator::Generate<kWasmStmt>(DataRange data) {
} }
template <> template <>
void WasmGenerator::Generate<kWasmI32>(DataRange data) { void WasmGenerator::Generate<kWasmI32>(DataRange& data) {
GeneratorRecursionScope rec_scope(this); GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() <= sizeof(uint32_t)) { if (recursion_limit_reached() || data.size() <= sizeof(uint32_t)) {
builder_->EmitI32Const(data.get<uint32_t>()); builder_->EmitI32Const(data.get<uint32_t>());
...@@ -364,7 +376,7 @@ void WasmGenerator::Generate<kWasmI32>(DataRange data) { ...@@ -364,7 +376,7 @@ void WasmGenerator::Generate<kWasmI32>(DataRange data) {
} }
template <> template <>
void WasmGenerator::Generate<kWasmI64>(DataRange data) { void WasmGenerator::Generate<kWasmI64>(DataRange& data) {
GeneratorRecursionScope rec_scope(this); GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() <= sizeof(uint64_t)) { if (recursion_limit_reached() || data.size() <= sizeof(uint64_t)) {
builder_->EmitI64Const(data.get<int64_t>()); builder_->EmitI64Const(data.get<int64_t>());
...@@ -411,7 +423,7 @@ void WasmGenerator::Generate<kWasmI64>(DataRange data) { ...@@ -411,7 +423,7 @@ void WasmGenerator::Generate<kWasmI64>(DataRange data) {
} }
template <> template <>
void WasmGenerator::Generate<kWasmF32>(DataRange data) { void WasmGenerator::Generate<kWasmF32>(DataRange& data) {
GeneratorRecursionScope rec_scope(this); GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() <= sizeof(float)) { if (recursion_limit_reached() || data.size() <= sizeof(float)) {
builder_->EmitF32Const(data.get<float>()); builder_->EmitF32Const(data.get<float>());
...@@ -434,7 +446,7 @@ void WasmGenerator::Generate<kWasmF32>(DataRange data) { ...@@ -434,7 +446,7 @@ void WasmGenerator::Generate<kWasmF32>(DataRange data) {
} }
template <> template <>
void WasmGenerator::Generate<kWasmF64>(DataRange data) { void WasmGenerator::Generate<kWasmF64>(DataRange& data) {
GeneratorRecursionScope rec_scope(this); GeneratorRecursionScope rec_scope(this);
if (recursion_limit_reached() || data.size() <= sizeof(double)) { if (recursion_limit_reached() || data.size() <= sizeof(double)) {
builder_->EmitF64Const(data.get<double>()); builder_->EmitF64Const(data.get<double>());
...@@ -456,12 +468,12 @@ void WasmGenerator::Generate<kWasmF64>(DataRange data) { ...@@ -456,12 +468,12 @@ void WasmGenerator::Generate<kWasmF64>(DataRange data) {
GenerateOneOf(alternates, data); GenerateOneOf(alternates, data);
} }
void WasmGenerator::grow_memory(DataRange data) { void WasmGenerator::grow_memory(DataRange& data) {
Generate<kWasmI32>(data); Generate<kWasmI32>(data);
builder_->EmitWithU8(kExprGrowMemory, 0); builder_->EmitWithU8(kExprGrowMemory, 0);
} }
void WasmGenerator::Generate(ValueType type, DataRange data) { void WasmGenerator::Generate(ValueType type, DataRange& data) {
switch (type) { switch (type) {
case kWasmStmt: case kWasmStmt:
return Generate<kWasmStmt>(data); return Generate<kWasmStmt>(data);
...@@ -492,7 +504,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer { ...@@ -492,7 +504,8 @@ class WasmCompileFuzzer : public WasmExecutionFuzzer {
WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii()); WasmFunctionBuilder* f = builder.AddFunction(sigs.i_iii());
WasmGenerator gen(f); WasmGenerator gen(f);
gen.Generate<kWasmI32>(DataRange(data, static_cast<uint32_t>(size))); DataRange range(data, static_cast<uint32_t>(size));
gen.Generate<kWasmI32>(range);
f->Emit(kExprEnd); f->Emit(kExprEnd);
builder.AddExport(CStrVector("main"), f); builder.AddExport(CStrVector("main"), f);
......
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