Skip to content

Commit 07c57f1

Browse files
authored
[interp] Remove overlap check from *.copy instr (WebAssembly#103)
1 parent d18ec64 commit 07c57f1

File tree

8 files changed

+35
-90
lines changed

8 files changed

+35
-90
lines changed

interpreter/runtime/memory.ml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,12 @@ let init mem bs d s n =
158158

159159
let copy mem d s n =
160160
let n' = I64_convert.extend_i32_u n in
161-
let overlap = I64.lt_u Int64.(abs (sub d s)) n' in
162161
let rec loop d s n dx =
163162
if I32.gt_u n 0l then begin
164163
store_byte mem d (load_byte mem s);
165164
loop (Int64.add d dx) (Int64.add s dx) (Int32.sub n 1l) dx
166165
end
167-
in (if overlap && s < d then
166+
in (if s < d then
168167
loop Int64.(add d (sub n' 1L)) Int64.(add s (sub n' 1L)) n (-1L)
169168
else
170169
loop d s n 1L)

interpreter/runtime/table.ml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,12 @@ let init tab es d s n =
6161
in loop es d s n
6262

6363
let copy tab d s n =
64-
let overlap = I32.lt_u Int32.(abs (sub d s)) n in
6564
let rec loop d s n dx =
6665
if I32.gt_u n 0l then begin
6766
store tab d (load tab s);
6867
loop (Int32.add d dx) (Int32.add s dx) (Int32.sub n 1l) dx
6968
end
70-
in (if overlap && s < d then
69+
in (if s < d then
7170
loop Int32.(add d (sub n 1l)) Int32.(add s (sub n 1l)) n (-1l)
7271
else
7372
loop d s n 1l)

proposals/bulk-memory-operations/Overview.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,12 @@ written (by the copy operation) in the other region.
319319
This instruction has two immediate arguments: the source and
320320
destination memory indices. They currently both must be zero.
321321

322-
If the regions overlap, and the source region starts at a lower
323-
address than the target region, then the copy takes place as if from
324-
higher to lower addresses: the highest source address is read first
325-
and the value is written to the highest target address, then the next
326-
highest, and so on. Otherwise, the copy takes place as if from lower
327-
to higher addresses: the lowest source address is read first and the
328-
value is written to the lowest target address, then the next lowest,
329-
and so on.
322+
If the source region starts at a lower address than the target region, then the
323+
copy takes place as if from higher to lower addresses: the highest source
324+
address is read first and the value is written to the highest target address,
325+
then the next highest, and so on. Otherwise, the copy takes place as if from
326+
lower to higher addresses: the lowest source address is read first and the
327+
value is written to the lowest target address, then the next lowest, and so on.
330328

331329
(The direction of the copy is defined in order to future-proof
332330
`memory.copy` for shared memory and a memory read/write protection

test/core/bulk.wast

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,6 @@
9999
(invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100))
100100
(invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100))
101101

102-
;; Out-of-bounds writes trap, but all previous writes succeed.
103-
(assert_trap (invoke "copy" (i32.const 0xfffe) (i32.const 0) (i32.const 3))
104-
"out of bounds memory access")
105-
(assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xaa))
106-
(assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xbb))
107-
108102
;; Succeed when copying 0 bytes at the end of the region.
109103
(invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0))
110104
(invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0))
@@ -284,12 +278,6 @@
284278
(invoke "copy" (i32.const 6) (i32.const 8) (i32.const 2))
285279
(invoke "copy" (i32.const 8) (i32.const 6) (i32.const 2))
286280

287-
;; Out-of-bounds writes trap, but all previous writes succeed.
288-
(assert_trap (invoke "call" (i32.const 9)) "uninitialized element")
289-
(assert_trap (invoke "copy" (i32.const 9) (i32.const 0) (i32.const 2))
290-
"out of bounds table access")
291-
(assert_return (invoke "call" (i32.const 9)) (i32.const 1))
292-
293281
;; Succeed when copying 0 elements at the end of the region.
294282
(invoke "copy" (i32.const 10) (i32.const 0) (i32.const 0))
295283
(invoke "copy" (i32.const 0) (i32.const 10) (i32.const 0))

test/core/memory_copy.wast

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -698,26 +698,6 @@
698698
(assert_return (invoke "load8_u" (i32.const 65092)) (i32.const 0))
699699
(assert_return (invoke "load8_u" (i32.const 65291)) (i32.const 0))
700700
(assert_return (invoke "load8_u" (i32.const 65490)) (i32.const 0))
701-
(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 0))
702-
(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 1))
703-
(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 2))
704-
(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 3))
705-
(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 4))
706-
(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 5))
707-
(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 6))
708-
(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 7))
709-
(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 8))
710-
(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 9))
711-
(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 10))
712-
(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 11))
713-
(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 12))
714-
(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 13))
715-
(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 14))
716-
(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 15))
717-
(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 16))
718-
(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 17))
719-
(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 18))
720-
(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 19))
721701

