2 * Copyright (c) Facebook, Inc. and its affiliates.
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the "hack" directory of this source tree.
13 module Logic
= Ifc_logic
14 module Utils
= Ifc_utils
15 module T
= Typing_defs
17 let comma_sep fmt
() = fprintf fmt
",@ "
19 let blank_sep fmt
() = fprintf fmt
"@ "
21 let newline_sep fmt
() = fprintf fmt
"@,"
23 let rec list pp_sep pp fmt
= function
25 | [x
] -> fprintf fmt
"%a" pp x
26 | x
:: xs
-> fprintf fmt
"%a%a%a" pp x pp_sep
() (list pp_sep pp
) xs
28 let smap pp_sep pp fmt map
=
29 let prop_pol fmt
(prop
, pol
) = fprintf fmt
"%s=%a" prop pp pol
in
30 list pp_sep
prop_pol fmt
(SMap.bindings map
)
32 let option pp fmt opt
=
34 | Some x
-> fprintf fmt
"%a" pp x
35 | None
-> fprintf fmt
"None"
37 let show_policy = function
40 | Ppurpose
(_
, p
) -> p
41 | Pfree_var
(v
, _s
) -> v
42 | Pbound_var n
-> Printf.sprintf
"<bound%d>" n
44 let policy fmt p
= fprintf fmt
"%s" (show_policy p
)
46 let array_kind fmt
= function
47 | Avec
-> fprintf fmt
"vec"
48 | Adict
-> fprintf fmt
"dict"
49 | Akeyset
-> fprintf fmt
"keyset"
51 let rec ptype fmt ty
=
53 let pp_sep fmt
() = fprintf fmt
"%s@ " sep
in
54 fprintf fmt
"(@[<hov2>%a@])" (list pp_sep ptype) l
59 fprintf fmt
"<%a>" policy p
60 | Ttuple tl
-> list'
"," tl
61 | Tunion
[] -> fprintf fmt
"nothing"
62 | Tunion tl
-> list'
" |" tl
63 | Tinter tl
-> list'
" &" tl
64 | Tclass
{ c_name
; c_self
; c_lump
} ->
65 fprintf fmt
"%s<@[<hov2>%a,@ %a@]>" c_name
policy c_self
policy c_lump
66 | Tfun fn
-> fun_ fmt fn
67 | Tcow_array
{ a_key
; a_value
; a_length
; a_kind
} ->
68 fprintf fmt
"%a" array_kind a_kind
;
69 fprintf fmt
"<%a => %a; |%a|>" ptype a_key
ptype a_value
policy a_length
72 if f
.sft_optional
then fprintf fmt
"?";
76 Nast.ShapeMap.pp
field fmt m
;
78 | T.Closed_shape
-> fprintf fmt
")"
79 | T.Open_shape
-> fprintf fmt
", ...)")
81 (* Format: <pc, self>(arg1, arg2, ...): ret [exn] *)
83 fprintf fmt
"<%a, %a>" policy fn
.f_pc
policy fn
.f_self
;
84 fprintf fmt
"(@[<hov>%a@])" (list comma_sep ptype) fn
.f_args
;
85 fprintf fmt
":@ %a [%a]" ptype fn
.f_ret
ptype fn
.f_exn
87 let fun_proto fmt fp
=
88 Option.iter ~f
:(fprintf fmt
"(this: %a)->" ptype) fp
.fp_this
;
89 fprintf fmt
"%s%a" fp
.fp_name fun_ fp
.fp_type
92 let is_symmetric = function
93 | (Cflow
(_
, a
, b
), Cflow
(_
, c
, d
)) -> equal_policy a d
&& equal_policy b c
97 if Policy.compare a b
<= 0 then
102 let rec conjuncts = function
103 | Cconj
((Cflow
(_
, a
, b
) as f1
), Cconj
((Cflow _
as f2
), prop))
104 when is_symmetric (f1
, f2
) ->
105 equate a b
:: conjuncts prop
106 | Cconj
((Cflow
(_
, a
, b
) as f1
), (Cflow _
as f2
)) when is_symmetric (f1
, f2
)
109 | Cconj
(cl
, cr
) -> conjuncts cl
@ conjuncts cr
116 | 'z'
:: n
-> 'a'
:: f n
117 | c
:: n
-> Char.(of_int_exn
(1 + to_int c
)) :: n
119 (fun i
-> String.of_char_list
(Utils.funpow i ~
f ~init
:[]))
121 let pp_policy b fmt
= function
122 | Pbound_var n
-> fprintf fmt
"%s" (bv (b
- n
))
126 let pol = pp_policy b
in
128 | [] -> fprintf fmt
"True"
129 | [`q
(p1
, p2
)] -> fprintf fmt
"%a = %a" pol p1
pol p2
130 | [`c
(Cflow
(_
, p1
, p2
))] -> fprintf fmt
"%a < %a" pol p1
pol p2
131 | [`c
(Cquant
(q
, n
, c
))] ->
134 "@[<hov2>%s @[<h>%a@].@ %a@]"
136 | Qexists
-> "exists"
137 | Qforall
-> "forall")
138 (list blank_sep pp_print_string
)
142 ~
f:(fun (i
, l
) -> (i
+ 1, l
@ [bv i
]))
146 | [`c
(Ccond
((_
, p
, x
), ct
, ce
))] ->
147 fprintf fmt
"@[<hov>if %a < %s@" pol p x
;
148 let cct = conjuncts ct
in
149 let cce = conjuncts ce
in
150 fprintf fmt
"then %a@ else %a@]" (aux b
) cct (aux b
) cce
151 | [`c
(Chole
(_
, fp
))] -> fprintf fmt
"@[<h>{%a}@]" fun_proto fp
153 let pp = list comma_sep (fun fmt c
-> aux b fmt
[c
]) in
154 fprintf fmt
"@[<hov>%a@]" pp l
156 (fun fmt c
-> aux 0 fmt
(conjuncts c
))
160 fprintf fmt
"@[<hov2>%a@]" (LMap.make_pp
Local_id.pp ptype) k
.k_vars
;
161 let policy_set fmt s
= list comma_sep policy fmt
(PSet.elements s
) in
162 if not
(PSet.is_empty k
.k_pc
) then
163 fprintf fmt
"@,@[<hov2>pc: @[<hov>%a@]@]" policy_set k
.k_pc
;
168 fprintf fmt
"* @[<hov2>pc: @[<hov>%a@]@]" policy renv.re_gpc
;
169 fprintf fmt
"@,* @[<hov2>This:@ @[<hov>%a@]@]" (option ptype) renv.re_this
;
170 fprintf fmt
"@,* @[<hov2>Return:@ @[<hov>%a@]@]" ptype renv.re_ret
;
171 fprintf fmt
"@,* @[<hov2>Exception: @[<hov>%a@]@]" ptype renv.re_exn
;
175 let rec flatten = function
176 | Cconj
(p1
, p2
) -> flatten p1
@ flatten p2
179 let rec group_by_line =
180 let has_same_pos p1 p2
=
181 Option.equal
Pos.equal
(unique_pos_of_prop p1
) (unique_pos_of_prop p2
)
186 let (group
, rest
) = List.partition_tf ~
f:(has_same_pos prop) props
in
187 let pos_opt = unique_pos_of_prop
prop in
188 let prop = Logic.conjoin
(prop :: group
) in
189 (pos_opt, prop) :: group_by_line rest
191 let group fmt
(pos_opt, p
) =
193 | Some pos
-> fprintf fmt
"@[<hov2>%a@ %a@]" Pos.pp pos
prop p
194 | None
-> fprintf fmt
"@[<hov2>[no pos]@ %a@]" prop p
196 let groups = list newline_sep group in
199 fprintf fmt
"@[<hov2>Deps:@ %a@]" SSet.pp (Env.get_deps
env);
200 let props = List.concat_map ~
f:flatten (Env.get_constraints
env) in
202 let compare (pos1
, _
) (pos2
, _
) = Option.compare Pos.compare pos1 pos2
in
203 group_by_line props |> List.sort ~
compare
205 fprintf fmt
"@,Constraints:@, @[<v>%a@]" groups prop_groups;
208 let class_decl fmt
{ cd_policied_properties
= props; _
} =
209 let policied_property fmt
{ pp_name
; pp_purpose
; _
} =
210 fprintf fmt
"%s:%s" pp_name pp_purpose
212 let properties fmt
= list comma_sep policied_property fmt
in
213 fprintf fmt
"{ policied_props = [@[<hov>%a@]] }" properties props
215 let fun_decl fmt decl
=
217 match decl
.fd_kind
with
218 | FDPolicied
(Some
policy) -> show_policy policy
219 | FDPolicied None
-> "implicit"
220 | FDInferFlows
-> "infer"
222 fprintf fmt
"{ kind = %s }" kind
224 let decl_env fmt de
=
225 let handle_class name decl
=
226 fprintf fmt
"class %s: %a@ " name
class_decl decl
228 fprintf fmt
"Decls:@. @[<v>";
229 let handle_fun name decl
=
230 fprintf fmt
"function %s: %a@ " name
fun_decl decl
232 SMap.iter
handle_class de
.de_class
;
233 SMap.iter
handle_fun de
.de_fun
;
236 let implicit_violation fmt
(l
, r
) =
239 "Data with an implicit policy is leaked by %a in context %a."
245 let security_lattice fmt lattice
=
246 let flow fmt
(l
, r
) = fprintf fmt
"%a < %a" policy l
policy r
in
247 let flows = FlowSet.elements lattice
in
248 fprintf fmt
"{%a}" (list comma_sep flow) flows