Mercurial > urweb
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 |