722702
(module
723703
(memory (export "mem") 1 1 )
@@ -1080,27 +1060,6 @@
10801060
(assert_return (invoke "load8_u" (i32.const 65093)) (i32.const 0))
10811061
(assert_return (invoke "load8_u" (i32.const 65292)) (i32.const 0))
10821062
(assert_return (invoke "load8_u" (i32.const 65491)) (i32.const 0))
1083-
(assert_return (invoke "load8_u" (i32.const 65515)) (i32.const 0))
1084-
(assert_return (invoke "load8_u" (i32.const 65516)) (i32.const 1))
1085-
(assert_return (invoke "load8_u" (i32.const 65517)) (i32.const 2))
1086-
(assert_return (invoke "load8_u" (i32.const 65518)) (i32.const 3))
1087-
(assert_return (invoke "load8_u" (i32.const 65519)) (i32.const 4))
1088-
(assert_return (invoke "load8_u" (i32.const 65520)) (i32.const 5))
1089-
(assert_return (invoke "load8_u" (i32.const 65521)) (i32.const 6))
1090-
(assert_return (invoke "load8_u" (i32.const 65522)) (i32.const 7))
1091-
(assert_return (invoke "load8_u" (i32.const 65523)) (i32.const 8))
1092-
(assert_return (invoke "load8_u" (i32.const 65524)) (i32.const 9))
1093-
(assert_return (invoke "load8_u" (i32.const 65525)) (i32.const 10))
1094-
(assert_return (invoke "load8_u" (i32.const 65526)) (i32.const 11))
1095-
(assert_return (invoke "load8_u" (i32.const 65527)) (i32.const 12))
1096-
(assert_return (invoke "load8_u" (i32.const 65528)) (i32.const 13))
1097-
(assert_return (invoke "load8_u" (i32.const 65529)) (i32.const 14))
1098-
(assert_return (invoke "load8_u" (i32.const 65530)) (i32.const 15))
1099-
(assert_return (invoke "load8_u" (i32.const 65531)) (i32.const 16))
1100-
(assert_return (invoke "load8_u" (i32.const 65532)) (i32.const 17))
1101-
(assert_return (invoke "load8_u" (i32.const 65533)) (i32.const 18))
1102-
(assert_return (invoke "load8_u" (i32.const 65534)) (i32.const 19))
1103-
(assert_return (invoke "load8_u" (i32.const 65535)) (i32.const 20))
11041063

11051064
(module
11061065
(memory (export "mem") 1 1 )

test/core/table_copy.wast

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -759,14 +759,14 @@
759759
(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
760760
(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
761761
(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
762-
(assert_return (invoke "test" (i32.const 24)) (i32.const 0))
763-
(assert_return (invoke "test" (i32.const 25)) (i32.const 1))
764-
(assert_return (invoke "test" (i32.const 26)) (i32.const 2))
765-
(assert_return (invoke "test" (i32.const 27)) (i32.const 3))
766-
(assert_return (invoke "test" (i32.const 28)) (i32.const 4))
767-
(assert_return (invoke "test" (i32.const 29)) (i32.const 5))
768-
(assert_return (invoke "test" (i32.const 30)) (i32.const 6))
769-
(assert_return (invoke "test" (i32.const 31)) (i32.const 7))
762+
(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
763+
(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
764+
(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
765+
(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
766+
(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
767+
(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
768+
(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
769+
(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
770770

771771
(module
772772
(type (func (result i32)))
@@ -819,15 +819,15 @@
819819
(assert_trap (invoke "test" (i32.const 20)) "uninitialized element")
820820
(assert_trap (invoke "test" (i32.const 21)) "uninitialized element")
821821
(assert_trap (invoke "test" (i32.const 22)) "uninitialized element")
822-
(assert_return (invoke "test" (i32.const 23)) (i32.const 0))
823-
(assert_return (invoke "test" (i32.const 24)) (i32.const 1))
824-
(assert_return (invoke "test" (i32.const 25)) (i32.const 2))
825-
(assert_return (invoke "test" (i32.const 26)) (i32.const 3))
826-
(assert_return (invoke "test" (i32.const 27)) (i32.const 4))
827-
(assert_return (invoke "test" (i32.const 28)) (i32.const 5))
828-
(assert_return (invoke "test" (i32.const 29)) (i32.const 6))
829-
(assert_return (invoke "test" (i32.const 30)) (i32.const 7))
830-
(assert_return (invoke "test" (i32.const 31)) (i32.const 8))
822+
(assert_trap (invoke "test" (i32.const 23)) "uninitialized element")
823+
(assert_trap (invoke "test" (i32.const 24)) "uninitialized element")
824+
(assert_trap (invoke "test" (i32.const 25)) "uninitialized element")
825+
(assert_trap (invoke "test" (i32.const 26)) "uninitialized element")
826+
(assert_trap (invoke "test" (i32.const 27)) "uninitialized element")
827+
(assert_trap (invoke "test" (i32.const 28)) "uninitialized element")
828+
(assert_trap (invoke "test" (i32.const 29)) "uninitialized element")
829+
(assert_trap (invoke "test" (i32.const 30)) "uninitialized element")
830+
(assert_trap (invoke "test" (i32.const 31)) "uninitialized element")
831831

832832
(module
833833
(type (func (result i32)))

test/meta/generate_memory_copy.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,8 @@ function initializers(count, startingAt) {
8484
return s;
8585
}
8686

87-
function mem_copy(min, max, shared, srcOffs, targetOffs, len, copyDown=false) {
87+
function mem_copy(min, max, shared, srcOffs, targetOffs, len) {
88+
let copyDown = srcOffs < targetOffs;
8889
let memLength = min * PAGESIZE;
8990
let targetAvail = memLength - targetOffs;
9091
let srcAvail = memLength - srcOffs;
@@ -165,21 +166,21 @@ if (WITH_SHARED_MEMORY) {
165166
}
166167

167168
// OOB target address, overlapping, src < target
168-
mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40, true);
169+
mem_copy(1, 1, "", PAGESIZE-50, PAGESIZE-20, 40);
169170

170171
// OOB source address, overlapping, target < src
171172
mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-50, 40);
172173

173174
// OOB both, overlapping, including target == src
174-
mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40, true);
175+
mem_copy(1, 1, "", PAGESIZE-30, PAGESIZE-20, 40);
175176
mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-30, 40);
176177
mem_copy(1, 1, "", PAGESIZE-20, PAGESIZE-20, 40);
177178

178179
// Arithmetic overflow on source address.
179180
mem_copy(1, "", "", PAGESIZE-20, 0, 0xFFFFF000);
180181

181182
// Arithmetic overflow on target adddress is an overlapping case.
182-
mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00, true);
183+
mem_copy(1, 1, "", PAGESIZE-0x1000, PAGESIZE-20, 0xFFFFFF00);
183184

184185
// Sundry compilation failures.
185186

test/meta/generate_table_copy.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,8 @@ tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))",
227227

228228
const tbl_copy_len = 16;
229229

230-
function tbl_copy(min, max, srcOffs, targetOffs, len, copyDown=false) {
230+
function tbl_copy(min, max, srcOffs, targetOffs, len) {
231+
let copyDown = srcOffs < targetOffs;
231232
let tblLength = min;
232233

233234
let targetAvail = tblLength - targetOffs;
@@ -319,18 +320,18 @@ tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), 0, tbl_co
319320
tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len)-1, 0, tbl_copy_len-1);
320321

321322
// OOB target address, overlapping, src < target
322-
tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len-5, Math.floor(1.5*tbl_copy_len), tbl_copy_len, true);
323+
tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len-5, Math.floor(1.5*tbl_copy_len), tbl_copy_len);
323324

324325
// OOB source address, overlapping, target < src
325326
tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len-5, tbl_copy_len);
326327

327328
// OOB both, overlapping, including src == target
328-
tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, Math.floor(1.5*tbl_copy_len), tbl_copy_len, true);
329+
tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, Math.floor(1.5*tbl_copy_len), tbl_copy_len);
329330
tbl_copy(tbl_copy_len*2, tbl_copy_len*4, Math.floor(1.5*tbl_copy_len), tbl_copy_len+5, tbl_copy_len);
330331
tbl_copy(tbl_copy_len*2, tbl_copy_len*4, tbl_copy_len+5, tbl_copy_len+5, tbl_copy_len);
331332

332333
// Arithmetic overflow on source address.
333334
tbl_copy(tbl_copy_len*8, tbl_copy_len*8, tbl_copy_len*7, 0, 0xFFFFFFE0);
334335

335336
// Arithmetic overflow on target adddress is an overlapping case.
336-
tbl_copy(tbl_copy_len*8, tbl_copy_len*8, 0, tbl_copy_len*7, 0xFFFFFFE0, true);
337+
tbl_copy(tbl_copy_len*8, tbl_copy_len*8, 0, tbl_copy_len*7, 0xFFFFFFE0);

0 commit comments

Comments
 (0)