summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-12-02 12:20:55 -0800
committerGitHub <noreply@github.com>2024-12-02 12:20:55 -0800
commit31c988b30556ef000bd2212754d7fc5beebf08d2 (patch)
treea8e3b30ad12c71aade983b9dc393b0cbc13556d7
parentb1c5a007f3986c11916e8ac4a84c41c01d5e04bb (diff)
downloadbinaryen-31c988b30556ef000bd2212754d7fc5beebf08d2.tar.gz
binaryen-31c988b30556ef000bd2212754d7fc5beebf08d2.tar.bz2
binaryen-31c988b30556ef000bd2212754d7fc5beebf08d2.zip
[GC] Fix trapping on array.new_data of dropped segments of offset > 0 (#7124)
Even if the size is 0, if the offset is > 0 then we should trap.
-rw-r--r--src/wasm-interpreter.h15
-rw-r--r--test/lit/exec/array.wast21
2 files changed, 33 insertions, 3 deletions
diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h
index 81531e27c..937248d81 100644
--- a/src/wasm-interpreter.h
+++ b/src/wasm-interpreter.h
@@ -4022,16 +4022,25 @@ public:
const auto& seg = *wasm.getDataSegment(curr->segment);
auto elemBytes = element.getByteSize();
- auto end = offset + size * elemBytes;
- if ((size != 0ull && droppedDataSegments.count(curr->segment)) ||
- end > seg.data.size()) {
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+
+ uint64_t end;
+ if (std::ckd_add(&end, offset, size * elemBytes) || end > seg.data.size()) {
trap("out of bounds segment access in array.new_data");
}
+ if (droppedDataSegments.count(curr->segment) && end > 0) {
+ trap("dropped segment access in array.new_data");
+ }
contents.reserve(size);
for (Index i = offset; i < end; i += elemBytes) {
auto addr = (void*)&seg.data[i];
contents.push_back(this->makeFromMemory(addr, element));
}
+
+#pragma GCC diagnostic pop
+
return self()->makeGCData(std::move(contents), curr->type);
}
Flow visitArrayNewElem(ArrayNewElem* curr) {
diff --git a/test/lit/exec/array.wast b/test/lit/exec/array.wast
index ff10c555c..d70af1ddc 100644
--- a/test/lit/exec/array.wast
+++ b/test/lit/exec/array.wast
@@ -13,6 +13,8 @@
(elem $passive $func)
+ (data $data "a")
+
;; CHECK: [fuzz-exec] calling func
;; CHECK-NEXT: [fuzz-exec] note result: func => 1
(func $func (export "func") (result i32)
@@ -98,6 +100,21 @@
(i32.const 0)
)
)
+
+ ;; CHECK: [fuzz-exec] calling drop_array.new_data
+ ;; CHECK-NEXT: [trap dropped segment access in array.new_data]
+ (func $drop_array.new_data (export "drop_array.new_data")
+ ;; Dropping the data segment causes the next instruction to trap, even though
+ ;; the size there is 0, because the offset is > 0.
+ (data.drop $data)
+ (drop
+ (array.new_data $array $data
+ (i32.const 1)
+ (i32.const 0)
+ )
+ )
+ )
+
)
;; CHECK: [fuzz-exec] calling func
;; CHECK-NEXT: [fuzz-exec] note result: func => 1
@@ -115,6 +132,10 @@
;; CHECK: [fuzz-exec] calling init_active_in_bounds
;; CHECK: [fuzz-exec] calling init_passive
+
+;; CHECK: [fuzz-exec] calling drop_array.new_data
+;; CHECK-NEXT: [trap dropped segment access in array.new_data]
+;; CHECK-NEXT: [fuzz-exec] comparing drop_array.new_data
;; CHECK-NEXT: [fuzz-exec] comparing func
;; CHECK-NEXT: [fuzz-exec] comparing init_active
;; CHECK-NEXT: [fuzz-exec] comparing init_active_in_bounds