Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow writing function contracts in webassembly code #407

Merged
merged 51 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
b1c607c
add custom annotations in ast and parser
Laplace-Demon Jul 18, 2024
0aa2bfb
add test for custom annotations
Laplace-Demon Jul 18, 2024
18bcfe1
remove misplaced test file
Laplace-Demon Jul 19, 2024
f75e388
simplify code
Laplace-Demon Jul 19, 2024
2e137e7
use string equality test instead of polymorphic one
Laplace-Demon Jul 19, 2024
7fabad7
add pretty-printer of annotations
Laplace-Demon Jul 19, 2024
9732b1d
Adopt to Prelude
Laplace-Demon Jul 23, 2024
dcecb0b
delete Fmt qualified name
Laplace-Demon Jul 23, 2024
f1c96d9
use hashmap to reord annotations
Laplace-Demon Jul 26, 2024
8fa8722
use s-expression to store annotations
Laplace-Demon Jul 27, 2024
2c6b5e6
add function contract annotations
Laplace-Demon Jul 29, 2024
ff2ec9c
replace let* with let+
Laplace-Demon Jul 29, 2024
18bb3e1
definition of function contracts
Laplace-Demon Jul 31, 2024
76d7b53
add custom section to binary module
Laplace-Demon Jul 31, 2024
240b77a
add function contracts as one kind of annotation, to be parsed either…
Laplace-Demon Aug 2, 2024
21b93f6
remove duplicate pattern
Laplace-Demon Aug 12, 2024
08c3699
parse function contract
Laplace-Demon Aug 12, 2024
9511220
add annotations to text_to_binary
Laplace-Demon Aug 12, 2024
7111a13
fix parser
Laplace-Demon Aug 12, 2024
3187bd8
delete quantified variable name in the process of rewrite
Laplace-Demon Aug 12, 2024
7f7f87b
better pretty printer
Laplace-Demon Aug 12, 2024
e4920d4
add unfinished test of spec
Laplace-Demon Aug 12, 2024
8885690
add rewriting for function parameters
Laplace-Demon Aug 13, 2024
8e916ab
small fixes
Laplace-Demon Aug 13, 2024
49909b7
fix
Laplace-Demon Aug 13, 2024
6c76976
rename Int32.to_string to Int32.to_string_exn
Laplace-Demon Aug 13, 2024
8b79776
replace optional arguments with labeled arguments in rewrite.ml
Laplace-Demon Aug 13, 2024
ea5d14f
allow nicer symbols to be parsed
Laplace-Demon Aug 13, 2024
8632890
deal with error when merging
Laplace-Demon Aug 13, 2024
574dc99
add cmdline option for code generation
Laplace-Demon Aug 13, 2024
fb31c05
add owi header
Laplace-Demon Aug 15, 2024
3b19c74
framework for rac code generation
Laplace-Demon Aug 18, 2024
81b0bf5
fix some tests by adding proper exceptions
Laplace-Demon Aug 21, 2024
ebf9a50
make rac a subcommand of owi
Laplace-Demon Aug 21, 2024
4e96795
promote some tests
Laplace-Demon Aug 21, 2024
77d1884
add 'unclosed annotation', 'unclosed comment' and 'unclosed string'
Laplace-Demon Aug 21, 2024
9aceccf
accomodate binary module simplification
Laplace-Demon Aug 22, 2024
5046234
fix
Laplace-Demon Aug 22, 2024
4c1795b
add bounded quantification
Laplace-Demon Aug 26, 2024
dbdd1a2
fix operator tests
Laplace-Demon Aug 27, 2024
873d937
add rac tests
Laplace-Demon Aug 27, 2024
4d547f6
rename rac to instrument
Laplace-Demon Aug 27, 2024
711790c
add option `--symbolic` to `owi instrument`
Laplace-Demon Aug 27, 2024
3517a43
add options --rac and --srac
Laplace-Demon Aug 27, 2024
4ed6c6e
remove unused owi functions
Laplace-Demon Aug 27, 2024
74fbb57
add memory instruction
Laplace-Demon Sep 2, 2024
e176356
changes.md
Laplace-Demon Sep 6, 2024
916ae44
add weasel example
Laplace-Demon Sep 6, 2024
681a2b4
readd owi run --rac
Laplace-Demon Sep 6, 2024
d0c7c95
link assert_i32 in cmd_run
Laplace-Demon Sep 6, 2024
f39e443
add assert.wat in test
Laplace-Demon Sep 17, 2024
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
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## unreleased

