Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions interpreter/runtime/memory.ml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@ exception SizeOverflow
exception SizeLimit
exception OutOfMemory

let page_size = 0x10000L (* 64 KiB *)

let valid_limits {min; max} =
match max with
| None -> true
| Some m -> I64.le_u min m

let valid_size at i =
match at with
| I32AT -> I64.le_u i 0xffffL
| I64AT -> true
let valid_size at pt i =
match pt with
| PageT 1 -> true
| PageT ps ->
match at with
| I32AT -> I64.le_u i (Int64.div 0xffffffffL (Int64.of_int ps))
| I64AT -> true

let create n (PageT ps) =
try
Expand All @@ -39,7 +40,7 @@ let create n (PageT ps) =

let alloc (MemoryT (at, lim, pt) as ty) =
assert Free.((memorytype ty).types = Set.empty);
if not (valid_size at lim.min) then raise SizeOverflow;
if not (valid_size at pt lim.min) then raise SizeOverflow;
if not (valid_limits lim) then raise Type;
{ty; content = create lim.min pt}

Expand All @@ -65,7 +66,7 @@ let grow mem delta =
let new_size = Int64.add old_size delta in
if I64.gt_u old_size new_size then raise SizeOverflow else
let lim' = {lim with min = new_size} in
if not (valid_size at new_size) then raise SizeOverflow else
if not (valid_size at pt new_size) then raise SizeOverflow else
if not (valid_limits lim') then raise SizeLimit else
let after = create new_size pt in
let dim = Array1_64.dim mem.content in
Expand Down
2 changes: 0 additions & 2 deletions interpreter/runtime/memory.mli
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ exception SizeOverflow
exception SizeLimit
exception OutOfMemory

val page_size : int64

val alloc : memorytype -> memory (* raises Type, SizeOverflow, OutOfMemory *)
val type_of : memory -> memorytype
val addrtype_of : memory -> addrtype
Expand Down
1 change: 1 addition & 0 deletions interpreter/text/lexer.mll
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,7 @@ rule token = parse
| "start" -> START
| "import" -> IMPORT
| "export" -> EXPORT
| "pagesize" -> PAGESIZE

| "module" -> MODULE
| "binary" -> BIN
Expand Down
28 changes: 23 additions & 5 deletions interpreter/text/parser.mly
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ let parse_annots (m : module_) : Custom.section list =
%token VEC_SHUFFLE
%token<Ast.laneidx -> Ast.instr'> VEC_EXTRACT VEC_REPLACE
%token FUNC START TYPE PARAM RESULT LOCAL GLOBAL
%token PAGESIZE
%token TABLE ELEM MEMORY TAG DATA DECLARE OFFSET ITEM IMPORT EXPORT
%token MODULE BIN QUOTE DEFINITION INSTANCE
%token SCRIPT REGISTER INVOKE GET
Expand Down Expand Up @@ -465,8 +466,21 @@ subtype :
tabletype :
| addrtype limits reftype { fun c -> TableT ($1, $2, $3 c) }

pagetype :
| LPAR PAGESIZE NAT RPAR
{ let v' =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can simplify this using the nat32 helper and Lib.Int.is_power_of_two, cf. the action for the align production.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using power_of_two now, will rework for nat32.

try (int_of_string $3)
with Failure _ ->
error (at $sloc) "invalid custom page size"
in
if not (v' > 0 && Lib.Int.is_power_of_two v') then
error (at $sloc) "invalid custom page size";
PageT v'
}

memorytype :
| addrtype limits { fun c -> MemoryT ($1, $2, PageT 0x10000) }
| addrtype limits pagetype { fun c -> MemoryT ($1, $2, $3) }

limits :
| NAT { {min = nat64 $1 $loc($1); max = None} }
Expand Down Expand Up @@ -1126,15 +1140,19 @@ memory_fields :
| inline_export memory_fields /* Sugar */
{ fun c x loc -> let mems, data, ims, exs = $2 c x loc in
mems, data, ims, $1 (MemoryX x) c :: exs }
| addrtype LPAR DATA string_list RPAR /* Sugar */
| addrtype pagetype LPAR DATA string_list RPAR /* Sugar */
{ fun c x loc ->
let size = Int64.(div (add (of_int (String.length $4)) 65535L) 65536L) in
let len64 = Int64.of_int (String.length $5) in
let size =
match $2 with
| PageT 0 -> len64 (* will be a validation error *)
| PageT 1 -> len64
| PageT ps -> Int64.(div (add len64 (sub (of_int ps) 1L)) (of_int ps)) in
let offset = [at_const $1 (0L @@ loc) @@ loc] @@ loc in
[Memory (MemoryT ($1, {min = size; max = Some size}, PageT 0x10000)) @@ loc],
[Data ($4, Active (x, offset) @@ loc) @@ loc],
[Memory (MemoryT ($1, {min = size; max = Some size}, $2)) @@ loc],
[Data ($5, Active (x, offset) @@ loc) @@ loc],
[], [] }


elemkind :
| FUNC { (NoNull, FuncHT) }

Expand Down
18 changes: 12 additions & 6 deletions interpreter/valid/valid.ml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ let check_limits {min; max} range at msg =
"size minimum must not be greater than maximum"

let check_pagetype (PageT ps) at =
require (ps = 0x10000 || ps = 1) at "page size must be 1 or 64KiB"
require (ps = 0x10000 || ps = 1) at "invalid custom page size"

let check_numtype (c : context) (t : numtype) at =
()
Expand Down Expand Up @@ -200,13 +200,19 @@ let check_globaltype (c : context) (gt : globaltype) at =

let check_memorytype (c : context) (mt : memorytype) at =
let MemoryT (at_, lim, pt) = mt in
check_pagetype pt at;
let sz, s =
match at_ with
| I32AT -> 0x1_0000L, "2^16 pages (4 GiB) for i32"
| I64AT -> 0x1_0000_0000_0000L, "2^48 pages (256 TiB) for i64"
match pt with
| PageT 0x10000 ->
(match at_ with
| I32AT -> 0x1_0000L, "2^16 pages (4 GiB) for i32"
| I64AT -> 0x1_0000_0000_0000L, "2^48 pages (256 TiB) for i64")
| _ -> (* TODO: divide by page size, what about error msg? *)
(match at_ with
| I32AT -> 0xFFFF_FFFFL, "2^32 - 1 bytes for i32"
| I64AT -> 0xFFFF_FFFF_FFFF_FFFFL, "2^64 - 1 bytes for i64")
in
check_limits lim sz at ("memory size must be at most " ^ s);
check_pagetype pt at
check_limits lim sz at ("memory size must be at most " ^ s)

let check_tabletype (c : context) (tt : tabletype) at =
let TableT (at_, lim, t) = tt in
Expand Down
2 changes: 1 addition & 1 deletion test/core/custom-page-sizes/custom-page-sizes.wast
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
;; Inline data segments

;; pagesize 0
(assert_malformed (module quote "(memory (pagesize 0) (data))") "invalid custom page size")
(assert_malformed (module quote "(module (memory (pagesize 0) (data)))") "invalid custom page size")

;; pagesize 1
(module
Expand Down
16 changes: 14 additions & 2 deletions test/core/custom-page-sizes/memory_max.wast
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,26 @@
(module
(import "test" "unknown" (func))
(memory 0xFFFF_FFFF (pagesize 1)))
"unknown import")
"incompatible import type")

