Skip to content

Commit d18ec64

Browse files
authored
[interp] Don't trap on zero-bytes out-of-bounds (WebAssembly#102)
1 parent 8c6ea22 commit d18ec64

15 files changed

+57
-89
lines changed

interpreter/runtime/memory.ml

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,6 @@ let store_packed sz mem a o v =
145145
| _ -> raise Type
146146
in storen mem a o n x
147147

148-
let check_str_bounds bs a =
149-
if I64.gt_u a (Int64.of_int (String.length bs)) then raise Bounds
150-
151-
let check_bounds mem a = if I64.gt_u a (bound mem) then raise Bounds
152-
153148
let init mem bs d s n =
154149
let load_str_byte a =
155150
try Char.code bs.[Int64.to_int a]
@@ -159,10 +154,7 @@ let init mem bs d s n =
159154
store_byte mem d (load_str_byte s);
160155
loop (Int64.add d 1L) (Int64.add s 1L) (Int32.sub n 1l)
161156
end
162-
in loop d s n;
163-
let n' = I64_convert.extend_i32_u n in
164-
check_bounds mem (Int64.add d n');
165-
check_str_bounds bs (Int64.add s n')
157+
in loop d s n
166158

167159
let copy mem d s n =
168160
let n' = I64_convert.extend_i32_u n in
@@ -175,15 +167,12 @@ let copy mem d s n =
175167
in (if overlap && s < d then
176168
loop Int64.(add d (sub n' 1L)) Int64.(add s (sub n' 1L)) n (-1L)
177169
else
178-
loop d s n 1L);
179-
check_bounds mem (Int64.add d n');
180-
check_bounds mem (Int64.add s n')
170+
loop d s n 1L)
181171

182172
let fill mem a v n =
183173
let rec loop a n =
184174
if I32.gt_u n 0l then begin
185175
store_byte mem a v;
186176
loop (Int64.add a 1L) (Int32.sub n 1l)
187177
end
188-
in loop a n;
189-
check_bounds mem (Int64.add a (I64_convert.extend_i32_u n))
178+
in loop a n

interpreter/runtime/table.ml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,16 @@ let load tab i =
4949
let store tab i v =
5050
try Lib.Array32.set tab.content i v with Invalid_argument _ -> raise Bounds
5151

52-
let check_bounds tab i = if I32.gt_u i (size tab) then raise Bounds
53-
5452
let init tab es d s n =
5553
let rec loop es d s n =
5654
match s, n, es with
57-
| 0l, 0l, _ -> ()
55+
| s, 0l, _ -> ()
5856
| 0l, n, e::es' ->
5957
store tab d e;
6058
loop es' (Int32.add d 1l) 0l (Int32.sub n 1l)
6159
| s, n, _::es' -> loop es' d (Int32.sub s 1l) n
6260
| _ -> raise Bounds
63-
in loop es d s n;
64-
check_bounds tab (Int32.add d n)
61+
in loop es d s n
6562

6663
let copy tab d s n =
6764
let overlap = I32.lt_u Int32.(abs (sub d s)) n in
@@ -73,6 +70,4 @@ let copy tab d s n =
7370
in (if overlap && s < d then
7471
loop Int32.(add d (sub n 1l)) Int32.(add s (sub n 1l)) n (-1l)
7572
else
76-
loop d s n 1l);
77-
check_bounds tab (Int32.add d n);
78-
check_bounds tab (Int32.add s n)
73+
loop d s n 1l)

test/core/bulk.wast

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,8 @@
4848
;; Succeed when writing 0 bytes at the end of the region.
4949
(invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0))
5050

51-
;; Fail on out-of-bounds when writing 0 bytes outside of memory.
52-
(assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0))
53-
"out of bounds memory access")
51+
;; OK to write 0 bytes outside of memory.
52+
(invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0))
5453

5554

5655
;; memory.copy
@@ -110,11 +109,9 @@
110109
(invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0))
111110
(invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0))
112111

113-
;; Fail on out-of-bounds when copying 0 bytes outside of memory.
114-
(assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0))
115-
"out of bounds memory access")
116-
(assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0))
117-
"out of bounds memory access")
112+
;; OK to copy 0 bytes outside of memory.
113+
(invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0))
114+
(invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0))
118115

119116

120117
;; memory.init
@@ -150,11 +147,9 @@
150147
(invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0))
151148
(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0))
152149

153-
;; Fail on out-of-bounds when writing 0 bytes outside of memory or segment.
154-
(assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0))
155-
"out of bounds memory access")
156-
(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0))
157-
"out of bounds memory access")
150+
;; OK to write 0 bytes outside of memory or segment.
151+
(invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0))
152+
(invoke "init" (i32.const 0) (i32.const 5) (i32.const 0))
158153

