Commit 0725ff15 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Make signature map move-only

Signature maps should only be updated, but never copied. We had a bug
because we accidentally updated a copy of the map. This refactoring
prevents any such bugs in the future, and fixes more occurences where
we accidentally copied structs containing a signature map (the move-only
constraint also extends to all structs containing a signature map).

Drive-by: Make InstanceBuilder::NeedsWrappers const.

R=titzer@chromium.org

Bug: chromium:741750
Change-Id: Id919203d8c4078e608a1163e5c790c97d06a9753
Reviewed-on: https://chromium-review.googlesource.com/571791Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46728}
parent 989d7b96
...@@ -1524,12 +1524,12 @@ Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(uint32_t min_mem_pages) { ...@@ -1524,12 +1524,12 @@ Handle<JSArrayBuffer> InstanceBuilder::AllocateMemory(uint32_t min_mem_pages) {
return mem_buffer; return mem_buffer;
} }
bool InstanceBuilder::NeedsWrappers() { bool InstanceBuilder::NeedsWrappers() const {
if (module_->num_exported_functions > 0) return true; if (module_->num_exported_functions > 0) return true;
for (auto table_instance : table_instances_) { for (auto& table_instance : table_instances_) {
if (!table_instance.js_wrappers.is_null()) return true; if (!table_instance.js_wrappers.is_null()) return true;
} }
for (auto table : module_->function_tables) { for (auto& table : module_->function_tables) {
if (table.exported) return true; if (table.exported) return true;
} }
return false; return false;
...@@ -1801,10 +1801,10 @@ void InstanceBuilder::LoadTableSegments(Handle<FixedArray> code_table, ...@@ -1801,10 +1801,10 @@ void InstanceBuilder::LoadTableSegments(Handle<FixedArray> code_table,
// since initializations are not sorted by table index. // since initializations are not sorted by table index.
for (auto table_init : module_->table_inits) { for (auto table_init : module_->table_inits) {
uint32_t base = EvalUint32InitExpr(table_init.offset); uint32_t base = EvalUint32InitExpr(table_init.offset);
DCHECK(in_bounds(base, static_cast<uint32_t>(table_init.entries.size()), uint32_t num_entries = static_cast<uint32_t>(table_init.entries.size());
DCHECK(in_bounds(base, num_entries,
table_instance.function_table->length())); table_instance.function_table->length()));
for (int i = 0, e = static_cast<int>(table_init.entries.size()); i < e; for (uint32_t i = 0; i < num_entries; ++i) {
++i) {
uint32_t func_index = table_init.entries[i]; uint32_t func_index = table_init.entries[i];
WasmFunction* function = &module_->functions[func_index]; WasmFunction* function = &module_->functions[func_index];
int table_index = static_cast<int>(i + base); int table_index = static_cast<int>(i + base);
......
...@@ -289,7 +289,7 @@ class InstanceBuilder { ...@@ -289,7 +289,7 @@ class InstanceBuilder {
// Allocate memory for a module instance as a new JSArrayBuffer. // Allocate memory for a module instance as a new JSArrayBuffer.
Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages); Handle<JSArrayBuffer> AllocateMemory(uint32_t min_mem_pages);
bool NeedsWrappers(); bool NeedsWrappers() const;
// Process the exports, creating wrappers for functions, tables, memories, // Process the exports, creating wrappers for functions, tables, memories,
// and globals. // and globals.
......
...@@ -444,11 +444,10 @@ class ModuleDecoder : public Decoder { ...@@ -444,11 +444,10 @@ class ModuleDecoder : public Decoder {
if (!AddTable(module_.get())) break; if (!AddTable(module_.get())) break;
import->index = import->index =
static_cast<uint32_t>(module_->function_tables.size()); static_cast<uint32_t>(module_->function_tables.size());
module_->function_tables.push_back({0, 0, false, module_->function_tables.emplace_back();
std::vector<int32_t>(), true,
false, SignatureMap()});
expect_u8("element type", kWasmAnyFunctionTypeForm);
WasmIndirectFunctionTable* table = &module_->function_tables.back(); WasmIndirectFunctionTable* table = &module_->function_tables.back();
table->imported = true;
expect_u8("element type", kWasmAnyFunctionTypeForm);
consume_resizable_limits("element count", "elements", consume_resizable_limits("element count", "elements",
FLAG_wasm_max_table_size, &table->min_size, FLAG_wasm_max_table_size, &table->min_size,
&table->has_max, FLAG_wasm_max_table_size, &table->has_max, FLAG_wasm_max_table_size,
...@@ -508,8 +507,7 @@ class ModuleDecoder : public Decoder { ...@@ -508,8 +507,7 @@ class ModuleDecoder : public Decoder {
for (uint32_t i = 0; ok() && i < table_count; i++) { for (uint32_t i = 0; ok() && i < table_count; i++) {
if (!AddTable(module_.get())) break; if (!AddTable(module_.get())) break;
module_->function_tables.push_back( module_->function_tables.emplace_back();
{0, 0, false, std::vector<int32_t>(), false, false, SignatureMap()});
WasmIndirectFunctionTable* table = &module_->function_tables.back(); WasmIndirectFunctionTable* table = &module_->function_tables.back();
expect_u8("table type", kWasmAnyFunctionTypeForm); expect_u8("table type", kWasmAnyFunctionTypeForm);
consume_resizable_limits("table elements", "elements", consume_resizable_limits("table elements", "elements",
......
...@@ -19,6 +19,12 @@ namespace wasm { ...@@ -19,6 +19,12 @@ namespace wasm {
// same index. // same index.
class V8_EXPORT_PRIVATE SignatureMap { class V8_EXPORT_PRIVATE SignatureMap {
public: public:
// Allow default construction and move construction (because we have vectors
// of objects containing SignatureMaps), but disallow copy or assign. It's
// too easy to get security bugs by accidentally updating a copy of the map.
SignatureMap() = default;
SignatureMap(SignatureMap&&) = default;
// Gets the index for a signature, assigning a new index if necessary. // Gets the index for a signature, assigning a new index if necessary.
uint32_t FindOrInsert(FunctionSig* sig); uint32_t FindOrInsert(FunctionSig* sig);
...@@ -32,6 +38,8 @@ class V8_EXPORT_PRIVATE SignatureMap { ...@@ -32,6 +38,8 @@ class V8_EXPORT_PRIVATE SignatureMap {
}; };
uint32_t next_ = 0; uint32_t next_ = 0;
std::map<FunctionSig*, uint32_t, CompareFunctionSigs> map_; std::map<FunctionSig*, uint32_t, CompareFunctionSigs> map_;
DISALLOW_COPY_AND_ASSIGN(SignatureMap);
}; };
} // namespace wasm } // namespace wasm
......
...@@ -134,13 +134,13 @@ struct WasmDataSegment { ...@@ -134,13 +134,13 @@ struct WasmDataSegment {
// Static representation of a wasm indirect call table. // Static representation of a wasm indirect call table.
struct WasmIndirectFunctionTable { struct WasmIndirectFunctionTable {
uint32_t min_size; // minimum table size. uint32_t min_size = 0; // minimum table size.
uint32_t max_size; // maximum table size. uint32_t max_size = 0; // maximum table size.
bool has_max; // true if there is a maximum size. bool has_max = false; // true if there is a maximum size.
// TODO(titzer): Move this to WasmInstance. Needed by interpreter only. // TODO(titzer): Move this to WasmInstance. Needed by interpreter only.
std::vector<int32_t> values; // function table, -1 indicating invalid. std::vector<int32_t> values; // function table, -1 indicating invalid.
bool imported; // true if imported. bool imported = false; // true if imported.
bool exported; // true if exported. bool exported = false; // true if exported.
SignatureMap map; // canonicalizing map for sig indexes. SignatureMap map; // canonicalizing map for sig indexes.
}; };
......
...@@ -251,12 +251,11 @@ class TestingModule : public ModuleEnv { ...@@ -251,12 +251,11 @@ class TestingModule : public ModuleEnv {
void AddIndirectFunctionTable(uint16_t* function_indexes, void AddIndirectFunctionTable(uint16_t* function_indexes,
uint32_t table_size) { uint32_t table_size) {
module_.function_tables.push_back({table_size, table_size, true, module_.function_tables.emplace_back();
std::vector<int32_t>(), false, false,
SignatureMap()});
WasmIndirectFunctionTable& table = module_.function_tables.back(); WasmIndirectFunctionTable& table = module_.function_tables.back();
table.min_size = table_size; table.min_size = table_size;
table.max_size = table_size; table.max_size = table_size;
table.has_max = true;
for (uint32_t i = 0; i < table_size; ++i) { for (uint32_t i = 0; i < table_size; ++i) {
table.values.push_back(function_indexes[i]); table.values.push_back(function_indexes[i]);
table.map.FindOrInsert(module_.functions[function_indexes[i]].sig); table.map.FindOrInsert(module_.functions[function_indexes[i]].sig);
......
...@@ -227,10 +227,7 @@ class TestModuleEnv : public ModuleEnv { ...@@ -227,10 +227,7 @@ class TestModuleEnv : public ModuleEnv {
mod.max_mem_pages = 100; mod.max_mem_pages = 100;
} }
void InitializeFunctionTable() { void InitializeFunctionTable() { mod.function_tables.emplace_back(); }
mod.function_tables.push_back(
{0, 0, true, std::vector<int32_t>(), false, false, SignatureMap()});
}
private: private:
WasmModule mod; WasmModule mod;
......
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