- add `owi instrument` to instrument Webassembly module annotated by Weasel specification language
- add `--srac` option to `sym` and `conc` cmd
- add `--rac` option to `run`, `sym` and `conc` cmd
- add `--output` option to `wat2wasm`, `wasm2wat` and `opt` cmd
- Change `free` prototype to now return a pointer on which tracking is deactivated
- add `--emit-file` option to `wasm2wat` to emit .wat files
Expand Down
4 changes: 4 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ COMMANDS
fmt [--inplace] [OPTION]… [ARG]…
Format a .wat or .wast file

instrument [--debug] [--symbolic] [--unsafe] [OPTION]… [ARG]…
Generate an instrumented file with runtime assertion checking
coming from Weasel specifications

opt [--debug] [--output=FILE] [--unsafe] [OPTION]… ARG
Optimize a module

Expand Down
6 changes: 6 additions & 0 deletions example/conc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,15 @@ OPTIONS
-p, --profiling
profiling mode

--rac
runtime assertion checking mode

-s VAL, --solver=VAL (absent=Z3)
SMT solver to use

--srac
symbolic runtime assertion checking mode

-u, --unsafe
skip typechecking pass

Expand Down
8 changes: 4 additions & 4 deletions example/define_host_function/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ let pure_wasm_module =
(* our pure wasm module, linked with `sausage` *)
let module_to_run, link_state =
match
Compile.Text.until_link link_state ~unsafe:false ~optimize:true ~name:None
pure_wasm_module
Compile.Text.until_link link_state ~unsafe:false ~rac:false ~srac:false
~optimize:true ~name:None pure_wasm_module
with
| Error _ -> assert false
| Ok v -> v
Expand Down Expand Up @@ -203,8 +203,8 @@ let pure_wasm_module =
(* our pure wasm module, linked with `chorizo` *)
let module_to_run, link_state =
match
Compile.Text.until_link link_state ~unsafe:false ~optimize:true ~name:None
pure_wasm_module
Compile.Text.until_link link_state ~unsafe:false ~rac:false ~srac:false
~optimize:true ~name:None pure_wasm_module
with
| Error _ -> assert false
| Ok v -> v
Expand Down
4 changes: 2 additions & 2 deletions example/define_host_function/extern.ml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ let pure_wasm_module =
(* our pure wasm module, linked with `sausage` *)
let module_to_run, link_state =
match
Compile.Text.until_link link_state ~unsafe:false ~optimize:true ~name:None
pure_wasm_module
Compile.Text.until_link link_state ~unsafe:false ~rac:false ~srac:false
~optimize:true ~name:None pure_wasm_module
with
| Error _ -> assert false
| Ok v -> v
Expand Down
4 changes: 2 additions & 2 deletions example/define_host_function/extern_mem.ml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ let pure_wasm_module =
(* our pure wasm module, linked with `chorizo` *)
let module_to_run, link_state =
match
Compile.Text.until_link link_state ~unsafe:false ~optimize:true ~name:None
pure_wasm_module
Compile.Text.until_link link_state ~unsafe:false ~rac:false ~srac:false
~optimize:true ~name:None pure_wasm_module
with
| Error _ -> assert false
| Ok v -> v
Expand Down
8 changes: 4 additions & 4 deletions example/define_host_function/life_game/life_console.ml
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ let pure_wasm_module_1 =
(* our first pure wasm module, linked with `life_ext` *)
let module_to_run, link_state =
match
Compile.Text.until_link link_state ~unsafe:false ~optimize:true
~name:(Some "life") pure_wasm_module_1
Compile.Text.until_link link_state ~unsafe:false ~rac:false ~srac:false
~optimize:true ~name:(Some "life") pure_wasm_module_1
with
| Error _ -> assert false
| Ok (m, state) -> (m, state)
Expand All @@ -85,8 +85,8 @@ let pure_wasm_module_2 =
(* our second pure wasm module, linked with `life_ext` and `life` interpreted before *)
let module_to_run, link_state =
match
Compile.Text.until_link link_state ~unsafe:false ~optimize:true ~name:None
pure_wasm_module_2
Compile.Text.until_link link_state ~unsafe:false ~rac:false ~srac:false
~optimize:true ~name:None pure_wasm_module_2
with
| Error _ -> assert false
| Ok (m, state) -> (m, state)
Expand Down
8 changes: 4 additions & 4 deletions example/define_host_function/life_game/life_graphics.ml
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ let pure_wasm_module_1 =
(* our first pure wasm module, linked with `life_ext` *)
let module_to_run, link_state =
match
Compile.Text.until_link link_state ~unsafe:false ~optimize:true
~name:(Some "life") pure_wasm_module_1
Compile.Text.until_link link_state ~unsafe:false ~rac:false ~srac:false
~optimize:true ~name:(Some "life") pure_wasm_module_1
with
| Error _ -> assert false
| Ok (m, state) -> (m, state)
Expand All @@ -97,8 +97,8 @@ let pure_wasm_module_2 =
(* our second pure wasm module, linked with `life_ext` and `life` interpreted before *)
let module_to_run, link_state =
match
Compile.Text.until_link link_state ~unsafe:false ~optimize:true ~name:None
pure_wasm_module_2
Compile.Text.until_link link_state ~unsafe:false ~rac:false ~srac:false
~optimize:true ~name:None pure_wasm_module_2
with
| Error _ -> assert false
| Ok (m, state) -> (m, state)
Expand Down
2 changes: 1 addition & 1 deletion example/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ val filename : Fpath.t = <abstr>
val m : Text.modul =
...
# let module_to_run, link_state =
match Compile.Text.until_link Link.empty_state ~unsafe:false ~optimize:false ~name:None m with
match Compile.Text.until_link Link.empty_state ~unsafe:false ~rac:false ~srac:false ~optimize:false ~name:None m with
| Ok v -> v
| Error _ -> assert false;;
val module_to_run : '_weak1 Link.module_to_run =
Expand Down
3 changes: 3 additions & 0 deletions example/run/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ OPTIONS
-p, --profiling
profiling mode