159154
;; data.drop
160155
(module
@@ -216,11 +211,9 @@
216211
(invoke "init" (i32.const 3) (i32.const 0) (i32.const 0))
217212
(invoke "init" (i32.const 0) (i32.const 4) (i32.const 0))
218213

219-
;; Fail on out-of-bounds when storing 0 elements outside of table or segment.
220-
(assert_trap (invoke "init" (i32.const 4) (i32.const 0) (i32.const 0))
221-
"out of bounds table access")
222-
(assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0))
223-
"out of bounds table access")
214+
;; OK to storing 0 elements outside of table or segment.
215+
(invoke "init" (i32.const 4) (i32.const 0) (i32.const 0))
216+
(invoke "init" (i32.const 0) (i32.const 5) (i32.const 0))
224217

225218

226219
;; elem.drop
@@ -302,7 +295,5 @@
302295
(invoke "copy" (i32.const 0) (i32.const 10) (i32.const 0))
303296

304297
;; Fail on out-of-bounds when copying 0 elements outside of table.
305-
(assert_trap (invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0))
306-
"out of bounds table access")
307-
(assert_trap (invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0))
308-
"out of bounds table access")
298+
(invoke "copy" (i32.const 11) (i32.const 0) (i32.const 0))
299+
(invoke "copy" (i32.const 0) (i32.const 11) (i32.const 0))

test/core/data.wast

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -182,20 +182,15 @@
182182
"data segment does not fit"
183183
)
184184

185-
(assert_unlinkable
186-
(module
187-
(memory 0)
188-
(data (i32.const 1))
189-
)
190-
"data segment does not fit"
185+
;; Writing 0 bytes outside of bounds is allowed now.
186+
(module
187+
(memory 0)
188+
(data (i32.const 1))
191189
)
192190

193-
(assert_unlinkable
194-
(module
195-
(memory 0 1)
196-
(data (i32.const 1))
197-
)
198-
"data segment does not fit"
191+
(module
192+
(memory 0 1)
193+
(data (i32.const 1))
199194
)
200195

201196
;; This seems to cause a time-out on Travis.

test/core/elem.wast

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,10 @@
166166
"elements segment does not fit"
167167
)
168168

169-
(assert_unlinkable
170-
(module
171-
(table 0 funcref)
172-
(elem (i32.const 1))
173-
)
174-
"elements segment does not fit"
169+
;; Writing 0 elems outside of bounds is allowed now.
170+
(module
171+
(table 0 funcref)
172+
(elem (i32.const 1))
175173
)
176174

177175
(assert_unlinkable

test/core/memory_copy.wast

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5001,7 +5001,7 @@
50015001
(memory 1 1)
50025002
(func (export "test")
50035003
(memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0))))
5004-
(assert_trap (invoke "test") "out of bounds")
5004+
(invoke "test")
50055005

50065006
(module
50075007
(memory 1 1)
@@ -5013,7 +5013,7 @@
50135013
(memory 1 1)
50145014
(func (export "test")
50155015
(memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0))))
5016-
(assert_trap (invoke "test") "out of bounds")
5016+
(invoke "test")
50175017

50185018
(module
50195019
(memory 1 1)

test/core/memory_fill.wast

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114

115115
(func (export "test")
116116
(memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0))))
117-
(assert_trap (invoke "test") "out of bounds memory access")
117+
(invoke "test")
118118

119119
(module
120120
(memory 1 1)

test/core/memory_init.wast

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@
270270
(data "\37")
271271
(func (export "test")
272272
(memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0))))
273-
(assert_trap (invoke "test") "out of bounds")
273+
(invoke "test")
274274

275275
(module
276276
(memory 1)
@@ -284,7 +284,7 @@
284284
(data "\37")
285285
(func (export "test")
286286
(memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0))))
287-
(assert_trap (invoke "test") "out of bounds")
287+
(invoke "test")
288288

289289
(module
290290
(memory 1)

test/core/table_copy.wast

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@
633633
(table.copy (i32.const 31) (i32.const 15) (i32.const 0))
634634
))
635635

636-
(assert_trap (invoke "test") "out of bounds")
636+
(invoke "test")
637637

638638
(module
639639
(table 30 30 funcref)
@@ -681,7 +681,7 @@
681681
(table.copy (i32.const 15) (i32.const 31) (i32.const 0))
682682
))
683683

684-
(assert_trap (invoke "test") "out of bounds")
684+
(invoke "test")
685685

686686
(module
687687
(table 30 30 funcref)

test/core/table_init.wast

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@
446446
(func (export "test")
447447
(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))
448448
))
449-
(assert_trap (invoke "test") "out of bounds")
449+
(invoke "test")
450450

451451
(module
452452
(table 30 30 funcref)
@@ -492,7 +492,7 @@
492492
(func (export "test")
493493
(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))
494494
))
495-
(assert_trap (invoke "test") "out of bounds")
495+
(invoke "test")
496496

