1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
(* SPDX-License-Identifier: AGPL-3.0-or-later *)
(* Copyright © 2021-2026 OCamlPro *)
(* Written by the Owi programmers *)

open Bos
open Syntax

let run_file ~parameters ~source_file =
  let { Symbolic_parameters.unsafe
      ; entry_point
      ; invoke_with_symbols
      ; exploration_strategy = _
      ; _
      } =
    parameters
  in
  let* modul = Compile.File.until_validate ~unsafe source_file in
  (* TODO: enable this once the smart strategy is fully implemented
  ( match exploration_strategy with
  | Smart -> Cmd_call_graph.compute_distances m entry_point
  | _ -> () );
  *)
  let* modul =
    Cmd_utils.set_entry_point entry_point invoke_with_symbols modul
  in

  let* abstract_invariant =
    if parameters.generate_abstract_invariant then
      let* env = Cmd_wasm_abs.env () in
      let+ modul, env =
        Compile.Binary.until_abstract_link ~unsafe ~name:None env modul
      in
      try
        let state = Abstract_interpreter_control_flow.modul ~env ~modul in
        state.invariant
      with Abstract_interpreter_control_flow.RecursiveFunctionCall ->
        Abstract_invariant.empty ()
    else Ok (Abstract_invariant.empty ())
  in

  let env = Env.Symbolic.empty ~context:() in
  let* env =
    Env.Symbolic.link_extern_module ~env ~name:"wasi_snapshot_preview1"
      Symbolic_wasm_ffi.wasi_snapshot_preview1
  in
  let* env =
    Env.Symbolic.link_extern_module ~env ~name:"owi" Symbolic_wasm_ffi.owi
  in
  let+ modul, env =
    (* unsafe is set to true because the module was already validated before *)
    Compile.Binary.until_symbolic_link env ~unsafe:true ~name:None modul
  in
  let module Parameters = struct
    let throw_away_trap =
      match parameters.fail_mode with
      | Assertion_only -> true
      | Both | Trap_only -> false

    let timeout = parameters.timeout

    let timeout_instr = parameters.timeout_instr

    let use_ite_for_select = parameters.use_ite_for_select

    let abstract_invariant = abstract_invariant
  end in
  let module I = Interpret.Symbolic (Parameters) in
  Benchmark.with_utime @@ fun () -> I.modul ~env ~modul

(* NB: This function propagates potential errors (Result.err) occurring
             during evaluation (OS, syntax error, etc.), except for Trap and Assert,
             which are handled here. Most of the computations are done in the Result
             monad, hence the let*. *)
let cmd ~parameters ~source_file =
  let { Symbolic_parameters.exploration_strategy
      ; fail_mode
      ; workers
      ; no_worker_isolation
      ; solver
      ; deterministic_result_order
      ; model_format
      ; no_value
      ; no_assert_failure_expression_printing
      ; seed
      ; workspace
      ; model_out_file
      ; with_breadcrumbs
      ; _
      } =
    parameters
  in

  (* deterministic_result_order implies no_stop_at_failure *)
  let no_stop_at_failure =
    parameters.deterministic_result_order || parameters.no_stop_at_failure
  in

  (* TODO: can we handle this at the cmdliner level? *)
  let* workspace =
    match workspace with
    | Some path -> Ok path
    | None -> OS.Dir.tmp "owi_sym_%s"
  in

  let* to_run, run_time = run_file ~parameters ~source_file in

  Symbolic_driver.run ~exploration_strategy ~fail_mode ~workers
    ~no_worker_isolation ~solver ~deterministic_result_order ~model_format
    ~no_value ~no_assert_failure_expression_printing ~workspace
    ~no_stop_at_failure ~model_out_file ~with_breadcrumbs ~seed ~run_time to_run