--rac
runtime assertion checking mode

-u, --unsafe
skip typechecking pass

Expand Down
6 changes: 6 additions & 0 deletions example/sym/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,15 @@ OPTIONS
-p, --profiling
profiling mode

--rac
runtime assertion checking mode

-s VAL, --solver=VAL (absent=Z3)
SMT solver to use

--srac
symbolic runtime assertion checking mode

-u, --unsafe
skip typechecking pass

Expand Down
138 changes: 138 additions & 0 deletions example/weasel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Weasel

Weasel stands for WEbAssembly Specification Language, it can be used to annotate Webassembly text modules in [custom annotation](https://github.com/WebAssembly/annotations). Annotated modules can be instrumented to perform runtime assertion checking thanks to owi's code generator.

Commands and options related to Weasel:
- `owi instrument` to instrument an annotated text module.
- `--rac` for `run`, `sym` and `conc` to instrument an annotated text module and perform runtime assertion checking.
- `--srac` for `sym` and `conc` to instrument an annotated text module and perform runtime assertion checking symbolically.

The formal specification of Weasel can be found in `src/annot/spec.ml`.

## Basic example

Suppose we have a function returning its parameter plus three:

```wast
(module
(;...;)
(func $plus_three (param $x i32) (result i32)
local.get $x
i32.const 3
i32.add
)
(;...;)
)
```

With Weasel, we can annotate this function by specifying its postconditions:

```wast
(module
(;...;)
(@contract $plus_three
(ensures (= result (+ $x 3)))
)
(func $plus_three (param $x i32) (result i32)
local.get $x
i32.const 3
i32.add
)
(;...;)
)
```

`owi instrument` generates a new wrapper function checking this postcondition:

```sh
$ owi instrument plus_three.wat
$ cat plus_three.instrumented.wat
(module
(import "symbolic" "assert" (func $assert (param i32)))
(type (sub final (func (param $x i32) (result i32))))
(type (sub final (func)))
(type (sub final (func (param i32))))
(type (sub final (func (result i32))))
(func $plus_three (param $x i32) (result i32)
local.get 0
i32.const 3
i32.add
)
(func $start
i32.const 42
call 3
drop
)
(func $__weasel_plus_three (param $x i32) (result i32) (local $__weasel_temp i32) (local $__weasel_res_0 i32)
local.get 0
call 1
local.set 2
local.get 2
local.get 0
i32.const 3
i32.add
i32.eq
call 0
local.get 2
)
(start 2)
)
```

We can perform runtime assertion checking either by `owi sym plus_three.instrumented.wat` or by `owi sym --rac plus_three.wat`.

```sh
$ owi sym plus_three.instrumented.wat
All OK
$ owi sym --rac plus_three.wat
All OK
```

## Man page

```sh
$ owi instrument --help=plain
NAME
owi-instrument - Generate an instrumented file with runtime assertion
checking coming from Weasel specifications

SYNOPSIS
owi instrument [--debug] [--symbolic] [--unsafe] [OPTION]… [ARG]…

OPTIONS
-d, --debug
debug mode

--symbolic
generate instrumented module that depends on symbolic execution

-u, --unsafe
skip typechecking pass

COMMON OPTIONS
--help[=FMT] (default=auto)
Show this help in format FMT. The value FMT must be one of auto,
pager, groff or plain. With auto, the format is pager or plain
whenever the TERM env var is dumb or undefined.

--version
Show version information.

EXIT STATUS
owi instrument exits with:

0 on success.

123 on indiscriminate errors reported on standard error.

124 on command line parsing errors.

125 on unexpected internal errors (bugs).

BUGS
Email them to <[email protected]>.

SEE ALSO
owi(1)

```
4 changes: 4 additions & 0 deletions example/weasel/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(mdx
(libraries owi)
(deps %{bin:owi} plus_three.wat plus_three.instrumented.wat)
(files README.md))
30 changes: 30 additions & 0 deletions example/weasel/plus_three.instrumented.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
(module
(import "symbolic" "assert" (func $assert (param i32)))
(type (sub final (func (param $x i32) (result i32))))
(type (sub final (func)))
(type (sub final (func (param i32))))
(type (sub final (func (result i32))))
(func $plus_three (param $x i32) (result i32)
local.get 0
i32.const 3
i32.add
)
(func $start
i32.const 42
call 3
drop
)
(func $__weasel_plus_three (param $x i32) (result i32) (local $__weasel_temp i32) (local $__weasel_res_0 i32)
local.get 0
call 1
local.set 2
local.get 2
local.get 0
i32.const 3
i32.add
i32.eq
call 0
local.get 2
)
(start 2)
)
16 changes: 16 additions & 0 deletions example/weasel/plus_three.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(module
(@contract $plus_three
(ensures (= result (+ $x 3)))
)
(func $plus_three (param $x i32) (result i32)
local.get $x
i32.const 3
i32.add
)
(func $start
i32.const 42
call $plus_three
drop
)
(start $start)
)
35 changes: 35 additions & 0 deletions src/annot/annot.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
(* SPDX-License-Identifier: AGPL-3.0-or-later *)
(* Copyright © 2021-2024 OCamlPro *)
(* Written by the Owi programmers *)

open Fmt

type t =
{ annotid : string
; items : Sexp.t
}

type 'a annot =
| Contract of 'a Contract.t
| Annot of t

let pp_annot fmt = function
| Contract contract ->
pf fmt "(@%a@\n @[<v>%a@]@\n)" string "contract" Contract.pp_contract
contract
| Annot annot ->
pf fmt "(@%a@\n @[<hv>%a@]@\n)" string annot.annotid Sexp.pp_sexp
annot.items

let annot_recorder : (string, Sexp.t) Hashtbl.t = Hashtbl.create 17

let record_annot annotid sexp = Hashtbl.add annot_recorder annotid sexp

let get_annots () =
let res =
Hashtbl.fold
(fun annotid items acc -> { annotid; items } :: acc)
annot_recorder []
in
Hashtbl.reset annot_recorder;
res
Loading
Loading