diff options
author | Sam Clegg <sbc@chromium.org> | 2020-01-09 11:36:21 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-09 11:36:21 -0800 |
commit | 415c3bb1b70c5edc9beb3a7e2cea5d9247e1e52c (patch) | |
tree | 5cf869855722fce5f88e11c0968007d8f37109f8 /src/interp/interp.cc | |
parent | 7de6d8eedd550a9001a2db9d9e04b7ad941c9be7 (diff) | |
download | wabt-415c3bb1b70c5edc9beb3a7e2cea5d9247e1e52c.tar.gz wabt-415c3bb1b70c5edc9beb3a7e2cea5d9247e1e52c.tar.bz2 wabt-415c3bb1b70c5edc9beb3a7e2cea5d9247e1e52c.zip |
Update testsuite (#1275)
The two primary changes involved are:
1. Removal of `assert_return_canonical_nan`/`arithetic nan` in favor of
special `nan:canonical`/`nan:arithmetic` constants that can only be
used in test expectations.
See: https://github.com/WebAssembly/spec/pull/1104
2. New trapping behaviour for bulk memory operations. Range checks are
now performed up front for opterations such as memory.fill and
memory.copy.
See: https://github.com/webassembly/bulk-memory-operations/issues/111
And: https://github.com/webassembly/bulk-memory-operations/pull/123
The old behaviour is still kept around to support table.fill which
is defined in reference-types proposal and has yet to be updated.
Diffstat (limited to 'src/interp/interp.cc')
-rw-r--r-- | src/interp/interp.cc | 99 |
1 files changed, 51 insertions, 48 deletions
diff --git a/src/interp/interp.cc b/src/interp/interp.cc index a3d621e7..61e9d98b 100644 --- a/src/interp/interp.cc +++ b/src/interp/interp.cc @@ -1018,7 +1018,11 @@ Result Thread::AtomicRmwCmpxchg(const uint8_t** pc) { return Push<ResultValueType>(static_cast<ExtendedType>(read)); } -bool ClampToBounds(uint32_t start, uint32_t* length, uint32_t max) { +// This function is used to clanp the bound for table.fill operations. This +// can be removed once the behaviour of table.fill is updated to match the +// new bulk meory semantics, which is to trap early on OOB. +// See: https://github.com/webassembly/bulk-memory-operations/issues/111 +static bool ClampToBounds(uint32_t start, uint32_t* length, uint32_t max) { if (start > max) { *length = 0; return false; @@ -1031,6 +1035,14 @@ bool ClampToBounds(uint32_t start, uint32_t* length, uint32_t max) { return true; } +static bool CheckBounds(uint32_t start, uint32_t length, uint32_t max) { + if (start > max) { + return false; + } + uint32_t avail = max - start; + return length <= avail; +} + Result Thread::MemoryInit(const uint8_t** pc) { Memory* memory = ReadMemory(pc); DataSegment* segment = ReadDataSegment(pc); @@ -1039,13 +1051,12 @@ Result Thread::MemoryInit(const uint8_t** pc) { uint32_t size = Pop<uint32_t>(); uint32_t src = Pop<uint32_t>(); uint32_t dst = Pop<uint32_t>(); + bool ok = CheckBounds(dst, size, memory_size); + ok &= CheckBounds(src, size, segment_size); + if (!ok) { + TRAP_MSG(MemoryAccessOutOfBounds, "memory.init out of bounds"); + } if (size > 0) { - TRAP_IF(segment->dropped, DataSegmentDropped); - bool ok = ClampToBounds(dst, &size, memory_size); - ok &= ClampToBounds(src, &size, segment_size); - if (!ok) { - TRAP_MSG(MemoryAccessOutOfBounds, "memory.init out of bounds"); - } memcpy(memory->data.data() + dst, segment->data.data() + src, size); } return ResultType::Ok; @@ -1053,8 +1064,7 @@ Result Thread::MemoryInit(const uint8_t** pc) { Result Thread::DataDrop(const uint8_t** pc) { DataSegment* segment = ReadDataSegment(pc); - TRAP_IF(segment->dropped, DataSegmentDropped); - segment->dropped = true; + segment->data.clear(); return ResultType::Ok; } @@ -1064,12 +1074,12 @@ Result Thread::MemoryCopy(const uint8_t** pc) { uint32_t size = Pop<uint32_t>(); uint32_t src = Pop<uint32_t>(); uint32_t dst = Pop<uint32_t>(); + bool ok = CheckBounds(dst, size, memory_size); + ok &= CheckBounds(src, size, memory_size); + if (!ok) { + TRAP_MSG(MemoryAccessOutOfBounds, "memory.copy out of bound"); + } if (size > 0) { - bool ok = ClampToBounds(dst, &size, memory_size); - ok &= ClampToBounds(src, &size, memory_size); - if (!ok) { - TRAP_MSG(MemoryAccessOutOfBounds, "memory.copy out of bound"); - } char* data = memory->data.data(); memmove(data + dst, data + src, size); } @@ -1082,11 +1092,10 @@ Result Thread::MemoryFill(const uint8_t** pc) { uint32_t size = Pop<uint32_t>(); uint8_t value = static_cast<uint8_t>(Pop<uint32_t>()); uint32_t dst = Pop<uint32_t>(); + if (!CheckBounds(dst, size, memory_size)) { + TRAP_MSG(MemoryAccessOutOfBounds, "memory.fill out of bounds"); + } if (size > 0) { - bool ok = ClampToBounds(dst, &size, memory_size); - if (!ok) { - TRAP_MSG(MemoryAccessOutOfBounds, "memory.fill out of bounds"); - } memset(memory->data.data() + dst, value, size); } return ResultType::Ok; @@ -1099,13 +1108,12 @@ Result Thread::TableInit(const uint8_t** pc) { uint32_t size = Pop<uint32_t>(); uint32_t src = Pop<uint32_t>(); uint32_t dst = Pop<uint32_t>(); + bool ok = CheckBounds(dst, size, table->size()); + ok &= CheckBounds(src, size, segment_size); + if (!ok) { + TRAP_MSG(TableAccessOutOfBounds, "table.init out of bounds"); + } if (size > 0) { - TRAP_IF(segment->dropped, ElemSegmentDropped); - bool ok = ClampToBounds(dst, &size, table->size()); - ok &= ClampToBounds(src, &size, segment_size); - if (!ok) { - TRAP_MSG(TableAccessOutOfBounds, "table.init out of bounds"); - } memcpy(table->entries.data() + dst, segment->elems.data() + src, size * sizeof(table->entries[0])); } @@ -1144,14 +1152,13 @@ Result Thread::TableFill(const uint8_t** pc) { for (uint32_t i = 0; i < size; i++) { table->entries[dst+i] = value; } - TRAP_IF(!ok, MemoryAccessOutOfBounds); + TRAP_IF(!ok, TableAccessOutOfBounds); return ResultType::Ok; } Result Thread::ElemDrop(const uint8_t** pc) { ElemSegment* segment = ReadElemSegment(pc); - TRAP_IF(segment->dropped, ElemSegmentDropped); - segment->dropped = true; + segment->elems.clear(); return ResultType::Ok; } @@ -1162,12 +1169,12 @@ Result Thread::TableCopy(const uint8_t** pc) { uint32_t size = Pop<uint32_t>(); uint32_t src = Pop<uint32_t>(); uint32_t dst = Pop<uint32_t>(); + bool ok = CheckBounds(dst, size, dst_table->size()); + ok &= CheckBounds(src, size, dst_table->size()); + if (!ok) { + TRAP_MSG(TableAccessOutOfBounds, "table.copy out of bounds"); + } if (size > 0) { - bool ok = ClampToBounds(dst, &size, dst_table->size()); - ok &= ClampToBounds(src, &size, dst_table->size()); - if (!ok) { - TRAP_MSG(TableAccessOutOfBounds, "table.copy out of bounds"); - } Ref* data_src = src_table->entries.data(); Ref* data_dst = dst_table->entries.data(); memmove(data_dst + dst, data_src + src, size * sizeof(Ref)); @@ -3755,40 +3762,36 @@ Result Executor::InitializeSegments(DefinedModule* module) { uint32_t table_size = info.table->size(); uint32_t segment_size = info.src.size(); uint32_t copy_size = segment_size; - bool ok = ClampToBounds(info.dst, ©_size, table_size); - - if (pass == Init && copy_size > 0) { - std::copy(info.src.begin(), info.src.begin() + copy_size, - info.table->entries.begin() + info.dst); - } - - if (!ok) { + if (!CheckBounds(info.dst, copy_size, table_size)) { TRAP_MSG(TableAccessOutOfBounds, "elem segment is out of bounds: [%u, %" PRIu64 ") >= max value %u", info.dst, static_cast<uint64_t>(info.dst) + segment_size, table_size); } + + if (pass == Init && copy_size > 0) { + std::copy(info.src.begin(), info.src.begin() + copy_size, + info.table->entries.begin() + info.dst); + } } for (const DataSegmentInfo& info : module->active_data_segments_) { uint32_t memory_size = info.memory->data.size(); uint32_t segment_size = info.data.size(); uint32_t copy_size = segment_size; - bool ok = ClampToBounds(info.dst, ©_size, memory_size); - - if (pass == Init && copy_size > 0) { - std::copy(info.data.begin(), info.data.begin() + copy_size, - info.memory->data.begin() + info.dst); - } - - if (!ok) { + if (!CheckBounds(info.dst, copy_size, memory_size)) { TRAP_MSG(MemoryAccessOutOfBounds, "data segment is out of bounds: [%u, %" PRIu64 ") >= max value %u", info.dst, static_cast<uint64_t>(info.dst) + segment_size, memory_size); } + + if (pass == Init && copy_size > 0) { + std::copy(info.data.begin(), info.data.begin() + copy_size, + info.memory->data.begin() + info.dst); + } } } |