Skip to content
This repository was archived by the owner on Nov 3, 2021. It is now read-only.

Commit f817560

Browse files
authored
[Interpreter] Initialized segments persist after instantiation failure
This behavior is a breaking change from the v1 spec, but it is unlikely that any programs depend on it.
1 parent 1671a38 commit f817560

File tree

6 files changed

+39
-35
lines changed

6 files changed

+39
-35
lines changed

interpreter/exec/eval.ml

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -405,26 +405,19 @@ let init_table (inst : module_inst) (seg : table_segment) =
405405
| Active {index; offset = const; init} ->
406406
let tab = table inst index in
407407
let offset = i32 (eval_const inst const) const.at in
408-
let end_ = Int32.(add offset (of_int (List.length init))) in
409-
let bound = Table.size tab in
410-
if I32.lt_u bound end_ || I32.lt_u end_ offset then
411-
Link.error seg.at "elements segment does not fit table";
412-
fun () ->
413-
Table.blit tab offset (List.map (fun x -> FuncElem (func inst x)) init)
414-
| Passive init -> fun () -> ()
408+
(try Table.init tab offset (List.map (fun x -> FuncElem (func inst x)) init)
409+
with Table.Bounds -> Link.error seg.at "elements segment does not fit table")
410+
| Passive init -> ()
415411

416412
let init_memory (inst : module_inst) (seg : memory_segment) =
417413
match seg.it with
418414
| Active {index; offset = const; init} ->
419415
let mem = memory inst index in
420416
let offset' = i32 (eval_const inst const) const.at in
421417
let offset = I64_convert.extend_i32_u offset' in
422-
let end_ = Int64.(add offset (of_int (String.length init))) in
423-
let bound = Memory.bound mem in
424-
if I64.lt_u bound end_ || I64.lt_u end_ offset then
425-
Link.error seg.at "data segment does not fit memory";
426-
fun () -> Memory.store_bytes mem offset init
427-
| Passive init -> fun () -> ()
418+
(try Memory.init mem offset init
419+
with Memory.Bounds -> Link.error seg.at "data segment does not fit memory")
420+
| Passive init -> ()
428421

429422

430423
let add_import (m : module_) (ext : extern) (im : import) (inst : module_inst)
@@ -460,9 +453,7 @@ let init (m : module_) (exts : extern list) : module_inst =
460453
in
461454
let inst = {inst1 with exports = List.map (create_export inst1) exports} in
462455
List.iter (init_func inst) fs;
463-
let init_elems = List.map (init_table inst) elems in
464-
let init_datas = List.map (init_memory inst) data in
465-
List.iter (fun f -> f ()) init_elems;
466-
List.iter (fun f -> f ()) init_datas;
456+
List.iter (init_table inst) elems;
457+
List.iter (init_memory inst) data;
467458
Lib.Option.app (fun x -> ignore (invoke (func inst x) [])) start;
468459
inst

interpreter/runtime/memory.ml

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -147,14 +147,11 @@ let store_packed sz mem a o v =
147147

148148
let check_bounds mem a = if I64.gt_u a (bound mem) then raise Bounds
149149

150-
let fill mem a v n =
151-
let rec loop a n =
152-
if n > 0l then begin
153-
store_byte mem a v;
154-
loop (Int64.add a 1L) (Int32.sub n 1l)
155-
end
156-
in loop a n;
157-
check_bounds mem Int64.(add a (of_int32 n))
150+
let init mem a bs =
151+
for i = 0 to String.length bs - 1 do
152+
store_byte mem Int64.(add a (of_int i)) (Char.code bs.[i])
153+
done;
154+
check_bounds mem Int64.(add a (of_int (String.length bs)))
158155

159156
let copy mem d s n =
160157
let n' = Int64.of_int32 n in
@@ -170,3 +167,12 @@ let copy mem d s n =
170167
loop d s n 1L);
171168
check_bounds mem (Int64.add d n');
172169
check_bounds mem (Int64.add s n')
170+
171+
let fill mem a v n =
172+
let rec loop a n =
173+
if n > 0l then begin
174+
store_byte mem a v;
175+
loop (Int64.add a 1L) (Int32.sub n 1l)
176+
end
177+
in loop a n;
178+
check_bounds mem Int64.(add a (of_int32 n))

interpreter/runtime/memory.mli

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,6 @@ val store_packed :
4444
pack_size -> memory -> address -> offset -> value -> unit
4545
(* raises Type, Bounds *)
4646

47-
val fill : memory -> address -> int -> count -> unit (* raises Bounds *)
47+
val init : memory -> address -> string -> unit (* raises Bounds *)
4848
val copy : memory -> address -> address -> count -> unit (* raises Bounds *)
49+
val fill : memory -> address -> int -> count -> unit (* raises Bounds *)

interpreter/runtime/table.ml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ let load tab i =
4848
let store tab i v =
4949
try Lib.Array32.set tab.content i v with Invalid_argument _ -> raise Bounds
5050

51-
let blit tab offset elems =
52-
let data = Array.of_list elems in
53-
try Lib.Array32.blit data 0l tab.content offset (Lib.Array32.length data)
54-
with Invalid_argument _ -> raise Bounds
51+
let check_bounds tab i = if I32.gt_u i (size tab) then raise Bounds
52+
53+
let init tab offset elems =
54+
List.iteri (fun i -> store tab (Int32.(add offset (of_int i)))) elems;
55+
check_bounds tab Int32.(add offset (of_int (List.length elems)))

interpreter/runtime/table.mli

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@ val grow : table -> size -> unit (* raises SizeOverflow, SizeLimit *)
2020

2121
val load : table -> index -> elem (* raises Bounds *)
2222
val store : table -> index -> elem -> unit (* raises Bounds *)
23-
val blit : table -> index -> elem list -> unit (* raises Bounds *)
23+
24+
val init : table -> index -> elem list -> unit (* raises Bounds *)

test/core/linking.wast

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@
224224
)
225225
(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
226226

227+
;; Unlike in the v1 spec, the elements stored before an out-of-bounds access
228+
;; persist after the instantiation failure.
227229
(assert_unlinkable
228230
(module
229231
(table (import "Mt" "tab") 10 funcref)
@@ -233,7 +235,7 @@
233235
)
234236
"elements segment does not fit"
235237
)
236-
(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
238+
(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0))
237239

238240
(assert_unlinkable
239241
(module
@@ -245,7 +247,7 @@
245247
)
246248
"data segment does not fit"
247249
)
248-
(assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized")
250+
(assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0))
249251

250252

251253
;; Memories
@@ -331,6 +333,8 @@
331333
)
332334
(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
333335

336+
;; Unlike in v1 spec, bytes written before an out-of-bounds access persist
337+
;; after the instantiation failure.
334338
(assert_unlinkable
335339
(module
336340
(memory (import "Mm" "mem") 1)
@@ -339,7 +343,7 @@
339343
)
340344
"data segment does not fit"
341345
)
342-
(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
346+
(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97))
343347

344348
(assert_unlinkable
345349
(module
@@ -351,4 +355,4 @@
351355
)
352356
"elements segment does not fit"
353357
)
354-
(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0))
358+
(assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97))

0 commit comments

Comments
 (0)