Commit 94266b7d authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Change the constant kV8MaxWasmMemoryPages to a command line flag.

The hardcoded constant caused a problem for the wasm fuzzer because
when the maximum memory was allocated in a test case, clusterfuzz ran
out of memory. with the command line flag we can set a lower limit
for the fuzzer.

The flag has the value of the constant as its default value, so that
for everything but the fuzzers nothing should change.

R=titzer@chromium.org
BUG=chromium:676888

Review-Url: https://codereview.chromium.org/2626313003
Cr-Commit-Position: refs/heads/master@{#42599}
parent 0d1e0a15
......@@ -1779,7 +1779,7 @@ Node* WasmGraphBuilder::GrowMemory(Node* input) {
Diamond check_input_range(
graph(), jsgraph()->common(),
graph()->NewNode(jsgraph()->machine()->Uint32LessThanOrEqual(), input,
jsgraph()->Uint32Constant(wasm::kV8MaxWasmMemoryPages)),
jsgraph()->Uint32Constant(FLAG_wasm_max_mem_pages)),
BranchHint::kTrue);
check_input_range.Chain(*control_);
......
......@@ -159,6 +159,7 @@ struct MaybeBoolFlag {
#define DEFINE_MAYBE_BOOL(nam, cmt) \
FLAG(MAYBE_BOOL, MaybeBoolFlag, nam, {false COMMA false}, cmt)
#define DEFINE_INT(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
#define DEFINE_UINT(nam, def, cmt) FLAG(UINT, unsigned int, nam, def, cmt)
#define DEFINE_FLOAT(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt)
#define DEFINE_STRING(nam, def, cmt) FLAG(STRING, const char*, nam, def, cmt)
#define DEFINE_ARGS(nam, cmt) FLAG(ARGS, JSArguments, nam, {0 COMMA NULL}, cmt)
......@@ -502,6 +503,7 @@ DEFINE_BOOL(wasm_disable_structured_cloning, false,
"disable WASM structured cloning")
DEFINE_INT(wasm_num_compilation_tasks, 10,
"number of parallel compilation tasks for wasm")
DEFINE_UINT(wasm_max_mem_pages, 16384, "maximum memory size of a wasm instance")
DEFINE_BOOL(trace_wasm_encoder, false, "trace encoding of wasm code")
DEFINE_BOOL(trace_wasm_decoder, false, "trace decoding of wasm code")
DEFINE_BOOL(trace_wasm_decode_time, false, "trace decoding time of wasm code")
......
......@@ -33,8 +33,15 @@ namespace {
// to the actual flag, default value, comment, etc. This is designed to be POD
// initialized as to avoid requiring static constructors.
struct Flag {
enum FlagType { TYPE_BOOL, TYPE_MAYBE_BOOL, TYPE_INT, TYPE_FLOAT,
TYPE_STRING, TYPE_ARGS };
enum FlagType {
TYPE_BOOL,
TYPE_MAYBE_BOOL,
TYPE_INT,
TYPE_UINT,
TYPE_FLOAT,
TYPE_STRING,
TYPE_ARGS
};
FlagType type_; // What type of flag, bool, int, or string.
const char* name_; // Name of the flag, ex "my_flag".
......@@ -64,6 +71,11 @@ struct Flag {
return reinterpret_cast<int*>(valptr_);
}
unsigned int* uint_variable() const {
DCHECK(type_ == TYPE_UINT);
return reinterpret_cast<unsigned int*>(valptr_);
}
double* float_variable() const {
DCHECK(type_ == TYPE_FLOAT);
return reinterpret_cast<double*>(valptr_);
......@@ -97,6 +109,11 @@ struct Flag {
return *reinterpret_cast<const int*>(defptr_);
}
unsigned int uint_default() const {
DCHECK(type_ == TYPE_UINT);
return *reinterpret_cast<const unsigned int*>(defptr_);
}
double float_default() const {
DCHECK(type_ == TYPE_FLOAT);
return *reinterpret_cast<const double*>(defptr_);
......@@ -121,6 +138,8 @@ struct Flag {
return maybe_bool_variable()->has_value == false;
case TYPE_INT:
return *int_variable() == int_default();
case TYPE_UINT:
return *uint_variable() == uint_default();
case TYPE_FLOAT:
return *float_variable() == float_default();
case TYPE_STRING: {
......@@ -149,6 +168,9 @@ struct Flag {
case TYPE_INT:
*int_variable() = int_default();
break;
case TYPE_UINT:
*uint_variable() = uint_default();
break;
case TYPE_FLOAT:
*float_variable() = float_default();
break;
......@@ -177,6 +199,8 @@ static const char* Type2String(Flag::FlagType type) {
case Flag::TYPE_BOOL: return "bool";
case Flag::TYPE_MAYBE_BOOL: return "maybe_bool";
case Flag::TYPE_INT: return "int";
case Flag::TYPE_UINT:
return "uint";
case Flag::TYPE_FLOAT: return "float";
case Flag::TYPE_STRING: return "string";
case Flag::TYPE_ARGS: return "arguments";
......@@ -199,6 +223,9 @@ std::ostream& operator<<(std::ostream& os, const Flag& flag) { // NOLINT
case Flag::TYPE_INT:
os << *flag.int_variable();
break;
case Flag::TYPE_UINT:
os << *flag.uint_variable();
break;
case Flag::TYPE_FLOAT:
os << *flag.float_variable();
break;
......@@ -399,6 +426,24 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
case Flag::TYPE_INT:
*flag->int_variable() = static_cast<int>(strtol(value, &endp, 10));
break;
case Flag::TYPE_UINT: {
// We do not use strtoul because it accepts negative numbers.
int64_t val = static_cast<int64_t>(strtoll(value, &endp, 10));
if (val < 0 || val > std::numeric_limits<unsigned int>::max()) {
PrintF(stderr,
"Error: Value for flag %s of type %s is out of bounds "
"[0-%" PRIu64
"]\n"
"Try --help for options\n",
arg, Type2String(flag->type()),
static_cast<uint64_t>(
std::numeric_limits<unsigned int>::max()));
return_code = j;
break;
}
*flag->uint_variable() = static_cast<unsigned int>(val);
break;
}
case Flag::TYPE_FLOAT:
*flag->float_variable() = strtod(value, &endp);
break;
......
......@@ -322,7 +322,7 @@ class ModuleDecoder : public Decoder {
// ===== Imported memory =========================================
if (!AddMemory(module)) break;
consume_resizable_limits(
"memory", "pages", kV8MaxWasmMemoryPages,
"memory", "pages", FLAG_wasm_max_mem_pages,
&module->min_mem_pages, &module->has_max_mem,
kSpecMaxWasmMemoryPages, &module->max_mem_pages);
break;
......@@ -394,7 +394,7 @@ class ModuleDecoder : public Decoder {
for (uint32_t i = 0; ok() && i < memory_count; i++) {
if (!AddMemory(module)) break;
consume_resizable_limits("memory", "pages", kV8MaxWasmMemoryPages,
consume_resizable_limits("memory", "pages", FLAG_wasm_max_mem_pages,
&module->min_mem_pages, &module->has_max_mem,
kSpecMaxWasmMemoryPages,
&module->max_mem_pages);
......
......@@ -616,7 +616,7 @@ static inline int32_t ExecuteGrowMemory(uint32_t delta_pages,
WasmInstance* instance) {
// TODO(ahaas): Move memory allocation to wasm-module.cc for better
// encapsulation.
if (delta_pages > wasm::kV8MaxWasmMemoryPages ||
if (delta_pages > FLAG_wasm_max_mem_pages ||
delta_pages > instance->module->max_mem_pages) {
return -1;
}
......@@ -633,7 +633,7 @@ static inline int32_t ExecuteGrowMemory(uint32_t delta_pages,
} else {
DCHECK_NOT_NULL(instance->mem_start);
new_size = old_size + delta_pages * wasm::WasmModule::kPageSize;
if (new_size / wasm::WasmModule::kPageSize > wasm::kV8MaxWasmMemoryPages ||
if (new_size / wasm::WasmModule::kPageSize > FLAG_wasm_max_mem_pages ||
new_size / wasm::WasmModule::kPageSize >
instance->module->max_mem_pages) {
return -1;
......
......@@ -499,7 +499,7 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
int initial = 0;
if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
v8_str(isolate, "initial"), &initial, 0,
i::wasm::kV8MaxWasmMemoryPages)) {
i::FLAG_wasm_max_mem_pages)) {
return;
}
// The descriptor's 'maximum'.
......@@ -697,8 +697,8 @@ void WebAssemblyMemoryGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
i::Handle<i::WasmMemoryObject>::cast(Utils::OpenHandle(*args.This()));
int64_t max_size64 = receiver->maximum_pages();
if (max_size64 < 0 ||
max_size64 > static_cast<int64_t>(i::wasm::kV8MaxWasmMemoryPages)) {
max_size64 = i::wasm::kV8MaxWasmMemoryPages;
max_size64 > static_cast<int64_t>(i::FLAG_wasm_max_mem_pages)) {
max_size64 = i::FLAG_wasm_max_mem_pages;
}
i::Handle<i::JSArrayBuffer> old_buffer(receiver->buffer());
uint32_t old_size =
......
......@@ -17,7 +17,8 @@ const size_t kV8MaxWasmImports = 100000;
const size_t kV8MaxWasmExports = 100000;
const size_t kV8MaxWasmGlobals = 1000000;
const size_t kV8MaxWasmDataSegments = 100000;
const size_t kV8MaxWasmMemoryPages = 16384; // = 1 GiB
// kV8MaxWasmMemoryPages is defined by FLAG_wasm_max_mem_pages
// const size_t kV8MaxWasmMemoryPages = 16384; // = 1 GiB
const size_t kV8MaxWasmStringSize = 100000;
const size_t kV8MaxWasmModuleSize = 1024 * 1024 * 1024; // = 1 GiB
const size_t kV8MaxWasmFunctionSize = 128 * 1024;
......
......@@ -755,7 +755,7 @@ Handle<Script> CreateWasmScript(Isolate* isolate,
Handle<JSArrayBuffer> wasm::NewArrayBuffer(Isolate* isolate, size_t size,
bool enable_guard_regions) {
if (size > (kV8MaxWasmMemoryPages * WasmModule::kPageSize)) {
if (size > (FLAG_wasm_max_mem_pages * WasmModule::kPageSize)) {
// TODO(titzer): lift restriction on maximum memory allocated here.
return Handle<JSArrayBuffer>::null();
}
......@@ -1834,7 +1834,7 @@ class WasmInstanceBuilder {
// Allocate memory for a module instance as a new JSArrayBuffer.
Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages) {
if (min_mem_pages > kV8MaxWasmMemoryPages) {
if (min_mem_pages > FLAG_wasm_max_mem_pages) {
thrower_->RangeError("Out of memory: wasm memory too large");
return Handle<JSArrayBuffer>::null();
}
......@@ -2276,14 +2276,14 @@ uint32_t GetMaxInstanceMemoryPages(Isolate* isolate,
Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate);
if (memory_object->has_maximum_pages()) {
uint32_t maximum = static_cast<uint32_t>(memory_object->maximum_pages());
if (maximum < kV8MaxWasmMemoryPages) return maximum;
if (maximum < FLAG_wasm_max_mem_pages) return maximum;
}
}
uint32_t compiled_max_pages = instance->compiled_module()->max_mem_pages();
isolate->counters()->wasm_max_mem_pages_count()->AddSample(
compiled_max_pages);
if (compiled_max_pages != 0) return compiled_max_pages;
return kV8MaxWasmMemoryPages;
return FLAG_wasm_max_mem_pages;
}
Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
......@@ -2301,7 +2301,7 @@ Handle<JSArrayBuffer> GrowMemoryBuffer(Isolate* isolate,
std::numeric_limits<uint32_t>::max());
uint32_t new_size = old_size + pages * WasmModule::kPageSize;
if (new_size <= old_size || max_pages * WasmModule::kPageSize < new_size ||
kV8MaxWasmMemoryPages * WasmModule::kPageSize < new_size) {
FLAG_wasm_max_mem_pages * WasmModule::kPageSize < new_size) {
return Handle<JSArrayBuffer>::null();
}
......@@ -2368,9 +2368,9 @@ int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate,
uint32_t max_pages;
if (memory_object->has_maximum_pages()) {
max_pages = static_cast<uint32_t>(memory_object->maximum_pages());
if (kV8MaxWasmMemoryPages < max_pages) return -1;
if (FLAG_wasm_max_mem_pages < max_pages) return -1;
} else {
max_pages = kV8MaxWasmMemoryPages;
max_pages = FLAG_wasm_max_mem_pages;
}
new_buffer = GrowMemoryBuffer(isolate, memory_buffer, pages, max_pages);
if (new_buffer.is_null()) return -1;
......
......@@ -17,6 +17,8 @@
#include "test/fuzzer/fuzzer-support.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
unsigned int flag_value = v8::internal::FLAG_wasm_max_mem_pages;
v8::internal::FLAG_wasm_max_mem_pages = 32;
v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get();
v8::Isolate* isolate = support->GetIsolate();
v8::internal::Isolate* i_isolate =
......@@ -35,5 +37,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
v8::internal::wasm::testing::CompileAndRunWasmModule(
i_isolate, data, data + size,
v8::internal::wasm::ModuleOrigin::kAsmJsOrigin);
v8::internal::FLAG_wasm_max_mem_pages = flag_value;
return 0;
}
......@@ -17,6 +17,8 @@
#include "test/fuzzer/fuzzer-support.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
unsigned int flag_value = v8::internal::FLAG_wasm_max_mem_pages;
v8::internal::FLAG_wasm_max_mem_pages = 32;
v8_fuzzer::FuzzerSupport* support = v8_fuzzer::FuzzerSupport::Get();
v8::Isolate* isolate = support->GetIsolate();
v8::internal::Isolate* i_isolate =
......@@ -34,5 +36,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
v8::internal::wasm::testing::SetupIsolateForWasmModule(i_isolate);
v8::internal::wasm::testing::CompileAndRunWasmModule(
i_isolate, data, data + size, v8::internal::wasm::kWasmOrigin);
v8::internal::FLAG_wasm_max_mem_pages = flag_value;
return 0;
}
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