497497
(module
498498
(table 30 30 funcref)

test/meta/generate_memory_copy.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,13 +304,13 @@ print(
304304
(invoke "test")
305305
`);
306306

307-
// Zero len with dest offset out-of-bounds past the end of memory is not allowed
307+
// Zero len with dest offset out-of-bounds past the end of memory is allowed
308308
print(
309309
`(module
310310
(memory 1 1)
311311
(func (export "test")
312312
(memory.copy (i32.const 0x20000) (i32.const 0x7000) (i32.const 0))))
313-
(assert_trap (invoke "test") "out of bounds")
313+
(invoke "test")
314314
`);
315315

316316
// Zero len with src offset out-of-bounds at the end of memory is allowed
@@ -322,13 +322,13 @@ print(
322322
(invoke "test")
323323
`);
324324

325-
// Zero len with src offset out-of-bounds past the end of memory is not allowed
325+
// Zero len with src offset out-of-bounds past the end of memory is allowed
326326
print(
327327
`(module
328328
(memory 1 1)
329329
(func (export "test")
330330
(memory.copy (i32.const 0x9000) (i32.const 0x20000) (i32.const 0))))
331-
(assert_trap (invoke "test") "out of bounds")
331+
(invoke "test")
332332
`);
333333

334334
// Zero len with both dest and src offsets out-of-bounds at the end of memory is allowed

test/meta/generate_memory_fill.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ print(
5656
(invoke "test")
5757
`);
5858

59-
// Zero len with offset out-of-bounds past the end of memory is not allowed
59+
// Zero len with offset out-of-bounds past the end of memory is allowed
6060
print(
6161
`(module
6262
${PREAMBLE}
6363
(func (export "test")
6464
(memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0))))
65-
(assert_trap (invoke "test") "out of bounds memory access")
65+
(invoke "test")
6666
`);
6767

6868
// Very large range

test/meta/generate_memory_init.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,13 @@ print(
164164
(assert_trap (invoke "test") "out of bounds")
165165
`);
166166

167-
// init: seg ix is valid passive, zero len, but src offset past the end
167+
// init: seg ix is valid passive, src offset past the end, zero len is always valid
168168
print(
169169
`(module
170170
${PREAMBLE}
171171
(func (export "test")
172172
(memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0))))
173-
(assert_trap (invoke "test") "out of bounds")
173+
(invoke "test")
174174
`);
175175

176176
// init: seg ix is valid passive, zero len, src offset at the end
@@ -182,13 +182,13 @@ print(
182182
(invoke "test")
183183
`);
184184

185-
// init: seg ix is valid passive, zero len, but dst offset past the end
185+
// init: seg ix is valid passive, dst offset past the end, zero len is always valid
186186
print(
187187
`(module
188188
${PREAMBLE}
189189
(func (export "test")
190190
(memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0))))
191-
(assert_trap (invoke "test") "out of bounds")
191+
(invoke "test")
192192
`);
193193

194194
// init: seg ix is valid passive, zero len, but dst offset at the end

test/meta/generate_table_copy.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,20 +189,20 @@ tab_test2("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))",
189189
"",
190190
undefined);
191191

192-
// copy: zero length with dst offset out of bounds past the end of the table is not allowed
192+
// copy: zero length with dst offset out of bounds past the end of the table is allowed
193193
tab_test2("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))",
194194
"",
195-
"out of bounds");
195+
undefined);
196196

197197
// copy: zero length with src offset out of bounds at the end of the table is allowed
198198
tab_test2("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))",
199199
"",
200200
undefined);
201201

202-
// copy: zero length with src offset out of bounds past the end of the table is not allowed
202+
// copy: zero length with src offset out of bounds past the end of the table is allowed
203203
tab_test2("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))",
204204
"",
205-
"out of bounds");
205+
undefined);
206206

207207
// copy: zero length with both dst and src offset out of bounds at the end of the table is allowed
208208
tab_test2("(table.copy (i32.const 30) (i32.const 30) (i32.const 0))",

test/meta/generate_table_init.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -226,19 +226,19 @@ tab_test1("(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))",
226226
undefined);
227227

228228
// init: seg ix is valid passive, zero len, and src offset out of bounds past the
229-
// end of the table - this is not allowed
229+
// end of the table - this is allowed
230230
tab_test1("(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))",
231-
"out of bounds");
231+
undefined);
232232

233233
// init: seg ix is valid passive, zero len, and dst offset out of bounds at the
234234
// end of the table - this is allowed
235235
tab_test1("(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))",
236236
undefined);
237237

238238
// init: seg ix is valid passive, zero len, and dst offset out of bounds past the
239-
// end of the table - this is not allowed
239+
// end of the table - this is allowed
240240
tab_test1("(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))",
241-
"out of bounds");
241+
undefined);
242242

243243
// init: seg ix is valid passive, zero len, and dst and src offsets out of bounds
244244
// at the end of the table - this is allowed

0 commit comments

Comments
 (0)