comparison src/iflow.sml @ 1202:509a6d7b60fb

Iflow tested with positive and negative cases
author Adam Chlipala <adamc@hcoop.net>
date Sun, 04 Apr 2010 16:17:23 -0400
parents 8793fd48968c
children a75c66dd2aeb
comparison
equal deleted inserted replaced
1201:8793fd48968c 1202:509a6d7b60fb
27 27
28 structure Iflow :> IFLOW = struct 28 structure Iflow :> IFLOW = struct
29 29
30 open Mono 30 open Mono
31 31
32 structure IM = IntBinaryMap
33
32 structure SS = BinarySetFn(struct 34 structure SS = BinarySetFn(struct
33 type ord_key = string 35 type ord_key = string
34 val compare = String.compare 36 val compare = String.compare
35 end) 37 end)
36 38
73 | Or of prop * prop 75 | Or of prop * prop
74 | Reln of reln * exp list 76 | Reln of reln * exp list
75 | Select of int * lvar * lvar * prop * exp 77 | Select of int * lvar * lvar * prop * exp
76 78
77 local 79 local
78 val count = ref 0 80 val count = ref 1
79 in 81 in
80 fun newLvar () = 82 fun newLvar () =
81 let 83 let
82 val n = !count 84 val n = !count
83 in 85 in
113 | Reln (r, es) => Reln (r, map (subExp (v, lv)) es) 115 | Reln (r, es) => Reln (r, map (subExp (v, lv)) es)
114 | Select (v1, lv1, lv2, p, e) => Select (v1, lv1, lv2, sub p, subExp (v, lv) e) 116 | Select (v1, lv1, lv2, p, e) => Select (v1, lv1, lv2, sub p, subExp (v, lv) e)
115 in 117 in
116 sub 118 sub
117 end 119 end
118
119 fun eq' (e1, e2) =
120 case (e1, e2) of
121 (Const p1, Const p2) => Prim.equal (p1, p2)
122 | (Var n1, Var n2) => n1 = n2
123 | (Lvar n1, Lvar n2) => n1 = n2
124 | (Func (f1, es1), Func (f2, es2)) => f1 = f2 andalso ListPair.allEq eq' (es1, es2)
125 | (Recd xes1, Recd xes2) => ListPair.allEq (fn ((x1, e1), (x2, e2)) => x1 = x2 andalso eq' (e1, e2)) (xes1, xes2)
126 | (Proj (e1, s1), Proj (e2, s2)) => eq' (e1, e2) andalso s1 = s2
127 | (Finish, Finish) => true
128 | _ => false
129 120
130 fun isKnown e = 121 fun isKnown e =
131 case e of 122 case e of
132 Const _ => true 123 Const _ => true
133 | Func (_, es) => List.all isKnown es 124 | Func (_, es) => List.all isKnown es
172 Finish 163 Finish
173 else 164 else
174 Proj (e', s)) 165 Proj (e', s))
175 | Finish => Finish 166 | Finish => Finish
176 167
177 fun eq (e1, e2) = eq' (simplify e1, simplify e2) 168 fun decomp fals or =
178
179 fun decomp or =
180 let 169 let
181 fun decomp p k = 170 fun decomp p k =
182 case p of 171 case p of
183 True => k [] 172 True => k []
184 | False => true 173 | False => fals
185 | Unknown => k [] 174 | Unknown => k []
186 | And (p1, p2) => 175 | And (p1, p2) =>
187 decomp p1 (fn ps1 => 176 decomp p1 (fn ps1 =>
188 decomp p2 (fn ps2 => 177 decomp p2 (fn ps2 =>
189 k (ps1 @ ps2))) 178 k (ps1 @ ps2)))
193 | Select _ => k [] 182 | Select _ => k []
194 in 183 in
195 decomp 184 decomp
196 end 185 end
197 186
198 fun rimp ((r1 : reln, es1), (r2, es2)) = 187 val unif = ref (IM.empty : exp IM.map)
199 r1 = r2 andalso ListPair.allEq eq (es1, es2) 188
200 189 fun lvarIn lv =
201 fun imp (p1, p2) = 190 let
202 decomp (fn (e1, e2) => e1 andalso e2 ()) p1 191 fun lvi e =
203 (fn hyps => 192 case e of
204 decomp (fn (e1, e2) => e1 orelse e2 ()) p2 193 Const _ => false
205 (fn goals => 194 | Var _ => false
206 List.all (fn r2 => List.exists (fn r1 => rimp (r1, r2)) hyps) goals)) 195 | Lvar lv' => lv' = lv
196 | Func (_, es) => List.exists lvi es
197 | Recd xes => List.exists (lvi o #2) xes
198 | Proj (e, _) => lvi e
199 | Finish => false
200 in
201 lvi
202 end
203
204 fun eq' (e1, e2) =
205 case (e1, e2) of
206 (Const p1, Const p2) => Prim.equal (p1, p2)
207 | (Var n1, Var n2) => n1 = n2
208
209 | (Lvar n1, _) =>
210 (case IM.find (!unif, n1) of
211 SOME e1 => eq' (e1, e2)
212 | NONE =>
213 case e2 of
214 Lvar n2 =>
215 (case IM.find (!unif, n2) of
216 SOME e2 => eq' (e1, e2)
217 | NONE => n1 = n2
218 orelse (unif := IM.insert (!unif, n1, e2);
219 true))
220 | _ =>
221 if lvarIn n1 e2 then
222 false
223 else
224 (unif := IM.insert (!unif, n1, e2);
225 true))
226
227 | (_, Lvar n2) =>
228 (case IM.find (!unif, n2) of
229 SOME e2 => eq' (e1, e2)
230 | NONE =>
231 if lvarIn n2 e1 then
232 false
233 else
234 (unif := IM.insert (!unif, n2, e1);
235 true))
236
237 | (Func (f1, es1), Func (f2, es2)) => f1 = f2 andalso ListPair.allEq eq' (es1, es2)
238 | (Recd xes1, Recd xes2) => ListPair.allEq (fn ((x1, e1), (x2, e2)) => x1 = x2 andalso eq' (e1, e2)) (xes1, xes2)
239 | (Proj (e1, s1), Proj (e2, s2)) => eq' (e1, e2) andalso s1 = s2
240 | (Finish, Finish) => true
241 | _ => false
242
243 fun eq (e1, e2) =
244 let
245 val saved = !unif
246 in
247 if eq' (simplify e1, simplify e2) then
248 true
249 else
250 (unif := saved;
251 false)
252 end
253
254 exception Imply of prop * prop
255
256 fun rimp ((r1, es1), (r2, es2)) =
257 case (r1, r2) of
258 (Sql r1', Sql r2') =>
259 r1' = r2' andalso
260 (case (es1, es2) of
261 ([Recd xes1], [Recd xes2]) =>
262 let
263 val saved = !unif
264 in
265 (*print ("Go: " ^ r1' ^ "\n");*)
266 (*raise Imply (Reln (r1, es1), Reln (r2, es2));*)
267 if List.all (fn (f, e2) =>
268 List.exists (fn (f', e1) =>
269 f' = f andalso eq (e1, e2)) xes1) xes2 then
270 true
271 else
272 (unif := saved;
273 false)
274 end
275 | _ => false)
276 | (Eq, Eq) =>
277 (case (es1, es2) of
278 ([x1, y1], [x2, y2]) =>
279 let
280 val saved = !unif
281 in
282 if eq (x1, x2) andalso eq (y1, y2) then
283 true
284 else
285 (unif := saved;
286 (*raise Imply (Reln (Eq, es1), Reln (Eq, es2));*)
287 eq (x1, y2) andalso eq (y1, x2))
288 end
289 | _ => false)
290 | _ => false
291
292 fun imply (p1, p2) =
293 (unif := IM.empty;
294 (*raise (Imply (p1, p2));*)
295 decomp true (fn (e1, e2) => e1 andalso e2 ()) p1
296 (fn hyps =>
297 decomp false (fn (e1, e2) => e1 orelse e2 ()) p2
298 (fn goals =>
299 let
300 fun gls goals onFail =
301 case goals of
302 [] => true
303 | g :: goals =>
304 let
305 fun hps hyps =
306 case hyps of
307 [] => onFail ()
308 | h :: hyps =>
309 let
310 val saved = !unif
311 in
312 if rimp (h, g) then
313 let
314 val changed = IM.numItems (!unif) = IM.numItems saved
315 in
316 gls goals (fn () => (unif := saved;
317 changed andalso hps hyps))
318 end
319 else
320 hps hyps
321 end
322 in
323 hps hyps
324 end
325 in
326 gls goals (fn () => false)
327 end)))
328
207 329
208 fun patCon pc = 330 fun patCon pc =
209 case pc of 331 case pc of
210 PConVar n => "C" ^ Int.toString n 332 PConVar n => "C" ^ Int.toString n
211 | PConFfi {mod = m, datatyp = d, con = c, ...} => m ^ "." ^ d ^ "." ^ c 333 | PConFfi {mod = m, datatyp = d, con = c, ...} => m ^ "." ^ d ^ "." ^ c
212 334
213 exception Summaries of (string * exp * prop * (exp * prop) list) list 335
214 336
215 datatype chunk = 337 datatype chunk =
216 String of string 338 String of string
217 | Exp of Mono.exp 339 | Exp of Mono.exp
218 340
224 346
225 type 'a parser = chunk list -> ('a * chunk list) option 347 type 'a parser = chunk list -> ('a * chunk list) option
226 348
227 fun always v chs = SOME (v, chs) 349 fun always v chs = SOME (v, chs)
228 350
229 fun parse p chs = 351 fun parse p s =
230 case p chs of 352 case p (chunkify s) of
231 SOME (v, []) => SOME v 353 SOME (v, []) => SOME v
232 | _ => NONE 354 | _ => NONE
233 355
234 fun const s chs = 356 fun const s chs =
235 case chs of 357 case chs of
323 (fn ((), ls) => ls) 445 (fn ((), ls) => ls)
324 446
325 val query = wrap (follow select from) 447 val query = wrap (follow select from)
326 (fn (fs, ts) => {Select = fs, From = ts}) 448 (fn (fs, ts) => {Select = fs, From = ts})
327 449
328 fun queryProp rv e = 450 fun queryProp rv oe e =
329 case parse query (chunkify e) of 451 case parse query e of
330 NONE => Unknown 452 NONE => Unknown
331 | SOME r => 453 | SOME r =>
332 foldl (fn ((t, v), p) => 454 let
333 And (p, 455 val p =
334 Reln (Sql t, 456 foldl (fn ((t, v), p) =>
335 [Recd (foldl (fn ((v', f), fs) => 457 And (p,
336 if v' = v then 458 Reln (Sql t,
337 (f, Proj (Proj (Lvar rv, v), f)) :: fs 459 [Recd (foldl (fn ((v', f), fs) =>
338 else 460 if v' = v then
339 fs) [] (#Select r))]))) 461 (f, Proj (Proj (Lvar rv, v), f)) :: fs
340 True (#From r) 462 else
341 463 fs) [] (#Select r))])))
342 fun evalExp env (e : Mono.exp, st as (nv, p, sent)) = 464 True (#From r)
465 in
466 case oe of
467 NONE => p
468 | SOME oe =>
469 And (p,
470 foldl (fn ((v, f), p) =>
471 Or (p,
472 Reln (Eq, [oe, Proj (Proj (Lvar rv, v), f)])))
473 False (#Select r))
474 end
475
476 fun evalExp env (e as (_, loc), st as (nv, p, sent)) =
343 let 477 let
344 fun default () = 478 fun default () =
345 (Var nv, (nv+1, p, sent)) 479 (Var nv, (nv+1, p, sent))
346 480
347 fun addSent (p, e, sent) = 481 fun addSent (p, e, sent) =
348 if isKnown e then 482 if isKnown e then
349 sent 483 sent
350 else 484 else
351 (e, p) :: sent 485 (loc, e, p) :: sent
352 in 486 in
353 case #1 e of 487 case #1 e of
354 EPrim p => (Const p, st) 488 EPrim p => (Const p, st)
355 | ERel n => (List.nth (env, n), st) 489 | ERel n => (List.nth (env, n), st)
356 | ENamed _ => default () 490 | ENamed _ => default ()
474 608
475 val (b, st') = evalExp (Var acc :: Var r :: env) (b, st') 609 val (b, st') = evalExp (Var acc :: Var r :: env) (b, st')
476 610
477 val r' = newLvar () 611 val r' = newLvar ()
478 val acc' = newLvar () 612 val acc' = newLvar ()
479 val qp = queryProp r' q 613 val qp = queryProp r' NONE q
480 614
481 val doSubExp = subExp (r, r') o subExp (acc, acc') 615 val doSubExp = subExp (r, r') o subExp (acc, acc')
482 val doSubProp = subProp (r, r') o subProp (acc, acc') 616 val doSubProp = subProp (r, r') o subProp (acc, acc')
483 617
484 val p = doSubProp (#2 st') 618 val p = doSubProp (#2 st')
485 val p = And (p, qp) 619 val p = And (p, qp)
486 val p = Select (r, r', acc', p, doSubExp b) 620 val p = Select (r, r', acc', p, doSubExp b)
487 in 621 in
488 (Var r, (#1 st + 1, And (#2 st, p), map (fn (e, p) => (doSubExp e, And (qp, doSubProp p))) (#3 st'))) 622 (Var r, (#1 st + 1, And (#2 st, p), map (fn (loc, e, p) => (loc,
623 doSubExp e,
624 And (qp, doSubProp p))) (#3 st')))
489 end 625 end
490 | EDml _ => default () 626 | EDml _ => default ()
491 | ENextval _ => default () 627 | ENextval _ => default ()
492 | ESetval _ => default () 628 | ESetval _ => default ()
493 629
502 | ESpawn _ => default () 638 | ESpawn _ => default ()
503 end 639 end
504 640
505 fun check file = 641 fun check file =
506 let 642 let
507 fun decl ((d, _), summaries) = 643 fun decl ((d, _), (vals, pols)) =
508 case d of 644 case d of
509 DVal (x, _, _, e, _) => 645 DVal (x, _, _, e, _) =>
510 let 646 let
511 fun deAbs (e, env, nv) = 647 fun deAbs (e, env, nv) =
512 case #1 e of 648 case #1 e of
513 EAbs (_, _, _, e) => deAbs (e, Var nv :: env, nv + 1) 649 EAbs (_, _, _, e) => deAbs (e, Var nv :: env, nv + 1)
514 | _ => (e, env, nv) 650 | _ => (e, env, nv)
515 651
516 val (e, env, nv) = deAbs (e, [], 0) 652 val (e, env, nv) = deAbs (e, [], 1)
517 653
518 val (e, (_, p, sent)) = evalExp env (e, (nv, True, [])) 654 val (e, (_, p, sent)) = evalExp env (e, (nv, True, []))
519 in 655 in
520 (x, e, p, sent) :: summaries 656 ((x, e, p, sent) :: vals, pols)
521 end 657 end
522 | _ => summaries 658
523 in 659 | DPolicy (PolQuery e) => (vals, queryProp 0 (SOME (Var 0)) e :: pols)
524 raise Summaries (foldl decl [] file) 660
661 | _ => (vals, pols)
662
663 val () = unif := IM.empty
664
665 val (vals, pols) = foldl decl ([], []) file
666 in
667 app (fn (name, _, _, sent) =>
668 app (fn (loc, e, p) =>
669 let
670 val p = And (p, Reln (Eq, [Var 0, e]))
671 in
672 if List.exists (fn pol => imply (p, pol)) pols then
673 ()
674 else
675 ErrorMsg.errorAt loc "The information flow policy may be violated here."
676 end) sent) vals
525 end 677 end
526 678
527 end 679 end