Skip to content

Commit 46e6454

Browse files
authored
Introduces context variables to the knowledge library (#1341)
1 parent ea79178 commit 46e6454

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

lib/knowledge/bap_knowledge.ml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,7 @@ module Knowledge = struct
20172017
type t = {
20182018
classes : objects Map.M(Name).t;
20192019
package : string;
2020+
context : Dict.t;
20202021
}
20212022
end
20222023

@@ -2026,6 +2027,7 @@ module Knowledge = struct
20262027
let empty : Env.t = {
20272028
package = user_package;
20282029
classes = Map.empty (module Name);
2030+
context = Dict.empty;
20292031
}
20302032

20312033
module State = struct
@@ -3037,6 +3039,39 @@ module Knowledge = struct
30373039
Map.to_sequence vals |>
30383040
Sequence.map ~f:fst
30393041

3042+
module Context = struct
3043+
type 'a var = {
3044+
nil : 'a knowledge;
3045+
key : 'a Dict.Key.t;
3046+
}
3047+
3048+
let declare ?(inspect=sexp_of_opaque) ?package name init =
3049+
let name = Name.create ?package name in {
3050+
nil = init;
3051+
key = Dict.Key.create ~name inspect;
3052+
}
3053+
3054+
let set {key} x = update @@ fun s -> {
3055+
s with context = Dict.set key x s.context
3056+
}
3057+
3058+
let get {key; nil} = get () >>= fun {context=s} ->
3059+
match Dict.find key s with
3060+
| None -> nil
3061+
| Some x -> !!x
3062+
3063+
let update v f =
3064+
get v >>= fun x ->
3065+
set v (f x)
3066+
3067+
let with_var v x f =
3068+
get v >>= fun x' ->
3069+
set v x >>= fun () ->
3070+
f () >>= fun r ->
3071+
set v x' >>| fun () ->
3072+
r
3073+
end
3074+
30403075
module Rule = struct
30413076
type def = Registry.def
30423077
type doc = Registry.doc

lib/knowledge/bap_knowledge.mli

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,57 @@ module Knowledge : sig
258258
val save : state -> string -> unit
259259

260260

261+
(** Context variables.
262+
263+
Context variables could be used to implement stateful
264+
analyses. They are not part of the knowledge base per se, but
265+
enable convience that is otherwise achieavable through adding a
266+
state to the knowledge monad using a monad transformer.
267+
268+
It is important to keep in mind that the contex variables are
269+
not a part of the knowledge and that every knowledge computation
270+
starts with a fresh set of variables, i.e., variables are not
271+
persistent.
272+
273+
The data type of the context variable is not required to have
274+
the domain structure or be comparable. The only requirement is
275+
that when a variable is declared it should be initialized.
276+
277+
@since 2.4.0
278+
279+
*)
280+
module Context : sig
281+
282+
283+
(** an abstract type denoting a context variable and its name. *)
284+
type 'a var
285+
286+
287+
(** [declare ~package name init] declares a new context variable.
288+
289+
The declared variable has the initial value [init]. The
290+
[inspect] function could be used for debugging and
291+
instrospection. *)
292+
val declare : ?inspect:('a -> Sexp.t) -> ?package:string -> string ->
293+
'a knowledge -> 'a var
294+
295+
(** [set v x] assings to the variable [v] a new value [x]. *)
296+
val set : 'a var -> 'a -> unit knowledge
297+
298+
(** [get v] is the current value assigned to [v]. *)
299+
val get : 'a var -> 'a knowledge
300+
301+
(** [update v f] applies [f] to the current value of [v] and
302+
assigns the result back.
303+
*)
304+
val update : 'a var -> ('a -> 'a) -> unit knowledge
305+
306+
307+
(** [with_var v x f] dynamically binds [v] to [x] while [f] is run.*)
308+
val with_var : 'a var -> 'a -> (unit -> 'b knowledge) -> 'b knowledge
309+
end
310+
311+
261312
(** prints the state of the knowledge base. *)
262313
val pp_state : Format.formatter -> state -> unit
263314

0 commit comments

Comments
 (0)