;; i32 (pagesize 1)
(assert_unlinkable
(module
(import "test" "unknown" (memory 0xFFFF_FFFF (pagesize 1))))
"incompatible import type")

;; i32 (default pagesize)
(assert_unlinkable
(module
(import "test" "unknown" (func))
(memory 65536 (pagesize 65536)))
"unknown import")
"incompatible import type")

;; i32 (default pagesize)
(assert_unlinkable
(module
(import "test" "unknown" (memory 65536 (pagesize 65536))))
"incompatible import type")

;; Memory size just over the maximum.

Expand Down
20 changes: 16 additions & 4 deletions test/core/custom-page-sizes/memory_max_i64.wast
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,28 @@
;; i64 (pagesize 1)
(assert_unlinkable
(module
(import "test" "import" (func))
(import "test" "unknown" (func))
(memory i64 0xFFFF_FFFF_FFFF_FFFF (pagesize 1)))
"unknown import")
"incompatible import type")

;; i64 (pagesize 1)
(assert_unlinkable
(module
(import "test" "unknown" (memory i64 0xFFFF_FFFF_FFFF_FFFF (pagesize 1))))
"incompatible import type")

;; i64 (default pagesize)
(assert_unlinkable
(module
(import "test" "unknown" (func))
(memory i64 0x1_0000_0000_0000 (pagesize 65536)))
"unknown import")
"incompatible import type")

;; i64 (default pagesize)
(assert_unlinkable
(module
(import "test" "unknown" (memory i64 0x1_0000_0000_0000 (pagesize 65536))))
"incompatible import type")

;; Memory size just over the maximum.
;;
Expand All @@ -36,7 +48,7 @@
;; i64 (pagesize 1)
(assert_malformed
(module quote "(memory i64 0x1_0000_0000_0000_0000 (pagesize 1))")
"constant out of range")
"i64 constant out of range")

;; i64 (default pagesize)
(assert_invalid
Expand Down