Skip to content

Commit 70eb1fd

Browse files
committed
some cleaning
1 parent 834349a commit 70eb1fd

File tree

16 files changed

+175
-133
lines changed

16 files changed

+175
-133
lines changed

dune-project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
(sedlex
7474
(>= 3.3))
7575
(smtml
76-
(>= 0.15.0))
76+
(>= 0.16.0))
7777
synchronizer
7878
(uutf
7979
(>= 1.0.3))

owi.opam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ depends: [
3838
"prelude" {>= "0.5"}
3939
"processor" {>= "0.2"}
4040
"sedlex" {>= "3.3"}
41-
"smtml" {>= "0.15.0"}
41+
"smtml" {>= "0.16.0"}
4242
"synchronizer"
4343
"uutf" {>= "1.0.3"}
4444
"xmlm" {>= "1.4.0"}

src/infra/benchmark.ml

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let empty_stats () =
1818
let handle_time_span atomic_span f =
1919
if Log.is_bench_enabled () then
2020
let counter = Mtime_clock.counter () in
21-
(* f is supposed to take a long time as it is calling the solver *)
21+
(* f is supposed to take a long time! *)
2222
let res = f () in
2323
let span = Mtime_clock.count counter in
2424
let rec atomic_set () =
@@ -44,7 +44,8 @@ let percentage ~whole ~self =
4444
let self = Mtime.Span.to_float_ns self in
4545
self /. whole *. 100.
4646

47-
let print_final ~bench_stats ~execution_time_a ~execution_time_b =
47+
let print_final ~bench_stats ~execution_time_a ~execution_time_b
48+
~wait_for_all_domains =
4849
let execution_time =
4950
(* execution time shouldn't be none in bench mode *)
5051
let execution_time_a =
@@ -100,14 +101,10 @@ let print_final ~bench_stats ~execution_time_a ~execution_time_b =
100101
solver_intermediate_model_time percentage );
101102

102103
Log.bench (fun m ->
103-
let percentage =
104-
let whole = Mtime.Span.to_float_ns execution_time in
105-
let interp = Mtime.Span.to_float_ns interpreter_time in
106-
interp /. whole *. 100.
107-
in
104+
let percentage = percentage ~whole:execution_time ~self:interpreter_time in
108105
m "interpreter loop time : %a (%.2G%%)" Mtime.Span.pp
109106
interpreter_time percentage );
110107
Log.bench (fun m -> m "path count: %d" (Atomic.get bench_stats.path_count));
111108

112-
let solver_stats = Solver.get_all_stats () in
109+
let solver_stats = Solver.get_all_stats ~wait_for_all_domains in
113110
Log.bench (fun m -> m "solver stats: %a" Solver.pp_stats solver_stats)

src/infra/log.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ include (val Logs.src_log main_src : Logs.LOG)
77
let is_bench_enabled () =
88
match Logs.Src.level bench_src with None -> false | Some _ -> true
99

10+
let is_info_enabled () =
11+
match Logs.Src.level main_src with
12+
| Some (Logs.Debug | Logs.Info) -> true
13+
| None | Some _ -> false
14+
1015
let bench_fn str fn =
1116
match Logs.Src.level bench_src with
1217
| None -> fn ()

src/infra/log.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ include Logs.LOG
22

33
val main_src : Logs.src
44

5+
val is_info_enabled : unit -> bool
6+
57
val is_bench_enabled : unit -> bool
68

79
val bench_fn : string -> (unit -> 'a) -> 'a

src/intf/symbolic_choice_intf.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ module type S = sig
7171
-> Smtml.Solver_type.t
7272
-> 'a t
7373
-> thread
74-
-> callback:(close:(unit -> unit) -> 'a eval * thread -> unit)
74+
-> callback:(close_work_queue:(unit -> unit) -> 'a eval * thread -> unit)
7575
-> callback_init:(unit -> unit)
7676
-> callback_end:(unit -> unit)
7777
-> unit Domain.t array

src/intf/work_ds_intf.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module type S = sig
1212
val push : 'a -> Prio.t -> 'a t -> unit
1313

1414
(** Make a new pledge, ie indicate that new elements may be pushed to the
15-
queue and that calls to pop should block waitting for them. *)
15+
queue and that calls to pop should block waiting for them. *)
1616
val make_pledge : 'a t -> unit
1717

1818
(** End one pledge. *)

src/symbolic/solver.ml

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,27 +27,35 @@ let check (S (solver_module, s)) pc =
2727
let module Solver = (val solver_module) in
2828
Solver.check_set s pc
2929

30-
let model_of_partition (S (solver_module, s)) ~partition : Smtml.Model.t =
30+
let model_of_path_condition (S (solver_module, s)) ~path_condition :
31+
Smtml.Model.t Option.t =
32+
let exception Unknown in
3133
let module Solver = (val solver_module) in
32-
let partition =
33-
List.map
34-
(fun pc ->
35-
match Solver.get_sat_model s pc with
36-
| `Model model -> model
37-
| `Unknown -> assert false
38-
| `Unsat -> assert false )
39-
partition
40-
in
41-
let model = Hashtbl.create 64 in
42-
List.iter
43-
(fun tbl -> Hashtbl.iter (fun sym v -> Hashtbl.add model sym v) tbl)
44-
partition;
45-
model
34+
try
35+
let sub_conditions = Symbolic_path_condition.slice path_condition in
36+
let models =
37+
List.map
38+
(fun pc ->
39+
match Solver.get_sat_model s pc with
40+
| `Model model -> model
41+
| `Unknown ->
42+
(* it can happen if the solver is interrupted, otherwise it is an error, we raise, so the function can return an option that will be handled by the called *)
43+
raise Unknown
44+
| `Unsat ->
45+
(* it can not happen otherwise it means we reached an unreachable branch (or added garbage to the PC and did something wrong, who knows... :-) *)
46+
assert false )
47+
sub_conditions
48+
in
49+
(* We build the new complete model by merging all "sub models" *)
50+
let model = Hashtbl.create 64 in
51+
List.iter (Hashtbl.iter (Hashtbl.add model)) models;
52+
Some model
53+
with Unknown -> None
4654

47-
let get_sat_model (S (solver_module, s)) ~symbol_scopes ~pc =
55+
let model_of_set (S (solver_module, s)) ~symbol_scopes ~set =
4856
let module Solver = (val solver_module) in
4957
let symbols = Symbol_scope.only_symbols symbol_scopes in
50-
Solver.get_sat_model ~symbols s pc
58+
Solver.get_sat_model ~symbols s set
5159

5260
let empty_stats = Smtml.Statistics.Map.empty
5361

@@ -61,9 +69,17 @@ let interrupt_all () =
6169
Solver.interrupt s )
6270
solvers
6371

64-
let get_all_stats () =
72+
let get_all_stats ~wait_for_all_domains =
6573
if not (Log.is_bench_enabled ()) then empty_stats
6674
else begin
75+
(* interrupt_all is unreliable but is a best effort to try to make sure we don't wait too long on really long requests.
76+
The reliable alternative would be to backup the statistics before each SMT request when in benchmark mode, but this would be too costly and lead to less accurate requests than random failures... *)
77+
interrupt_all ();
78+
(* we wait for all domains to terminate because:
79+
- some solvers can not be interrupted and usually don't like being asked for statistics while running
80+
- we already got all the previous metrics, so we don't care about waiting more... *)
81+
wait_for_all_domains ();
82+
6783
let solvers = Atomic.get instances in
6884
List.fold_left
6985
(fun stats_acc (S (solver_module, s)) ->
@@ -74,7 +90,7 @@ let get_all_stats () =
7490
Logs.warn (fun m ->
7591
m
7692
"could not fetch the statistics of one solver because it was \
77-
canceled" );
93+
canceled, used empty stats instead" );
7894
empty_stats
7995
in
8096
Smtml.Statistics.merge stats stats_acc )

src/symbolic/solver.mli

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,20 @@ val fresh : Smtml.Solver_type.t -> unit -> t
88

99
val check : t -> Smtml.Expr.Set.t -> [ `Sat | `Unknown | `Unsat ]
1010

11-
val get_sat_model :
11+
val model_of_set :
1212
t
1313
-> symbol_scopes:Symbol_scope.t
14-
-> pc:Smtml.Expr.Set.t
14+
-> set:Smtml.Expr.Set.t
1515
-> [ `Unsat | `Unknown | `Model of Smtml.Model.t ]
1616

17-
val model_of_partition : t -> partition:Smtml.Expr.Set.t list -> Smtml.Model.t
17+
val model_of_path_condition :
18+
t -> path_condition:Symbolic_path_condition.t -> Smtml.Model.t option
1819

1920
val empty_stats : Smtml.Statistics.t
2021

2122
val stats_are_empty : Smtml.Statistics.t -> bool
2223

2324
val pp_stats : Smtml.Statistics.t Fmt.t
2425

25-
val get_all_stats : unit -> Smtml.Statistics.t
26-
27-
val interrupt_all : unit -> unit
26+
val get_all_stats :
27+
wait_for_all_domains:(Unit.t -> Unit.t) -> Smtml.Statistics.t

src/symbolic/symbolic_choice.ml

Lines changed: 56 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -92,21 +92,21 @@ module CoreImpl = struct
9292
(fun f write_back -> handle_status (Schedulable.run f wls) write_back)
9393
sched.work_queue
9494

95-
let spawn_worker sched wls_init callback callback_init callback_close =
95+
let spawn_worker sched wls_init ~callback ~callback_init ~callback_end =
9696
callback_init ();
9797
Domain.spawn (fun () ->
98-
Fun.protect
99-
~finally:(fun () -> callback_close ())
100-
(fun () ->
101-
let wls = wls_init () in
102-
try
103-
work wls sched
104-
(callback ~close:(fun () ->
105-
Work_datastructure.close sched.work_queue ) )
106-
with e ->
107-
let bt = Printexc.get_raw_backtrace () in
108-
Work_datastructure.close sched.work_queue;
109-
Printexc.raise_with_backtrace e bt ) )
98+
let wls = wls_init () in
99+
Fun.protect ~finally:callback_end (fun () ->
100+
try
101+
work wls sched
102+
(callback ~close_work_queue:(fun () ->
103+
Work_datastructure.close sched.work_queue ) )
104+
with e ->
105+
let bt = Printexc.get_raw_backtrace () in
106+
(* TODO: I don't understand why we are closing the work queue if one worker dies...
107+
If I remove this line, nothing seens to go wrong with the tests... *)
108+
Work_datastructure.close sched.work_queue;
109+
Printexc.raise_with_backtrace e bt ) )
110110
end
111111

112112
module State = struct
@@ -256,7 +256,7 @@ module CoreImpl = struct
256256
-> Smtml.Solver_type.t
257257
-> 'a t
258258
-> thread
259-
-> callback:(close:(unit -> unit) -> 'a eval * thread -> unit)
259+
-> callback:(close_work_queue:(unit -> unit) -> 'a eval * thread -> unit)
260260
-> callback_init:(unit -> unit)
261261
-> callback_end:(unit -> unit)
262262
-> unit Domain.t array
@@ -314,19 +314,24 @@ module CoreImpl = struct
314314
add_init_task sched (State.run t thread);
315315
if workers > 1 then Logs_threaded.enable ();
316316
Array.init workers (fun _i ->
317-
spawn_worker sched (Solver.fresh solver) callback callback_init
318-
callback_end )
317+
spawn_worker sched (Solver.fresh solver) ~callback ~callback_init
318+
~callback_end )
319319

320320
let trap t =
321321
let* thread in
322322
let* solver in
323-
let pc = Thread.pc thread in
323+
let path_condition = Thread.pc thread in
324324
let symbol_scopes = Thread.symbol_scopes thread in
325325
let stats = Thread.bench_stats thread in
326-
let model =
326+
let* model =
327327
Benchmark.handle_time_span stats.solver_final_model_time @@ fun () ->
328-
let partition = Symbolic_path_condition.explode pc in
329-
Solver.model_of_partition solver ~partition
328+
match Solver.model_of_path_condition solver ~path_condition with
329+
| Some model -> return model
330+
| None ->
331+
(* It can happen when the solver is interrupted *)
332+
(* TODO: once https://github.com/formalsec/smtml/pull/479 is merged
333+
if solver was interrupted then stop else assert false *)
334+
stop
330335
in
331336
let labels = Thread.labels thread in
332337
let breadcrumbs = Thread.breadcrumbs thread in
@@ -358,7 +363,7 @@ module Make (Thread : Thread_intf.S) = struct
358363
let get_pc () =
359364
let+ thread in
360365
let pc = Thread.pc thread in
361-
let pc = Symbolic_path_condition.explode pc in
366+
let pc = Symbolic_path_condition.slice pc in
362367
List.fold_left Smtml.Expr.Set.union Smtml.Expr.Set.empty pc
363368

364369
let add_breadcrumb crumb =
@@ -396,26 +401,26 @@ module Make (Thread : Thread_intf.S) = struct
396401
let* () = yield prio in
397402
let* thread in
398403
let* solver in
399-
let pc = Thread.pc thread in
400-
let sliced_pc = Symbolic_path_condition.slice pc v in
404+
let pc = Thread.pc thread |> Symbolic_path_condition.slice_on_condition v in
401405
let stats = Thread.bench_stats thread in
402406
let reachability =
403407
Benchmark.handle_time_span stats.solver_sat_time @@ fun () ->
404-
Solver.check solver sliced_pc
408+
Solver.check solver pc
405409
in
406410
return reachability
407411

408412
let get_model_or_stop symbol =
409413
let* () = yield Prio.default in
410414
let* solver in
411-
let+ thread in
412-
let pc = Thread.pc thread in
413-
let pc = Symbolic_path_condition.slice_on_symbol pc symbol in
415+
let* thread in
416+
let set =
417+
Thread.pc thread |> Symbolic_path_condition.slice_on_symbol symbol
418+
in
414419
let stats = Thread.bench_stats thread in
415420
let symbol_scopes = Symbol_scope.of_symbol symbol in
416421
let sat_model =
417422
Benchmark.handle_time_span stats.solver_intermediate_model_time (fun () ->
418-
Solver.get_sat_model solver ~symbol_scopes ~pc )
423+
Solver.model_of_set solver ~symbol_scopes ~set )
419424
in
420425
match sat_model with
421426
| `Unsat -> stop
@@ -426,7 +431,11 @@ module Make (Thread : Thread_intf.S) = struct
426431
(* the model exists so the symbol should evaluate *)
427432
assert false
428433
end
429-
| `Unknown -> assert false
434+
| `Unknown ->
435+
(* It can happen when the solver is interrupted *)
436+
(* TODO: once https://github.com/formalsec/smtml/pull/479 is merged
437+
if solver was interrupted then stop else assert false *)
438+
stop
430439

431440
let select_inner ~explore_first ?(with_breadcrumbs = true)
432441
~check_only_true_branch (cond : Symbolic_boolean.t) ~prio_true ~prio_false =
@@ -460,6 +469,8 @@ module Make (Thread : Thread_intf.S) = struct
460469
stop
461470
| `Unknown ->
462471
(* It can happen when the solver is interrupted *)
472+
(* TODO: once https://github.com/formalsec/smtml/pull/479 is merged
473+
if solver was interrupted then stop else assert false *)
463474
stop
464475
end
465476
end
@@ -495,25 +506,27 @@ module Make (Thread : Thread_intf.S) = struct
495506
(Some assign, sym)
496507

497508
let select_i32 (i : Symbolic_i32.t) =
498-
let sym_int = Smtml.Expr.simplify i in
499-
match Smtml.Expr.view sym_int with
509+
let i = Smtml.Expr.simplify i in
510+
match Smtml.Expr.view i with
500511
| Val (Bitv bv) when Smtml.Bitvector.numbits bv <= 32 ->
501512
return (Smtml.Bitvector.to_int32 bv)
502513
| _ ->
503-
let* assign, symbol = summary_symbol sym_int in
514+
let* assign, symbol = summary_symbol i in
504515
let* () =
505516
match assign with Some assign -> add_pc assign | None -> return ()
506517
in
507518
let rec generator () =
508519
let* possible_value = get_model_or_stop symbol in
509-
let* possible_value in
510520
let i =
511521
match possible_value with
512522
| Smtml.Value.Bitv bv when Smtml.Bitvector.numbits bv <= 32 ->
513523
Smtml.Bitvector.to_int32 bv
514-
| _ -> Fmt.failwith "Unreachable: found symbol must be a value"
524+
| _ ->
525+
(* it should be a value! *)
526+
assert false
515527
in
516528
let s = Smtml.Expr.symbol symbol in
529+
(* TODO: everything which follows look like select_inner and could probably be simplified by calling it directly! *)
517530
let this_value_cond =
518531
let open Smtml.Expr in
519532
Bitv.I32.(s = v i)
@@ -548,13 +561,18 @@ module Make (Thread : Thread_intf.S) = struct
548561
else
549562
let* thread in
550563
let* solver in
551-
let pc = Thread.pc thread in
564+
let path_condition = Thread.pc thread in
552565
let symbol_scopes = Thread.symbol_scopes thread in
553566
let stats = Thread.bench_stats thread in
554-
let model =
567+
let* model =
555568
Benchmark.handle_time_span stats.solver_final_model_time @@ fun () ->
556-
let partition = Symbolic_path_condition.explode pc in
557-
Solver.model_of_partition solver ~partition
569+
match Solver.model_of_path_condition solver ~path_condition with
570+
| Some model -> return model
571+
| None ->
572+
(* It can happen when the solver is interrupted *)
573+
(* TODO: once https://github.com/formalsec/smtml/pull/479 is merged
574+
if solver was interrupted then stop else assert false *)
575+
stop
558576
in
559577
let breadcrumbs = Thread.breadcrumbs thread in
560578
let labels = Thread.labels thread in

0 commit comments

Comments
 (0)