Commit 8d76f0e3 authored by titzer's avatar titzer Committed by Commit bot

[wasm] Enforce memory and table limits during instantiation.

R=rossberg@chromium.org
BUG=chromium:575167

Review-Url: https://codereview.chromium.org/2636173002
Cr-Commit-Position: refs/heads/master@{#42426}
parent cfa6ce32
...@@ -319,11 +319,10 @@ class ModuleDecoder : public Decoder { ...@@ -319,11 +319,10 @@ class ModuleDecoder : public Decoder {
} }
case kExternalMemory: { case kExternalMemory: {
// ===== Imported memory ========================================= // ===== Imported memory =========================================
bool has_max = false; consume_resizable_limits(
consume_resizable_limits("memory", "pages", kV8MaxWasmMemoryPages, "memory", "pages", kV8MaxWasmMemoryPages,
&module->min_mem_pages, &has_max, &module->min_mem_pages, &module->has_max_mem,
kSpecMaxWasmMemoryPages, kSpecMaxWasmMemoryPages, &module->max_mem_pages);
&module->max_mem_pages);
SetHasMemory(module); SetHasMemory(module);
break; break;
} }
...@@ -394,10 +393,10 @@ class ModuleDecoder : public Decoder { ...@@ -394,10 +393,10 @@ class ModuleDecoder : public Decoder {
uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories); uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories);
for (uint32_t i = 0; ok() && i < memory_count; i++) { for (uint32_t i = 0; ok() && i < memory_count; i++) {
bool has_max = false; consume_resizable_limits("memory", "pages", kV8MaxWasmMemoryPages,
consume_resizable_limits( &module->min_mem_pages, &module->has_max_mem,
"memory", "pages", kV8MaxWasmMemoryPages, &module->min_mem_pages, kSpecMaxWasmMemoryPages,
&has_max, kSpecMaxWasmMemoryPages, &module->max_mem_pages); &module->max_mem_pages);
} }
SetHasMemory(module); SetHasMemory(module);
section_iter.advance(); section_iter.advance();
......
...@@ -354,22 +354,22 @@ void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -354,22 +354,22 @@ void WebAssemblyInstantiate(const v8::FunctionCallbackInfo<v8::Value>& args) {
bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower, bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
Local<Context> context, Local<v8::Object> object, Local<Context> context, Local<v8::Object> object,
Local<String> property, int* result, int lower_bound, Local<String> property, int* result,
int upper_bound) { int64_t lower_bound, uint64_t upper_bound) {
v8::MaybeLocal<v8::Value> maybe = object->Get(context, property); v8::MaybeLocal<v8::Value> maybe = object->Get(context, property);
v8::Local<v8::Value> value; v8::Local<v8::Value> value;
if (maybe.ToLocal(&value)) { if (maybe.ToLocal(&value)) {
int64_t number; int64_t number;
if (!value->IntegerValue(context).To(&number)) return false; if (!value->IntegerValue(context).To(&number)) return false;
if (number < static_cast<int64_t>(lower_bound)) { if (number < lower_bound) {
thrower->RangeError("Property value %" PRId64 thrower->RangeError("Property value %" PRId64
" is below the lower bound %d", " is below the lower bound %" PRIx64,
number, lower_bound); number, lower_bound);
return false; return false;
} }
if (number > static_cast<int64_t>(upper_bound)) { if (number > static_cast<int64_t>(upper_bound)) {
thrower->RangeError("Property value %" PRId64 thrower->RangeError("Property value %" PRId64
" is above the upper bound %d", " is above the upper bound %" PRIu64,
number, upper_bound); number, upper_bound);
return false; return false;
} }
...@@ -379,8 +379,6 @@ bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower, ...@@ -379,8 +379,6 @@ bool GetIntegerProperty(v8::Isolate* isolate, ErrorThrower* thrower,
return false; return false;
} }
const int max_table_size = 1 << 26;
void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) { void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate(); v8::Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate); HandleScope scope(isolate);
...@@ -408,28 +406,23 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -408,28 +406,23 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
} }
} }
// The descriptor's 'initial'. // The descriptor's 'initial'.
int initial; int initial = 0;
if (!GetIntegerProperty(isolate, &thrower, context, descriptor, if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
v8_str(isolate, "initial"), &initial, 0, v8_str(isolate, "initial"), &initial, 0,
max_table_size)) { i::wasm::kV8MaxWasmTableSize)) {
return; return;
} }
// The descriptor's 'maximum'. // The descriptor's 'maximum'.
int maximum = 0; int maximum = -1;
Local<String> maximum_key = v8_str(isolate, "maximum"); Local<String> maximum_key = v8_str(isolate, "maximum");
Maybe<bool> has_maximum = descriptor->Has(context, maximum_key); Maybe<bool> has_maximum = descriptor->Has(context, maximum_key);
if (has_maximum.IsNothing()) { if (!has_maximum.IsNothing() && has_maximum.FromJust()) {
// There has been an exception, just return.
return;
}
if (has_maximum.FromJust()) {
if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key, if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key,
&maximum, initial, max_table_size)) { &maximum, initial,
i::wasm::kSpecMaxWasmTableSize)) {
return; return;
} }
} else {
maximum = static_cast<int>(i::wasm::kV8MaxWasmTableSize);
} }
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
...@@ -452,23 +445,21 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -452,23 +445,21 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
Local<Context> context = isolate->GetCurrentContext(); Local<Context> context = isolate->GetCurrentContext();
Local<v8::Object> descriptor = args[0]->ToObject(context).ToLocalChecked(); Local<v8::Object> descriptor = args[0]->ToObject(context).ToLocalChecked();
// The descriptor's 'initial'. // The descriptor's 'initial'.
int initial; int initial = 0;
if (!GetIntegerProperty(isolate, &thrower, context, descriptor, if (!GetIntegerProperty(isolate, &thrower, context, descriptor,
v8_str(isolate, "initial"), &initial, 0, 65536)) { v8_str(isolate, "initial"), &initial, 0,
i::wasm::kV8MaxWasmMemoryPages)) {
return; return;
} }
// The descriptor's 'maximum'. // The descriptor's 'maximum'.
int maximum = 0; int maximum = -1;
Local<String> maximum_key = v8_str(isolate, "maximum"); Local<String> maximum_key = v8_str(isolate, "maximum");
Maybe<bool> has_maximum = descriptor->Has(context, maximum_key); Maybe<bool> has_maximum = descriptor->Has(context, maximum_key);
if (has_maximum.IsNothing()) { if (!has_maximum.IsNothing() && has_maximum.FromJust()) {
// There has been an exception, just return.
return;
}
if (has_maximum.FromJust()) {
if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key, if (!GetIntegerProperty(isolate, &thrower, context, descriptor, maximum_key,
&maximum, initial, 65536)) { &maximum, initial,
i::wasm::kSpecMaxWasmMemoryPages)) {
return; return;
} }
} }
...@@ -481,8 +472,8 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -481,8 +472,8 @@ void WebAssemblyMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
thrower.RangeError("could not allocate memory"); thrower.RangeError("could not allocate memory");
return; return;
} }
i::Handle<i::JSObject> memory_obj = i::WasmMemoryObject::New( i::Handle<i::JSObject> memory_obj =
i_isolate, buffer, has_maximum.FromJust() ? maximum : -1); i::WasmMemoryObject::New(i_isolate, buffer, maximum);
args.GetReturnValue().Set(Utils::ToLocal(memory_obj)); args.GetReturnValue().Set(Utils::ToLocal(memory_obj));
} }
...@@ -523,7 +514,13 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) { ...@@ -523,7 +514,13 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
} }
new_size64 += old_size; new_size64 += old_size;
if (new_size64 < old_size || new_size64 > receiver->maximum_length()) { int64_t max_size64 = receiver->maximum_length();
if (max_size64 < 0 ||
max_size64 > static_cast<int64_t>(i::wasm::kV8MaxWasmTableSize)) {
max_size64 = i::wasm::kV8MaxWasmTableSize;
}
if (new_size64 < old_size || new_size64 > max_size64) {
v8::Local<v8::Value> e = v8::Exception::RangeError( v8::Local<v8::Value> e = v8::Exception::RangeError(
v8_str(isolate, new_size64 < old_size ? "trying to shrink table" v8_str(isolate, new_size64 < old_size ? "trying to shrink table"
: "maximum table size exceeded")); : "maximum table size exceeded"));
......
...@@ -31,6 +31,7 @@ const size_t kV8MaxWasmTables = 1; ...@@ -31,6 +31,7 @@ const size_t kV8MaxWasmTables = 1;
const size_t kV8MaxWasmMemories = 1; const size_t kV8MaxWasmMemories = 1;
const size_t kSpecMaxWasmMemoryPages = 65536; const size_t kSpecMaxWasmMemoryPages = 65536;
const size_t kSpecMaxWasmTableSize = 0xFFFFFFFFu;
const uint64_t kWasmMaxHeapOffset = const uint64_t kWasmMaxHeapOffset =
static_cast<uint64_t>( static_cast<uint64_t>(
......
...@@ -1669,16 +1669,34 @@ class WasmInstanceBuilder { ...@@ -1669,16 +1669,34 @@ class WasmInstanceBuilder {
table_instance.js_wrappers = Handle<FixedArray>( table_instance.js_wrappers = Handle<FixedArray>(
table_instance.table_object->functions(), isolate_); table_instance.table_object->functions(), isolate_);
// TODO(titzer): import table size must match exactly for now. int imported_cur_size = table_instance.js_wrappers->length();
int table_size = table_instance.js_wrappers->length(); if (imported_cur_size < static_cast<int>(table.min_size)) {
if (table_size != static_cast<int>(table.min_size)) {
thrower_->LinkError( thrower_->LinkError(
"table import %d is wrong size (%d), expected %u", index, "table import %d is smaller than minimum %d, got %u", index,
table_size, table.min_size); table.min_size, imported_cur_size);
return -1; return -1;
} }
if (table.has_max) {
int64_t imported_max_size =
table_instance.table_object->maximum_length();
if (imported_max_size < 0) {
thrower_->LinkError(
"table import %d has no maximum length, expected %d", index,
table.max_size);
return -1;
}
if (imported_max_size > table.max_size) {
thrower_->LinkError(
"table import %d has maximum larger than maximum %d, "
"got %" PRIx64,
index, table.max_size, imported_max_size);
return -1;
}
}
// Allocate a new dispatch table and signature table. // Allocate a new dispatch table and signature table.
int table_size = imported_cur_size;
table_instance.function_table = table_instance.function_table =
isolate_->factory()->NewFixedArray(table_size); isolate_->factory()->NewFixedArray(table_size);
table_instance.signature_table = table_instance.signature_table =
...@@ -1720,6 +1738,29 @@ class WasmInstanceBuilder { ...@@ -1720,6 +1738,29 @@ class WasmInstanceBuilder {
DCHECK(WasmJs::IsWasmMemoryObject(isolate_, memory)); DCHECK(WasmJs::IsWasmMemoryObject(isolate_, memory));
instance->set_memory_object(*memory); instance->set_memory_object(*memory);
memory_ = Handle<JSArrayBuffer>(memory->buffer(), isolate_); memory_ = Handle<JSArrayBuffer>(memory->buffer(), isolate_);
uint32_t imported_cur_pages = static_cast<uint32_t>(
memory_->byte_length()->Number() / WasmModule::kPageSize);
if (imported_cur_pages < module_->min_mem_pages) {
thrower_->LinkError(
"memory import %d is smaller than maximum %u, got %u", index,
module_->min_mem_pages, imported_cur_pages);
}
int32_t imported_max_pages = memory->maximum_pages();
if (module_->has_max_mem) {
if (imported_max_pages < 0) {
thrower_->LinkError(
"memory import %d has no maximum limit, expected at most %u",
index, imported_max_pages);
return -1;
}
if (static_cast<uint32_t>(imported_max_pages) >
module_->max_mem_pages) {
thrower_->LinkError(
"memory import %d has larger maximum than maximum %u, got %d",
index, module_->max_mem_pages, imported_max_pages);
return -1;
}
}
break; break;
} }
case kExternalGlobal: { case kExternalGlobal: {
...@@ -2212,13 +2253,14 @@ int32_t wasm::GetInstanceMemorySize(Isolate* isolate, ...@@ -2212,13 +2253,14 @@ int32_t wasm::GetInstanceMemorySize(Isolate* isolate,
} }
} }
uint32_t GetMaxInstanceMemorySize(Isolate* isolate, uint32_t GetMaxInstanceMemoryPages(Isolate* isolate,
Handle<WasmInstanceObject> instance) { Handle<WasmInstanceObject> instance) {
if (instance->has_memory_object()) { if (instance->has_memory_object()) {
Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate); Handle<WasmMemoryObject> memory_object(instance->memory_object(), isolate);
if (memory_object->has_maximum_pages()) {
int maximum = memory_object->maximum_pages(); uint32_t maximum = static_cast<uint32_t>(memory_object->maximum_pages());
if (maximum > 0) return static_cast<uint32_t>(maximum); if (maximum < kV8MaxWasmMemoryPages) return maximum;
}
} }
uint32_t compiled_max_pages = instance->compiled_module()->max_mem_pages(); uint32_t compiled_max_pages = instance->compiled_module()->max_mem_pages();
isolate->counters()->wasm_max_mem_pages_count()->AddSample( isolate->counters()->wasm_max_mem_pages_count()->AddSample(
...@@ -2294,7 +2336,7 @@ int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate, Handle<Object> receiver, ...@@ -2294,7 +2336,7 @@ int32_t wasm::GrowWebAssemblyMemory(Isolate* isolate, Handle<Object> receiver,
Handle<WasmInstanceObject> instance = instance_wrapper->instance_object(); Handle<WasmInstanceObject> instance = instance_wrapper->instance_object();
DCHECK(IsWasmInstance(*instance)); DCHECK(IsWasmInstance(*instance));
if (pages == 0) return GetInstanceMemorySize(isolate, instance); if (pages == 0) return GetInstanceMemorySize(isolate, instance);
uint32_t max_pages = GetMaxInstanceMemorySize(isolate, instance); uint32_t max_pages = GetMaxInstanceMemoryPages(isolate, instance);
// Grow memory object buffer and update instances associated with it. // Grow memory object buffer and update instances associated with it.
MaybeHandle<JSArrayBuffer> memory_buffer = handle(memory_object->buffer()); MaybeHandle<JSArrayBuffer> memory_buffer = handle(memory_object->buffer());
...@@ -2342,7 +2384,7 @@ int32_t wasm::GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance, ...@@ -2342,7 +2384,7 @@ int32_t wasm::GrowMemory(Isolate* isolate, Handle<WasmInstanceObject> instance,
old_size = old_buffer->byte_length()->Number(); old_size = old_buffer->byte_length()->Number();
old_mem_start = static_cast<Address>(old_buffer->backing_store()); old_mem_start = static_cast<Address>(old_buffer->backing_store());
} }
uint32_t max_pages = GetMaxInstanceMemorySize(isolate, instance_obj); uint32_t max_pages = GetMaxInstanceMemoryPages(isolate, instance_obj);
Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer> buffer =
GrowMemoryBuffer(isolate, instance_buffer, pages, max_pages); GrowMemoryBuffer(isolate, instance_buffer, pages, max_pages);
if (buffer.is_null()) return -1; if (buffer.is_null()) return -1;
......
...@@ -179,6 +179,7 @@ struct V8_EXPORT_PRIVATE WasmModule { ...@@ -179,6 +179,7 @@ struct V8_EXPORT_PRIVATE WasmModule {
Zone* owned_zone; Zone* owned_zone;
uint32_t min_mem_pages = 0; // minimum size of the memory in 64k pages uint32_t min_mem_pages = 0; // minimum size of the memory in 64k pages
uint32_t max_mem_pages = 0; // maximum size of the memory in 64k pages uint32_t max_mem_pages = 0; // maximum size of the memory in 64k pages
bool has_max_mem = false; // try if a maximum memory size exists
bool has_memory = false; // true if the memory was defined or imported bool has_memory = false; // true if the memory was defined or imported
bool mem_export = false; // true if the memory is exported bool mem_export = false; // true if the memory is exported
// TODO(wasm): reconcile start function index being an int with // TODO(wasm): reconcile start function index being an int with
......
...@@ -122,7 +122,7 @@ DEFINE_OBJ_GETTER(WasmModuleObject, compiled_module, kCompiledModule, ...@@ -122,7 +122,7 @@ DEFINE_OBJ_GETTER(WasmModuleObject, compiled_module, kCompiledModule,
WasmCompiledModule) WasmCompiledModule)
Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial, Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
uint32_t maximum, int64_t maximum,
Handle<FixedArray>* js_functions) { Handle<FixedArray>* js_functions) {
Handle<JSFunction> table_ctor( Handle<JSFunction> table_ctor(
isolate->native_context()->wasm_table_constructor()); isolate->native_context()->wasm_table_constructor());
...@@ -133,8 +133,8 @@ Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial, ...@@ -133,8 +133,8 @@ Handle<WasmTableObject> WasmTableObject::New(Isolate* isolate, uint32_t initial,
(*js_functions)->set(i, null); (*js_functions)->set(i, null);
} }
table_obj->SetInternalField(kFunctions, *(*js_functions)); table_obj->SetInternalField(kFunctions, *(*js_functions));
table_obj->SetInternalField(kMaximum, Handle<Object> max = isolate->factory()->NewNumber(maximum);
static_cast<Object*>(Smi::FromInt(maximum))); table_obj->SetInternalField(kMaximum, *max);
Handle<FixedArray> dispatch_tables = isolate->factory()->NewFixedArray(0); Handle<FixedArray> dispatch_tables = isolate->factory()->NewFixedArray(0);
table_obj->SetInternalField(kDispatchTables, *dispatch_tables); table_obj->SetInternalField(kDispatchTables, *dispatch_tables);
...@@ -176,8 +176,12 @@ DEFINE_OBJ_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray) ...@@ -176,8 +176,12 @@ DEFINE_OBJ_ACCESSORS(WasmTableObject, functions, kFunctions, FixedArray)
uint32_t WasmTableObject::current_length() { return functions()->length(); } uint32_t WasmTableObject::current_length() { return functions()->length(); }
uint32_t WasmTableObject::maximum_length() { bool WasmTableObject::has_maximum_length() {
return SafeUint32(GetInternalField(kMaximum)); return GetInternalField(kMaximum)->Number() >= 0;
}
int64_t WasmTableObject::maximum_length() {
return static_cast<int64_t>(GetInternalField(kMaximum)->Number());
} }
WasmTableObject* WasmTableObject::cast(Object* object) { WasmTableObject* WasmTableObject::cast(Object* object) {
...@@ -195,14 +199,14 @@ void WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table, ...@@ -195,14 +199,14 @@ void WasmTableObject::Grow(Isolate* isolate, Handle<WasmTableObject> table,
Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate, Handle<WasmMemoryObject> WasmMemoryObject::New(Isolate* isolate,
Handle<JSArrayBuffer> buffer, Handle<JSArrayBuffer> buffer,
int maximum) { int32_t maximum) {
Handle<JSFunction> memory_ctor( Handle<JSFunction> memory_ctor(
isolate->native_context()->wasm_memory_constructor()); isolate->native_context()->wasm_memory_constructor());
Handle<JSObject> memory_obj = Handle<JSObject> memory_obj =
isolate->factory()->NewJSObject(memory_ctor, TENURED); isolate->factory()->NewJSObject(memory_ctor, TENURED);
memory_obj->SetInternalField(kArrayBuffer, *buffer); memory_obj->SetInternalField(kArrayBuffer, *buffer);
memory_obj->SetInternalField(kMaximum, Handle<Object> max = isolate->factory()->NewNumber(maximum);
static_cast<Object*>(Smi::FromInt(maximum))); memory_obj->SetInternalField(kMaximum, *max);
Handle<Symbol> memory_sym(isolate->native_context()->wasm_memory_sym()); Handle<Symbol> memory_sym(isolate->native_context()->wasm_memory_sym());
Object::SetProperty(memory_obj, memory_sym, memory_obj, STRICT).Check(); Object::SetProperty(memory_obj, memory_sym, memory_obj, STRICT).Check();
return Handle<WasmMemoryObject>::cast(memory_obj); return Handle<WasmMemoryObject>::cast(memory_obj);
...@@ -216,8 +220,12 @@ uint32_t WasmMemoryObject::current_pages() { ...@@ -216,8 +220,12 @@ uint32_t WasmMemoryObject::current_pages() {
return SafeUint32(buffer()->byte_length()) / wasm::WasmModule::kPageSize; return SafeUint32(buffer()->byte_length()) / wasm::WasmModule::kPageSize;
} }
bool WasmMemoryObject::has_maximum_pages() {
return GetInternalField(kMaximum)->Number() >= 0;
}
int32_t WasmMemoryObject::maximum_pages() { int32_t WasmMemoryObject::maximum_pages() {
return SafeInt32(GetInternalField(kMaximum)); return static_cast<int32_t>(GetInternalField(kMaximum)->Number());
} }
WasmMemoryObject* WasmMemoryObject::cast(Object* object) { WasmMemoryObject* WasmMemoryObject::cast(Object* object) {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "src/objects-inl.h" #include "src/objects-inl.h"
#include "src/trap-handler/trap-handler.h" #include "src/trap-handler/trap-handler.h"
#include "src/wasm/managed.h" #include "src/wasm/managed.h"
#include "src/wasm/wasm-limits.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -60,10 +61,11 @@ class WasmTableObject : public JSObject { ...@@ -60,10 +61,11 @@ class WasmTableObject : public JSObject {
FixedArray* dispatch_tables(); FixedArray* dispatch_tables();
uint32_t current_length(); uint32_t current_length();
uint32_t maximum_length(); bool has_maximum_length();
int64_t maximum_length(); // Returns < 0 if no maximum.
static Handle<WasmTableObject> New(Isolate* isolate, uint32_t initial, static Handle<WasmTableObject> New(Isolate* isolate, uint32_t initial,
uint32_t maximum, int64_t maximum,
Handle<FixedArray>* js_functions); Handle<FixedArray>* js_functions);
static void Grow(Isolate* isolate, Handle<WasmTableObject> table, static void Grow(Isolate* isolate, Handle<WasmTableObject> table,
uint32_t count); uint32_t count);
...@@ -86,11 +88,12 @@ class WasmMemoryObject : public JSObject { ...@@ -86,11 +88,12 @@ class WasmMemoryObject : public JSObject {
void AddInstance(Isolate* isolate, Handle<WasmInstanceObject> object); void AddInstance(Isolate* isolate, Handle<WasmInstanceObject> object);
void ResetInstancesLink(Isolate* isolate); void ResetInstancesLink(Isolate* isolate);
uint32_t current_pages(); uint32_t current_pages();
int32_t maximum_pages(); // returns < 0 if there is no maximum bool has_maximum_pages();
int32_t maximum_pages(); // Returns < 0 if there is no maximum.
static Handle<WasmMemoryObject> New(Isolate* isolate, static Handle<WasmMemoryObject> New(Isolate* isolate,
Handle<JSArrayBuffer> buffer, Handle<JSArrayBuffer> buffer,
int maximum); int32_t maximum);
static bool Grow(Isolate* isolate, Handle<WasmMemoryObject> memory, static bool Grow(Isolate* isolate, Handle<WasmMemoryObject> memory,
uint32_t count); uint32_t count);
......
...@@ -9,7 +9,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -9,7 +9,7 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
(function SerializeAndDeserializeModule() { (function SerializeAndDeserializeModule() {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImportedMemory("", "memory", 1,1); builder.addImportedMemory("", "memory", 1);
var kSig_v_i = makeSig([kWasmI32], []); var kSig_v_i = makeSig([kWasmI32], []);
var signature = builder.addType(kSig_v_i); var signature = builder.addType(kSig_v_i);
builder.addImport("", "some_value", kSig_i_v); builder.addImport("", "some_value", kSig_i_v);
......
...@@ -382,3 +382,18 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -382,3 +382,18 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(3, instance.exports.mem_size()); assertEquals(3, instance.exports.mem_size());
assertEquals(3*kPageSize, instance.exports.exported_mem.buffer.byteLength); assertEquals(3*kPageSize, instance.exports.exported_mem.buffer.byteLength);
})(); })();
(function TestImportTooLarge() {
print("TestImportTooLarge");
let builder = new WasmModuleBuilder();
builder.addImportedMemory("m", "m", 1, 2);
// initial size is too large
assertThrows(() => builder.instantiate({m: {m: new WebAssembly.Memory({initial: 3, maximum: 3})}}));
// maximum size is too large
assertThrows(() => builder.instantiate({m: {m: new WebAssembly.Memory({initial: 1, maximum: 4})}}));
// no maximum
assertThrows(() => builder.instantiate({m: {m: new WebAssembly.Memory({initial: 1})}}));
})();
...@@ -199,7 +199,8 @@ function js_div(a, b) { return (a / b) | 0; } ...@@ -199,7 +199,8 @@ function js_div(a, b) { return (a / b) | 0; }
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
print(" base = " + i); print(" base = " + i);
let table = new WebAssembly.Table({element: "anyfunc", let table = new WebAssembly.Table({element: "anyfunc",
initial: kTableSize}); initial: kTableSize,
maximum: kTableSize});
assertEquals(10, table.length); assertEquals(10, table.length);
let i2 = new WebAssembly.Instance(m2, {q: {base: i, table: table, let i2 = new WebAssembly.Instance(m2, {q: {base: i, table: table,
js_div: js_div}}); js_div: js_div}});
...@@ -242,7 +243,8 @@ function js_div(a, b) { return (a / b) | 0; } ...@@ -242,7 +243,8 @@ function js_div(a, b) { return (a / b) | 0; }
print("CumulativeTest..."); print("CumulativeTest...");
let kTableSize = 10; let kTableSize = 10;
let table = new WebAssembly.Table({element: "anyfunc", initial: 10}); let table = new WebAssembly.Table(
{element: "anyfunc", initial: kTableSize, maximum: kTableSize});
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
...@@ -457,3 +459,22 @@ function js_div(a, b) { return (a / b) | 0; } ...@@ -457,3 +459,22 @@ function js_div(a, b) { return (a / b) | 0; }
} }
assertThrows(() => table.grow(11)); assertThrows(() => table.grow(11));
})(); })();
(function TestImportTooLarge() {
print("TestImportTooLarge...");
let builder = new WasmModuleBuilder();
builder.addImportedTable("t", "t", 1, 2);
// initial size is too large
assertThrows(() => builder.instantiate({t: {t: new WebAssembly.Table(
{element: "anyfunc", initial: 3, maximum: 3})}}));
// maximum size is too large
assertThrows(() => builder.instantiate({t: {t: new WebAssembly.Table(
{element: "anyfunc", initial: 1, maximum: 4})}}));
// no maximum
assertThrows(() => builder.instantiate({t: {t: new WebAssembly.Table(
{element: "anyfunc", initial: 1})}}));
})();
...@@ -126,7 +126,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -126,7 +126,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
(function InstancesAreIsolatedFromEachother() { (function InstancesAreIsolatedFromEachother() {
print("InstancesAreIsolatedFromEachother..."); print("InstancesAreIsolatedFromEachother...");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImportedMemory("", "memory", 1,1); builder.addImportedMemory("", "memory", 1);
var kSig_v_i = makeSig([kWasmI32], []); var kSig_v_i = makeSig([kWasmI32], []);
var signature = builder.addType(kSig_v_i); var signature = builder.addType(kSig_v_i);
builder.addImport("m", "some_value", kSig_i_v); builder.addImport("m", "some_value", kSig_i_v);
...@@ -207,7 +207,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88))); ...@@ -207,7 +207,7 @@ assertFalse(WebAssembly.validate(bytes(88, 88, 88, 88, 88, 88, 88, 88)));
(function InstanceMemoryIsIsolated() { (function InstanceMemoryIsIsolated() {
print("InstanceMemoryIsIsolated..."); print("InstanceMemoryIsIsolated...");
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImportedMemory("", "memory", 1,1); builder.addImportedMemory("", "memory", 1);
builder.addFunction("f", kSig_i_v) builder.addFunction("f", kSig_i_v)
.addBody([ .addBody([
......
...@@ -12,7 +12,7 @@ var kMemSize = 65536; ...@@ -12,7 +12,7 @@ var kMemSize = 65536;
function genModule(memory) { function genModule(memory) {
var builder = new WasmModuleBuilder(); var builder = new WasmModuleBuilder();
builder.addImportedMemory("", "memory", 1, 1); builder.addImportedMemory("", "memory", 1);
builder.exportMemoryAs("memory"); builder.exportMemoryAs("memory");
builder.addFunction("main", kSig_i_i) builder.addFunction("main", kSig_i_i)
.addBody([ .addBody([
......
...@@ -13,6 +13,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -13,6 +13,8 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
var outOfUint32RangeValue = 1e12; var outOfUint32RangeValue = 1e12;
var int32ButOob = 1073741824; var int32ButOob = 1073741824;
var kMaxUint32 = (4 * 1024 * 1024 * 1024) - 1;
var kV8MaxWasmTableSize = 10000000;
function assertTableIsValid(table) { function assertTableIsValid(table) {
assertSame(WebAssembly.Table.prototype, table.__proto__); assertSame(WebAssembly.Table.prototype, table.__proto__);
...@@ -41,14 +43,17 @@ function assertTableIsValid(table) { ...@@ -41,14 +43,17 @@ function assertTableIsValid(table) {
assertThrows(() => new WebAssembly.Table({element: 0, initial: 10}), TypeError); assertThrows(() => new WebAssembly.Table({element: 0, initial: 10}), TypeError);
assertThrows(() => new WebAssembly.Table({element: "any", initial: 10}), TypeError); assertThrows(() => new WebAssembly.Table({element: "any", initial: 10}), TypeError);
assertThrows(() => new WebAssembly.Table({element: "anyfunc", initial: -1}), RangeError); assertThrows(() => new WebAssembly.Table(
assertThrows(() => new WebAssembly.Table({element: "anyfunc", initial: outOfUint32RangeValue}), RangeError); {element: "anyfunc", initial: -1}), RangeError);
assertThrows(() => new WebAssembly.Table(
{element: "anyfunc", initial: outOfUint32RangeValue}), RangeError);
assertThrows(() => new WebAssembly.Table({element: "anyfunc", initial: 10, maximum: -1}), RangeError); assertThrows(() => new WebAssembly.Table(
assertThrows(() => new WebAssembly.Table({element: "anyfunc", initial: 10, maximum: outOfUint32RangeValue}), RangeError); {element: "anyfunc", initial: 10, maximum: -1}), RangeError);
assertThrows(() => new WebAssembly.Table({element: "anyfunc", initial: 10, maximum: 9}), RangeError); assertThrows(() => new WebAssembly.Table(
{element: "anyfunc", initial: 10, maximum: outOfUint32RangeValue}), RangeError);
assertThrows(() => new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: int32ButOob})); assertThrows(() => new WebAssembly.Table(
{element: "anyfunc", initial: 10, maximum: 9}), RangeError);
let table; let table;
table = new WebAssembly.Table({element: "anyfunc", initial: 1}); table = new WebAssembly.Table({element: "anyfunc", initial: 1});
...@@ -94,6 +99,14 @@ function assertTableIsValid(table) { ...@@ -94,6 +99,14 @@ function assertTableIsValid(table) {
table = new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: undefined}); table = new WebAssembly.Table({element: "anyfunc", initial: 0, maximum: undefined});
assertTableIsValid(table); assertTableIsValid(table);
assertEquals(0, table.length); assertEquals(0, table.length);
table = new WebAssembly.Table({element: "anyfunc", maximum: kMaxUint32});
assertTableIsValid(table);
assertEquals(0, table.length);
table = new WebAssembly.Table({element: "anyfunc", maximum: kV8MaxWasmTableSize + 1});
assertTableIsValid(table);
assertEquals(0, table.length);
})(); })();
(function TestMaximumIsReadOnce() { (function TestMaximumIsReadOnce() {
...@@ -260,4 +273,9 @@ function assertTableIsValid(table) { ...@@ -260,4 +273,9 @@ function assertTableIsValid(table) {
assertThrows(() => table.grow(-10), RangeError); assertThrows(() => table.grow(-10), RangeError);
assertThrows(() => WebAssembly.Table.prototype.grow.call([], 0), TypeError); assertThrows(() => WebAssembly.Table.prototype.grow.call([], 0), TypeError);
table = new WebAssembly.Table(
{element: "anyfunc", initial: 0, maximum: kV8MaxWasmTableSize});
table.grow(kV8MaxWasmTableSize);
assertThrows(() => table.grow(1), RangeError);
})(); })();
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