Mercurial > urweb
comparison src/iflow.sml @ 1236:d5ecceb7d1a1
Completely redid main Iflow logic; so far, policy and policy2 work
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Tue, 13 Apr 2010 16:30:46 -0400 |
parents | a7b773f1d053 |
children | a9c200f73f24 |
comparison
equal
deleted
inserted
replaced
1235:a7b773f1d053 | 1236:d5ecceb7d1a1 |
---|---|
70 | Var of int | 70 | Var of int |
71 | Lvar of lvar | 71 | Lvar of lvar |
72 | Func of func * exp list | 72 | Func of func * exp list |
73 | Recd of (string * exp) list | 73 | Recd of (string * exp) list |
74 | Proj of exp * string | 74 | Proj of exp * string |
75 | Finish | |
76 | 75 |
77 datatype reln = | 76 datatype reln = |
78 Known | 77 Known |
79 | Sql of string | 78 | Sql of string |
80 | PCon0 of string | 79 | PCon0 of string |
93 | And of prop * prop | 92 | And of prop * prop |
94 | Or of prop * prop | 93 | Or of prop * prop |
95 | Reln of reln * exp list | 94 | Reln of reln * exp list |
96 | Cond of exp * prop | 95 | Cond of exp * prop |
97 | 96 |
98 val unif = ref (IM.empty : exp IM.map) | |
99 | |
100 fun reset () = unif := IM.empty | |
101 fun save () = !unif | |
102 fun restore x = unif := x | |
103 | |
104 local | 97 local |
105 open Print | 98 open Print |
106 val string = PD.string | 99 val string = PD.string |
107 in | 100 in |
108 | 101 |
115 | 108 |
116 fun p_exp e = | 109 fun p_exp e = |
117 case e of | 110 case e of |
118 Const p => Prim.p_t p | 111 Const p => Prim.p_t p |
119 | Var n => string ("x" ^ Int.toString n) | 112 | Var n => string ("x" ^ Int.toString n) |
120 | Lvar n => | 113 | Lvar n => string ("X" ^ Int.toString n) |
121 (case IM.find (!unif, n) of | |
122 NONE => string ("X" ^ Int.toString n) | |
123 | SOME e => p_exp e) | |
124 | Func (f, es) => box [p_func f, | 114 | Func (f, es) => box [p_func f, |
125 string "(", | 115 string "(", |
126 p_list p_exp es, | 116 p_list p_exp es, |
127 string ")"] | 117 string ")"] |
128 | Recd xes => box [string "{", | 118 | Recd xes => box [string "{", |
132 space, | 122 space, |
133 p_exp e]) xes, | 123 p_exp e]) xes, |
134 string "}"] | 124 string "}"] |
135 | Proj (e, x) => box [p_exp e, | 125 | Proj (e, x) => box [p_exp e, |
136 string ("." ^ x)] | 126 string ("." ^ x)] |
137 | Finish => string "FINISH" | |
138 | 127 |
139 fun p_bop s es = | 128 fun p_bop s es = |
140 case es of | 129 case es of |
141 [e1, e2] => box [p_exp e1, | 130 [e1, e2] => box [p_exp e1, |
142 space, | 131 space, |
201 p_prop p, | 190 p_prop p, |
202 string ")"] | 191 string ")"] |
203 | 192 |
204 end | 193 end |
205 | 194 |
206 local | |
207 val count = ref 1 | |
208 in | |
209 fun newLvar () = | |
210 let | |
211 val n = !count | |
212 in | |
213 count := n + 1; | |
214 n | |
215 end | |
216 end | |
217 | |
218 fun isKnown e = | 195 fun isKnown e = |
219 case e of | 196 case e of |
220 Const _ => true | 197 Const _ => true |
221 | Func (_, es) => List.all isKnown es | 198 | Func (_, es) => List.all isKnown es |
222 | Recd xes => List.all (isKnown o #2) xes | 199 | Recd xes => List.all (isKnown o #2) xes |
223 | Proj (e, _) => isKnown e | 200 | Proj (e, _) => isKnown e |
224 | _ => false | 201 | _ => false |
225 | 202 |
226 fun isFinish e = | 203 fun simplify unif = |
227 case e of | 204 let |
228 Finish => true | 205 fun simplify e = |
229 | _ => false | 206 case e of |
230 | 207 Const _ => e |
231 fun simplify e = | 208 | Var _ => e |
232 case e of | 209 | Lvar n => |
233 Const _ => e | 210 (case IM.find (unif, n) of |
234 | Var _ => e | 211 NONE => e |
235 | Lvar n => | 212 | SOME e => simplify e) |
236 (case IM.find (!unif, n) of | 213 | Func (f, es) => Func (f, map simplify es) |
237 NONE => e | 214 | Recd xes => Recd (map (fn (x, e) => (x, simplify e)) xes) |
238 | SOME e => simplify e) | 215 | Proj (e, s) => Proj (simplify e, s) |
239 | Func (f, es) => Func (f, map simplify es) | 216 in |
240 | Recd xes => Recd (map (fn (x, e) => (x, simplify e)) xes) | 217 simplify |
241 | Proj (e, s) => Proj (simplify e, s) | 218 end |
242 | Finish => Finish | |
243 | 219 |
244 datatype atom = | 220 datatype atom = |
245 AReln of reln * exp list | 221 AReln of reln * exp list |
246 | ACond of exp * prop | 222 | ACond of exp * prop |
247 | 223 |
248 fun p_atom a = | 224 fun p_atom a = |
249 p_prop (case a of | 225 p_prop (case a of |
250 AReln x => Reln x | 226 AReln x => Reln x |
251 | ACond x => Cond x) | 227 | ACond x => Cond x) |
252 | 228 |
253 fun lvarIn lv = | |
254 let | |
255 fun lvi e = | |
256 case e of | |
257 Const _ => false | |
258 | Var _ => false | |
259 | Lvar lv' => lv' = lv | |
260 | Func (_, es) => List.exists lvi es | |
261 | Recd xes => List.exists (lvi o #2) xes | |
262 | Proj (e, _) => lvi e | |
263 | Finish => false | |
264 in | |
265 lvi | |
266 end | |
267 | |
268 fun lvarInP lv = | |
269 let | |
270 fun lvi p = | |
271 case p of | |
272 True => false | |
273 | False => false | |
274 | Unknown => true | |
275 | And (p1, p2) => lvi p1 orelse lvi p2 | |
276 | Or (p1, p2) => lvi p1 orelse lvi p2 | |
277 | Reln (_, es) => List.exists (lvarIn lv) es | |
278 | Cond (e, p) => lvarIn lv e orelse lvi p | |
279 in | |
280 lvi | |
281 end | |
282 | |
283 fun varIn lv = | |
284 let | |
285 fun lvi e = | |
286 case e of | |
287 Const _ => false | |
288 | Lvar _ => false | |
289 | Var lv' => lv' = lv | |
290 | Func (_, es) => List.exists lvi es | |
291 | Recd xes => List.exists (lvi o #2) xes | |
292 | Proj (e, _) => lvi e | |
293 | Finish => false | |
294 in | |
295 lvi | |
296 end | |
297 | |
298 fun varInP lv = | |
299 let | |
300 fun lvi p = | |
301 case p of | |
302 True => false | |
303 | False => false | |
304 | Unknown => false | |
305 | And (p1, p2) => lvi p1 orelse lvi p2 | |
306 | Or (p1, p2) => lvi p1 orelse lvi p2 | |
307 | Reln (_, es) => List.exists (varIn lv) es | |
308 | Cond (e, p) => varIn lv e orelse lvi p | |
309 in | |
310 lvi | |
311 end | |
312 | |
313 fun bumpLvars by = | |
314 let | |
315 fun lvi e = | |
316 case e of | |
317 Const _ => e | |
318 | Var _ => e | |
319 | Lvar lv => Lvar (lv + by) | |
320 | Func (f, es) => Func (f, map lvi es) | |
321 | Recd xes => Recd (map (fn (x, e) => (x, lvi e)) xes) | |
322 | Proj (e, f) => Proj (lvi e, f) | |
323 | Finish => e | |
324 in | |
325 lvi | |
326 end | |
327 | |
328 fun bumpLvarsP by = | |
329 let | |
330 fun lvi p = | |
331 case p of | |
332 True => p | |
333 | False => p | |
334 | Unknown => p | |
335 | And (p1, p2) => And (lvi p1, lvi p2) | |
336 | Or (p1, p2) => And (lvi p1, lvi p2) | |
337 | Reln (r, es) => Reln (r, map (bumpLvars by) es) | |
338 | Cond (e, p) => Cond (bumpLvars by e, lvi p) | |
339 in | |
340 lvi | |
341 end | |
342 | |
343 fun maxLvar e = | |
344 let | |
345 fun lvi e = | |
346 case e of | |
347 Const _ => 0 | |
348 | Var _ => 0 | |
349 | Lvar lv => lv | |
350 | Func (f, es) => foldl Int.max 0 (map lvi es) | |
351 | Recd xes => foldl Int.max 0 (map (lvi o #2) xes) | |
352 | Proj (e, f) => lvi e | |
353 | Finish => 0 | |
354 in | |
355 lvi e | |
356 end | |
357 | |
358 fun maxLvarP p = | |
359 let | |
360 fun lvi p = | |
361 case p of | |
362 True => 0 | |
363 | False => 0 | |
364 | Unknown => 0 | |
365 | And (p1, p2) => Int.max (lvi p1, lvi p2) | |
366 | Or (p1, p2) => Int.max (lvi p1, lvi p2) | |
367 | Reln (r, es) => foldl Int.max 0 (map maxLvar es) | |
368 | Cond (e, p) => Int.max (maxLvar e, lvi p) | |
369 in | |
370 lvi p | |
371 end | |
372 | |
373 fun eq' (e1, e2) = | |
374 case (e1, e2) of | |
375 (Const p1, Const p2) => Prim.equal (p1, p2) | |
376 | (Var n1, Var n2) => n1 = n2 | |
377 | |
378 | (Lvar n1, _) => | |
379 (case IM.find (!unif, n1) of | |
380 SOME e1 => eq' (e1, e2) | |
381 | NONE => | |
382 case e2 of | |
383 Lvar n2 => | |
384 (case IM.find (!unif, n2) of | |
385 SOME e2 => eq' (e1, e2) | |
386 | NONE => n1 = n2 | |
387 orelse (unif := IM.insert (!unif, n2, e1); | |
388 true)) | |
389 | _ => | |
390 if lvarIn n1 e2 then | |
391 false | |
392 else | |
393 (unif := IM.insert (!unif, n1, e2); | |
394 true)) | |
395 | |
396 | (_, Lvar n2) => | |
397 (case IM.find (!unif, n2) of | |
398 SOME e2 => eq' (e1, e2) | |
399 | NONE => | |
400 if lvarIn n2 e1 then | |
401 false | |
402 else | |
403 ((*Print.prefaces "unif" [("n2", Print.PD.string (Int.toString n2)), | |
404 ("e1", p_exp e1)];*) | |
405 unif := IM.insert (!unif, n2, e1); | |
406 true)) | |
407 | |
408 | (Func (f1, es1), Func (f2, es2)) => f1 = f2 andalso ListPair.allEq eq' (es1, es2) | |
409 | (Recd xes1, Recd xes2) => ListPair.allEq (fn ((x1, e1), (x2, e2)) => x1 = x2 andalso eq' (e1, e2)) (xes1, xes2) | |
410 | (Proj (e1, s1), Proj (e2, s2)) => eq' (e1, e2) andalso s1 = s2 | |
411 | (Finish, Finish) => true | |
412 | _ => false | |
413 | |
414 fun eq (e1, e2) = | |
415 let | |
416 val saved = save () | |
417 in | |
418 if eq' (simplify e1, simplify e2) then | |
419 true | |
420 else | |
421 (restore saved; | |
422 false) | |
423 end | |
424 | |
425 val debug = ref false | 229 val debug = ref false |
426 | |
427 fun eeq (e1, e2) = | |
428 case (e1, e2) of | |
429 (Const p1, Const p2) => Prim.equal (p1, p2) | |
430 | (Var n1, Var n2) => n1 = n2 | |
431 | (Lvar n1, Lvar n2) => n1 = n2 | |
432 | (Func (f1, es1), Func (f2, es2)) => f1 = f2 andalso ListPair.allEq eeq (es1, es2) | |
433 | (Recd xes1, Recd xes2) => length xes1 = length xes2 andalso | |
434 List.all (fn (x2, e2) => | |
435 List.exists (fn (x1, e1) => x1 = x2 andalso eeq (e1, e2)) xes2) xes1 | |
436 | (Proj (e1, x1), Proj (e2, x2)) => eeq (e1, e2) andalso x1 = x2 | |
437 | (Finish, Finish) => true | |
438 | _ => false | |
439 | 230 |
440 (* Congruence closure *) | 231 (* Congruence closure *) |
441 structure Cc :> sig | 232 structure Cc :> sig |
442 type database | 233 type database |
443 | 234 |
444 exception Contradiction | 235 exception Contradiction |
445 exception Undetermined | 236 exception Undetermined |
446 | 237 |
447 val database : unit -> database | 238 val database : unit -> database |
239 val clear : database -> unit | |
448 | 240 |
449 val assert : database * atom -> unit | 241 val assert : database * atom -> unit |
450 val check : database * atom -> bool | 242 val check : database * atom -> bool |
451 | 243 |
452 val p_database : database Print.printer | 244 val p_database : database Print.printer |
487 fun database () = {Vars = ref IM.empty, | 279 fun database () = {Vars = ref IM.empty, |
488 Consts = ref CM.empty, | 280 Consts = ref CM.empty, |
489 Con0s = ref SM.empty, | 281 Con0s = ref SM.empty, |
490 Records = ref [], | 282 Records = ref [], |
491 Funcs = ref []} | 283 Funcs = ref []} |
284 | |
285 fun clear (t : database) = (#Vars t := IM.empty; | |
286 #Consts t := CM.empty; | |
287 #Con0s t := SM.empty; | |
288 #Records t := []; | |
289 #Funcs t := []) | |
492 | 290 |
493 fun unNode n = | 291 fun unNode n = |
494 case !n of | 292 case !n of |
495 Node r => r | 293 Node r => r |
496 | 294 |
592 Known = ref false}) | 390 Known = ref false}) |
593 in | 391 in |
594 #Vars db := IM.insert (!(#Vars db), n, r); | 392 #Vars db := IM.insert (!(#Vars db), n, r); |
595 r | 393 r |
596 end) | 394 end) |
597 | Lvar n => | 395 | Lvar _ => raise Undetermined |
598 (case IM.find (!unif, n) of | |
599 NONE => raise Undetermined | |
600 | SOME e => rep e) | |
601 | Func (DtCon0 f, []) => (case SM.find (!(#Con0s db), f) of | 396 | Func (DtCon0 f, []) => (case SM.find (!(#Con0s db), f) of |
602 SOME r => repOf r | 397 SOME r => repOf r |
603 | NONE => | 398 | NONE => |
604 let | 399 let |
605 val r = ref (Node {Rep = ref NONE, | 400 val r = ref (Node {Rep = ref NONE, |
733 #Rep (unNode r) := SOME r''; | 528 #Rep (unNode r) := SOME r''; |
734 r' | 529 r' |
735 end | 530 end |
736 | _ => raise Contradiction | 531 | _ => raise Contradiction |
737 end | 532 end |
738 | Finish => raise Contradiction | |
739 in | 533 in |
740 rep e | 534 rep e |
741 end | 535 end |
742 | 536 |
743 fun p_repOf db e = p_rep (representative (db, e)) | 537 fun p_repOf db e = p_rep (representative (db, e)) |
935 in | 729 in |
936 loop (representative (db, d)) | 730 loop (representative (db, d)) |
937 end | 731 end |
938 | 732 |
939 end | 733 end |
940 | |
941 fun decomp fals or = | |
942 let | |
943 fun decomp p k = | |
944 case p of | |
945 True => k [] | |
946 | False => fals | |
947 | Unknown => k [] | |
948 | And (p1, p2) => | |
949 decomp p1 (fn ps1 => | |
950 decomp p2 (fn ps2 => | |
951 k (ps1 @ ps2))) | |
952 | Or (p1, p2) => | |
953 or (decomp p1 k, fn () => decomp p2 k) | |
954 | Reln x => k [AReln x] | |
955 | Cond x => k [ACond x] | |
956 in | |
957 decomp | |
958 end | |
959 | 734 |
960 val tabs = ref (SM.empty : (string list * string list list) SM.map) | 735 val tabs = ref (SM.empty : (string list * string list list) SM.map) |
961 | 736 |
962 fun ccOf hyps = | 737 fun ccOf hyps = |
963 let | 738 let |
1016 in | 791 in |
1017 findKeys hyps; | 792 findKeys hyps; |
1018 cc | 793 cc |
1019 end | 794 end |
1020 | 795 |
1021 fun imply (cc, hyps, goals, outs) = | |
1022 let | |
1023 fun gls goals onFail acc = | |
1024 case goals of | |
1025 [] => | |
1026 ((List.all (fn a => | |
1027 if Cc.check (cc, a) then | |
1028 true | |
1029 else | |
1030 ((*Print.prefaces "Can't prove" | |
1031 [("a", p_atom a), | |
1032 ("hyps", Print.p_list p_atom hyps), | |
1033 ("db", Cc.p_database cc)];*) | |
1034 false)) acc | |
1035 andalso ((*Print.preface ("Finding", Cc.p_database cc);*) true) | |
1036 andalso (case outs of | |
1037 NONE => true | |
1038 | SOME outs => Cc.builtFrom (cc, {Derived = Var 0, | |
1039 Base = outs}))) | |
1040 handle Cc.Contradiction => false | |
1041 | Cc.Undetermined => false) | |
1042 orelse onFail () | |
1043 | (g as AReln (Sql gf, [ge])) :: goals => | |
1044 let | |
1045 fun hps hyps = | |
1046 case hyps of | |
1047 [] => gls goals onFail (g :: acc) | |
1048 | (h as AReln (Sql hf, [he])) :: hyps => | |
1049 if gf = hf then | |
1050 let | |
1051 val saved = save () | |
1052 in | |
1053 if eq (ge, he) then | |
1054 let | |
1055 val changed = IM.numItems (!unif) | |
1056 <> IM.numItems saved | |
1057 in | |
1058 gls goals (fn () => (restore saved; | |
1059 changed | |
1060 andalso hps hyps)) | |
1061 acc | |
1062 end | |
1063 else | |
1064 hps hyps | |
1065 end | |
1066 else | |
1067 hps hyps | |
1068 | _ :: hyps => hps hyps | |
1069 in | |
1070 hps hyps | |
1071 end | |
1072 | g :: goals => gls goals onFail (g :: acc) | |
1073 in | |
1074 reset (); | |
1075 (*Print.prefaces "Big go" [("hyps", Print.p_list p_atom hyps), | |
1076 ("goals", Print.p_list p_atom goals)];*) | |
1077 gls goals (fn () => false) [] | |
1078 end | |
1079 | |
1080 fun patCon pc = | 796 fun patCon pc = |
1081 case pc of | 797 case pc of |
1082 PConVar n => "C" ^ Int.toString n | 798 PConVar n => "C" ^ Int.toString n |
1083 | PConFfi {mod = m, datatyp = d, con = c, ...} => m ^ "." ^ d ^ "." ^ c | 799 | PConFfi {mod = m, datatyp = d, con = c, ...} => m ^ "." ^ d ^ "." ^ c |
1084 | 800 |
1428 val dml = log "dml" | 1144 val dml = log "dml" |
1429 (altL [wrap insert Insert, | 1145 (altL [wrap insert Insert, |
1430 wrap delete Delete, | 1146 wrap delete Delete, |
1431 wrap update Update]) | 1147 wrap update Update]) |
1432 | 1148 |
1149 type check = exp * ErrorMsg.span | |
1150 | |
1151 structure St :> sig | |
1152 val reset : unit -> unit | |
1153 | |
1154 type stashed | |
1155 val stash : unit -> stashed | |
1156 val reinstate : stashed -> unit | |
1157 | |
1158 val nextVar : unit -> int | |
1159 | |
1160 val assert : atom list -> unit | |
1161 | |
1162 val addPath : check -> unit | |
1163 | |
1164 val allowSend : atom list * exp list -> unit | |
1165 val send : check -> unit | |
1166 | |
1167 val allowInsert : atom list -> unit | |
1168 val insert : ErrorMsg.span -> unit | |
1169 | |
1170 val allowDelete : atom list -> unit | |
1171 val delete : ErrorMsg.span -> unit | |
1172 | |
1173 val allowUpdate : atom list -> unit | |
1174 val update : ErrorMsg.span -> unit | |
1175 | |
1176 val havocReln : reln -> unit | |
1177 end = struct | |
1178 | |
1179 val hnames = ref 1 | |
1180 | |
1181 type hyps = int * atom list | |
1182 | |
1183 val db = Cc.database () | |
1184 val path = ref ([] : (hyps * check) option ref list) | |
1185 val hyps = ref (0, [] : atom list) | |
1186 val nvar = ref 0 | |
1187 | |
1188 fun reset () = (Cc.clear db; | |
1189 path := []; | |
1190 hyps := (0, []); | |
1191 nvar := 0) | |
1192 | |
1193 fun setHyps (h as (n', hs)) = | |
1194 let | |
1195 val (n, _) = !hyps | |
1196 in | |
1197 if n' = n then | |
1198 () | |
1199 else | |
1200 (hyps := h; | |
1201 Cc.clear db; | |
1202 app (fn a => Cc.assert (db, a)) hs) | |
1203 end | |
1204 | |
1205 type stashed = int * (hyps * check) option ref list * (int * atom list) | |
1206 fun stash () = (!nvar, !path, !hyps) | |
1207 fun reinstate (nv, p, h) = | |
1208 (nvar := nv; | |
1209 path := p; | |
1210 setHyps h) | |
1211 | |
1212 fun nextVar () = | |
1213 let | |
1214 val n = !nvar | |
1215 in | |
1216 nvar := n + 1; | |
1217 n | |
1218 end | |
1219 | |
1220 fun assert ats = | |
1221 let | |
1222 val n = !hnames | |
1223 val (_, hs) = !hyps | |
1224 in | |
1225 hnames := n + 1; | |
1226 hyps := (n, ats @ hs); | |
1227 app (fn a => Cc.assert (db, a)) ats | |
1228 end | |
1229 | |
1230 fun addPath c = path := ref (SOME (!hyps, c)) :: !path | |
1231 | |
1232 val sendable = ref ([] : (atom list * exp list) list) | |
1233 | |
1234 fun checkGoals goals unifs succ fail = | |
1235 case goals of | |
1236 [] => succ (unifs, []) | |
1237 | AReln (Sql tab, [Lvar lv]) :: goals => | |
1238 let | |
1239 val saved = stash () | |
1240 val (_, hyps) = !hyps | |
1241 | |
1242 fun tryAll unifs hyps = | |
1243 case hyps of | |
1244 [] => fail () | |
1245 | AReln (Sql tab', [e]) :: hyps => | |
1246 if tab' = tab then | |
1247 checkGoals goals (IM.insert (unifs, lv, e)) succ | |
1248 (fn () => tryAll unifs hyps) | |
1249 else | |
1250 tryAll unifs hyps | |
1251 | _ :: hyps => tryAll unifs hyps | |
1252 in | |
1253 tryAll unifs hyps | |
1254 end | |
1255 | AReln (r, es) :: goals => checkGoals goals unifs | |
1256 (fn (unifs, ls) => succ (unifs, AReln (r, map (simplify unifs) es) :: ls)) | |
1257 fail | |
1258 | ACond _ :: _ => fail () | |
1259 | |
1260 fun buildable (e, loc) = | |
1261 let | |
1262 fun doPols pols acc fail = | |
1263 case pols of | |
1264 [] => ((*Print.prefaces "buildable" [("Base", Print.p_list p_exp acc), | |
1265 ("Derived", p_exp e), | |
1266 ("Hyps", Print.p_list p_atom (#2 (!hyps)))];*) | |
1267 if Cc.builtFrom (db, {Base = acc, Derived = e}) then | |
1268 () | |
1269 else | |
1270 fail ()) | |
1271 | (goals, es) :: pols => | |
1272 checkGoals goals IM.empty | |
1273 (fn (unifs, goals) => | |
1274 if List.all (fn a => Cc.check (db, a)) goals then | |
1275 doPols pols (map (simplify unifs) es @ acc) fail | |
1276 else | |
1277 doPols pols acc fail) | |
1278 (fn () => doPols pols acc fail) | |
1279 in | |
1280 doPols (!sendable) [] | |
1281 (fn () => let | |
1282 val (_, hs) = !hyps | |
1283 in | |
1284 ErrorMsg.errorAt loc "The information flow policy may be violated here."; | |
1285 Print.preface ("Hypotheses", Print.p_list p_atom hs) | |
1286 end) | |
1287 end | |
1288 | |
1289 fun checkPaths () = | |
1290 let | |
1291 val hs = !hyps | |
1292 in | |
1293 app (fn r => | |
1294 case !r of | |
1295 NONE => () | |
1296 | SOME (hs, e) => | |
1297 (r := NONE; | |
1298 setHyps hs; | |
1299 buildable e)) (!path); | |
1300 setHyps hs | |
1301 end | |
1302 | |
1303 fun allowSend v = sendable := v :: !sendable | |
1304 | |
1305 fun send (e, loc) = ((*Print.preface ("Send", p_exp e);*) | |
1306 checkPaths (); | |
1307 if isKnown e then | |
1308 () | |
1309 else | |
1310 buildable (e, loc)) | |
1311 | |
1312 fun doable pols (loc : ErrorMsg.span) = | |
1313 let | |
1314 val pols = !pols | |
1315 in | |
1316 if List.exists (fn goals => | |
1317 checkGoals goals IM.empty | |
1318 (fn (_, goals) => List.all (fn a => Cc.check (db, a)) goals) | |
1319 (fn () => false)) pols then | |
1320 () | |
1321 else | |
1322 let | |
1323 val (_, hs) = !hyps | |
1324 in | |
1325 ErrorMsg.errorAt loc "The database update policy may be violated here."; | |
1326 Print.preface ("Hypotheses", Print.p_list p_atom hs) | |
1327 end | |
1328 end | |
1329 | |
1330 val insertable = ref ([] : atom list list) | |
1331 fun allowInsert v = insertable := v :: !insertable | |
1332 val insert = doable insertable | |
1333 | |
1334 val updatable = ref ([] : atom list list) | |
1335 fun allowUpdate v = updatable := v :: !updatable | |
1336 val update = doable updatable | |
1337 | |
1338 val deletable = ref ([] : atom list list) | |
1339 fun allowDelete v = deletable := v :: !deletable | |
1340 val delete = doable deletable | |
1341 | |
1342 fun havocReln r = | |
1343 let | |
1344 val n = !hnames | |
1345 val (_, hs) = !hyps | |
1346 in | |
1347 hnames := n + 1; | |
1348 hyps := (n, List.filter (fn AReln (r', _) => r' <> r | _ => true) hs) | |
1349 end | |
1350 | |
1351 end | |
1352 | |
1353 | |
1433 fun removeDups (ls : (string * string) list) = | 1354 fun removeDups (ls : (string * string) list) = |
1434 case ls of | 1355 case ls of |
1435 [] => [] | 1356 [] => [] |
1436 | x :: ls => | 1357 | x :: ls => |
1437 let | 1358 let |
1441 ls | 1362 ls |
1442 else | 1363 else |
1443 x :: ls | 1364 x :: ls |
1444 end | 1365 end |
1445 | 1366 |
1446 datatype queryMode = | |
1447 SomeCol | |
1448 | AllCols of exp | |
1449 | |
1450 fun expIn rv env rvOf = | 1367 fun expIn rv env rvOf = |
1451 let | 1368 let |
1452 fun expIn (e, rvN) = | 1369 fun expIn e = |
1453 let | 1370 let |
1454 fun default () = | 1371 fun default () = inl (rv ()) |
1455 let | |
1456 val (rvN, e') = rv rvN | |
1457 in | |
1458 (inl e', rvN) | |
1459 end | |
1460 in | 1372 in |
1461 case e of | 1373 case e of |
1462 SqConst p => (inl (Const p), rvN) | 1374 SqConst p => inl (Const p) |
1463 | Field (v, f) => (inl (Proj (rvOf v, f)), rvN) | 1375 | Field (v, f) => inl (Proj (rvOf v, f)) |
1464 | Binop (bo, e1, e2) => | 1376 | Binop (bo, e1, e2) => |
1465 let | 1377 let |
1466 val (e1, rvN) = expIn (e1, rvN) | 1378 val e1 = expIn e1 |
1467 val (e2, rvN) = expIn (e2, rvN) | 1379 val e2 = expIn e2 |
1468 in | 1380 in |
1469 (inr (case (bo, e1, e2) of | 1381 inr (case (bo, e1, e2) of |
1470 (Exps f, inl e1, inl e2) => f (e1, e2) | 1382 (Exps f, inl e1, inl e2) => f (e1, e2) |
1471 | (Props f, inr p1, inr p2) => f (p1, p2) | 1383 | (Props f, inr p1, inr p2) => f (p1, p2) |
1472 | _ => Unknown), rvN) | 1384 | _ => Unknown) |
1473 end | 1385 end |
1474 | SqKnown e => | 1386 | SqKnown e => |
1475 (case expIn (e, rvN) of | 1387 (case expIn e of |
1476 (inl e, rvN) => (inr (Reln (Known, [e])), rvN) | 1388 inl e => inr (Reln (Known, [e])) |
1477 | _ => (inr Unknown, rvN)) | 1389 | _ => inr Unknown) |
1478 | Inj e => | 1390 | Inj e => |
1479 let | 1391 let |
1480 fun deinj e = | 1392 fun deinj e = |
1481 case #1 e of | 1393 case #1 e of |
1482 ERel n => (List.nth (env, n), rvN) | 1394 ERel n => List.nth (env, n) |
1483 | EField (e, f) => | 1395 | EField (e, f) => Proj (deinj e, f) |
1484 let | 1396 | _ => rv () |
1485 val (e, rvN) = deinj e | |
1486 in | |
1487 (Proj (e, f), rvN) | |
1488 end | |
1489 | _ => | |
1490 let | |
1491 val (rvN, e) = rv rvN | |
1492 in | |
1493 (e, rvN) | |
1494 end | |
1495 | |
1496 val (e, rvN) = deinj e | |
1497 in | 1397 in |
1498 (inl e, rvN) | 1398 inl (deinj e) |
1499 end | 1399 end |
1500 | SqFunc (f, e) => | 1400 | SqFunc (f, e) => |
1501 (case expIn (e, rvN) of | 1401 (case expIn e of |
1502 (inl e, rvN) => (inl (Func (Other f, [e])), rvN) | 1402 inl e => inl (Func (Other f, [e])) |
1503 | _ => default ()) | 1403 | _ => default ()) |
1504 | 1404 |
1505 | Count => default () | 1405 | Count => default () |
1506 end | 1406 end |
1507 in | 1407 in |
1508 expIn | 1408 expIn |
1509 end | 1409 end |
1510 | 1410 |
1511 fun queryProp env rvN rv oe e = | 1411 fun decomp {Save = save, Restore = restore, Add = add} = |
1512 let | 1412 let |
1513 fun default () = (print ("Warning: Information flow checker can't parse SQL query at " | 1413 fun go p k = |
1514 ^ ErrorMsg.spanToString (#2 e) ^ "\n"); | 1414 case p of |
1515 (rvN, Unknown, [], [])) | 1415 True => k () |
1416 | False => () | |
1417 | Unknown => () | |
1418 | And (p1, p2) => go p1 (fn () => go p2 k) | |
1419 | Or (p1, p2) => | |
1420 let | |
1421 val saved = save () | |
1422 in | |
1423 go p1 k; | |
1424 restore saved; | |
1425 go p2 k | |
1426 end | |
1427 | Reln x => (add (AReln x); k ()) | |
1428 | Cond x => (add (ACond x); k ()) | |
1429 in | |
1430 go | |
1431 end | |
1432 | |
1433 datatype queryMode = | |
1434 SomeCol of exp list -> unit | |
1435 | AllCols of exp -> unit | |
1436 | |
1437 type 'a doQuery = { | |
1438 Env : exp list, | |
1439 NextVar : unit -> exp, | |
1440 Add : atom -> unit, | |
1441 Save : unit -> 'a, | |
1442 Restore : 'a -> unit, | |
1443 UsedExp : exp -> unit, | |
1444 Cont : queryMode | |
1445 } | |
1446 | |
1447 fun doQuery (arg : 'a doQuery) e = | |
1448 let | |
1449 fun default () = print ("Warning: Information flow checker can't parse SQL query at " | |
1450 ^ ErrorMsg.spanToString (#2 e) ^ "\n") | |
1516 in | 1451 in |
1517 case parse query e of | 1452 case parse query e of |
1518 NONE => default () | 1453 NONE => default () |
1519 | SOME q => | 1454 | SOME q => |
1520 let | 1455 let |
1521 fun doQuery (q, rvN) = | 1456 fun doQuery q = |
1522 case q of | 1457 case q of |
1523 Query1 r => | 1458 Query1 r => |
1524 let | 1459 let |
1525 val (rvs, rvN) = ListUtil.foldlMap (fn ((_, v), rvN) => | 1460 val rvs = map (fn (_, v) => (v, #NextVar arg ())) (#From r) |
1526 let | |
1527 val (rvN, e) = rv rvN | |
1528 in | |
1529 ((v, e), rvN) | |
1530 end) rvN (#From r) | |
1531 | 1461 |
1532 fun rvOf v = | 1462 fun rvOf v = |
1533 case List.find (fn (v', _) => v' = v) rvs of | 1463 case List.find (fn (v', _) => v' = v) rvs of |
1534 NONE => raise Fail "Iflow.queryProp: Bad table variable" | 1464 NONE => raise Fail "Iflow.queryProp: Bad table variable" |
1535 | SOME (_, e) => e | 1465 | SOME (_, e) => e |
1466 | |
1467 val expIn = expIn (#NextVar arg) (#Env arg) rvOf | |
1468 | |
1469 val saved = #Save arg () | |
1470 fun addFrom () = app (fn (t, v) => #Add arg (AReln (Sql t, [rvOf v]))) (#From r) | |
1536 | 1471 |
1537 fun usedFields e = | 1472 fun usedFields e = |
1538 case e of | 1473 case e of |
1539 SqConst _ => [] | 1474 SqConst _ => [] |
1540 | Field (v, f) => [(v, f)] | 1475 | Field (v, f) => [(v, f)] |
1542 | SqKnown _ => [] | 1477 | SqKnown _ => [] |
1543 | Inj _ => [] | 1478 | Inj _ => [] |
1544 | SqFunc (_, e) => usedFields e | 1479 | SqFunc (_, e) => usedFields e |
1545 | Count => [] | 1480 | Count => [] |
1546 | 1481 |
1547 val p = | 1482 fun doUsed () = case #Where r of |
1548 foldl (fn ((t, v), p) => And (p, Reln (Sql t, [rvOf v]))) True (#From r) | 1483 NONE => () |
1549 | 1484 | SOME e => |
1550 val expIn = expIn rv env rvOf | 1485 #UsedExp arg (Recd (ListUtil.mapi |
1551 | 1486 (fn (n, (v, f)) => (Int.toString n, |
1552 val (p, rvN) = case #Where r of | 1487 Proj (rvOf v, f))) |
1553 NONE => (p, rvN) | 1488 (usedFields e))) |
1554 | SOME e => | 1489 |
1555 case expIn (e, rvN) of | 1490 fun normal' () = |
1556 (inr p', rvN) => (And (p, p'), rvN) | 1491 case #Cont arg of |
1557 | _ => (p, rvN) | 1492 SomeCol k => |
1558 | |
1559 fun normal () = | |
1560 case oe of | |
1561 SomeCol => | |
1562 let | 1493 let |
1563 val (sis, rvN) = | 1494 val sis = map (fn si => |
1564 ListUtil.foldlMap | 1495 case si of |
1565 (fn (si, rvN) => | 1496 SqField (v, f) => Proj (rvOf v, f) |
1566 case si of | 1497 | SqExp (e, f) => |
1567 SqField (v, f) => (Proj (rvOf v, f), rvN) | 1498 case expIn e of |
1568 | SqExp (e, f) => | 1499 inr _ => #NextVar arg () |
1569 case expIn (e, rvN) of | 1500 | inl e => e) (#Select r) |
1570 (inr _, _) => | |
1571 let | |
1572 val (rvN, e) = rv rvN | |
1573 in | |
1574 (e, rvN) | |
1575 end | |
1576 | (inl e, rvN) => (e, rvN)) rvN (#Select r) | |
1577 in | 1501 in |
1578 (rvN, p, True, sis) | 1502 k sis |
1579 end | 1503 end |
1580 | AllCols oe => | 1504 | AllCols k => |
1581 let | 1505 let |
1582 val (ts, es, rvN) = | 1506 val (ts, es) = |
1583 foldl (fn (si, (ts, es, rvN)) => | 1507 foldl (fn (si, (ts, es)) => |
1584 case si of | 1508 case si of |
1585 SqField (v, f) => | 1509 SqField (v, f) => |
1586 let | 1510 let |
1587 val fs = getOpt (SM.find (ts, v), SM.empty) | 1511 val fs = getOpt (SM.find (ts, v), SM.empty) |
1588 in | 1512 in |
1589 (SM.insert (ts, v, SM.insert (fs, f, Proj (rvOf v, f))), es, rvN) | 1513 (SM.insert (ts, v, SM.insert (fs, f, Proj (rvOf v, f))), es) |
1590 end | 1514 end |
1591 | SqExp (e, f) => | 1515 | SqExp (e, f) => |
1592 let | 1516 let |
1593 val (e, rvN) = | 1517 val e = |
1594 case expIn (e, rvN) of | 1518 case expIn e of |
1595 (inr _, rvN) => | 1519 inr _ => #NextVar arg () |
1596 let | 1520 | inl e => e |
1597 val (rvN, e) = rv rvN | |
1598 in | |
1599 (e, rvN) | |
1600 end | |
1601 | (inl e, rvN) => (e, rvN) | |
1602 in | 1521 in |
1603 (ts, SM.insert (es, f, e), rvN) | 1522 (ts, SM.insert (es, f, e)) |
1604 end) | 1523 end) |
1605 (SM.empty, SM.empty, rvN) (#Select r) | 1524 (SM.empty, SM.empty) (#Select r) |
1606 | |
1607 val p' = Reln (Eq, [oe, Recd (map (fn (t, fs) => (t, Recd (SM.listItemsi fs))) | |
1608 (SM.listItemsi ts) | |
1609 @ SM.listItemsi es)]) | |
1610 in | 1525 in |
1611 (rvN, And (p, p'), True, []) | 1526 k (Recd (map (fn (t, fs) => (t, Recd (SM.listItemsi fs))) |
1527 (SM.listItemsi ts) | |
1528 @ SM.listItemsi es)) | |
1612 end | 1529 end |
1613 | 1530 |
1614 val (rvN, p, wp, outs) = | 1531 fun doWhere final = |
1615 case #Select r of | 1532 (addFrom (); |
1616 [SqExp (Binop (Exps bo, Count, SqConst (Prim.Int 0)), f)] => | 1533 case #Where r of |
1617 (case bo (Const (Prim.Int 1), Const (Prim.Int 2)) of | 1534 NONE => (doUsed (); final ()) |
1618 Reln (Gt, [Const (Prim.Int 1), Const (Prim.Int 2)]) => | 1535 | SOME e => |
1619 (case oe of | 1536 case expIn e of |
1620 SomeCol => | 1537 inl _ => (doUsed (); final ()) |
1621 let | 1538 | inr p => |
1622 val (rvN, oe) = rv rvN | 1539 let |
1623 in | 1540 val saved = #Save arg () |
1624 (rvN, | 1541 in |
1625 Or (Reln (Eq, [oe, Func (DtCon0 "Basis.bool.False", [])]), | 1542 decomp {Save = #Save arg, Restore = #Restore arg, Add = #Add arg} |
1626 And (Reln (Eq, [oe, Func (DtCon0 "Basis.bool.True", [])]), | 1543 p (fn () => (doUsed (); final ()) handle Cc.Contradiction => ()); |
1627 p)), | 1544 #Restore arg saved |
1628 Reln (Eq, [oe, Func (DtCon0 "Basis.bool.True", [])]), | 1545 end) |
1629 [oe]) | 1546 handle Cc.Contradiction => () |
1630 end | 1547 |
1631 | AllCols oe => | 1548 fun normal () = doWhere normal' |
1632 let | |
1633 fun oeEq e = Reln (Eq, [oe, Recd [(f, e)]]) | |
1634 in | |
1635 (rvN, | |
1636 Or (oeEq (Func (DtCon0 "Basis.bool.False", [])), | |
1637 And (oeEq (Func (DtCon0 "Basis.bool.True", [])), | |
1638 p)), | |
1639 oeEq (Func (DtCon0 "Basis.bool.True", [])), | |
1640 []) | |
1641 end) | |
1642 | _ => normal ()) | |
1643 | _ => normal () | |
1644 in | 1549 in |
1645 (rvN, p, map (fn x => (wp, x)) | 1550 (case #Select r of |
1646 (case #Where r of | 1551 [SqExp (Binop (Exps bo, Count, SqConst (Prim.Int 0)), f)] => |
1647 NONE => [] | 1552 (case bo (Const (Prim.Int 1), Const (Prim.Int 2)) of |
1648 | SOME e => map (fn (v, f) => Proj (rvOf v, f)) (usedFields e)), outs) | 1553 Reln (Gt, [Const (Prim.Int 1), Const (Prim.Int 2)]) => |
1554 (case #Cont arg of | |
1555 SomeCol _ => () | |
1556 | AllCols k => | |
1557 let | |
1558 fun answer e = k (Recd [(f, e)]) | |
1559 | |
1560 val () = answer (Func (DtCon0 "Basis.bool.False", [])) | |
1561 val saved = #Save arg () | |
1562 in | |
1563 doWhere (fn () => answer (Func (DtCon0 "Basis.bool.True", []))); | |
1564 #Restore arg saved | |
1565 end) | |
1566 | _ => normal ()) | |
1567 | _ => normal ()) | |
1568 before #Restore arg saved | |
1649 end | 1569 end |
1650 | Union (q1, q2) => | 1570 | Union (q1, q2) => |
1651 let | 1571 let |
1652 val (rvN, p1, used1, outs1) = doQuery (q1, rvN) | 1572 val saved = #Save arg () |
1653 val (rvN, p2, used2, outs2) = doQuery (q2, rvN) | |
1654 in | 1573 in |
1655 case (outs1, outs2) of | 1574 doQuery q1; |
1656 ([], []) => (rvN, Or (p1, p2), | 1575 #Restore arg saved; |
1657 map (fn (p, e) => (And (p1, p), e)) used1 | 1576 doQuery q2; |
1658 @ map (fn (p, e) => (And (p2, p), e)) used2, []) | 1577 #Restore arg saved |
1659 | _ => default () | |
1660 end | 1578 end |
1661 in | 1579 in |
1662 doQuery (q, rvN) | 1580 doQuery q |
1663 end | 1581 end |
1664 end | 1582 end |
1665 | 1583 |
1666 fun insertProp rvN rv e = | |
1667 let | |
1668 fun default () = (print ("Warning: Information flow checker can't parse SQL query at " | |
1669 ^ ErrorMsg.spanToString (#2 e) ^ "\n"); | |
1670 Unknown) | |
1671 in | |
1672 case parse query e of | |
1673 SOME (Query1 r) => | |
1674 let | |
1675 val (rvs, rvN) = ListUtil.foldlMap (fn ((_, v), rvN) => | |
1676 let | |
1677 val (rvN, e) = rv rvN | |
1678 in | |
1679 ((v, e), rvN) | |
1680 end) rvN (#From r) | |
1681 | |
1682 fun rvOf v = | |
1683 case List.find (fn (v', _) => v' = v) rvs of | |
1684 NONE => raise Fail "Iflow.insertProp: Bad table variable" | |
1685 | SOME (_, e) => e | |
1686 | |
1687 val p = | |
1688 foldl (fn ((t, v), p) => | |
1689 let | |
1690 val t = | |
1691 case v of | |
1692 "New" => t ^ "$New" | |
1693 | _ => t | |
1694 in | |
1695 And (p, Reln (Sql t, [rvOf v])) | |
1696 end) True (#From r) | |
1697 | |
1698 val expIn = expIn rv [] rvOf | |
1699 in | |
1700 case #Where r of | |
1701 NONE => p | |
1702 | SOME e => | |
1703 case expIn (e, rvN) of | |
1704 (inr p', _) => And (p, p') | |
1705 | _ => p | |
1706 end | |
1707 | _ => default () | |
1708 end | |
1709 | |
1710 fun deleteProp rvN rv e = | |
1711 let | |
1712 fun default () = (print ("Warning: Information flow checker can't parse SQL query at " | |
1713 ^ ErrorMsg.spanToString (#2 e) ^ "\n"); | |
1714 Unknown) | |
1715 in | |
1716 case parse query e of | |
1717 SOME (Query1 r) => | |
1718 let | |
1719 val (rvs, rvN) = ListUtil.foldlMap (fn ((_, v), rvN) => | |
1720 let | |
1721 val (rvN, e) = rv rvN | |
1722 in | |
1723 ((v, e), rvN) | |
1724 end) rvN (#From r) | |
1725 | |
1726 fun rvOf v = | |
1727 case List.find (fn (v', _) => v' = v) rvs of | |
1728 NONE => raise Fail "Iflow.deleteProp: Bad table variable" | |
1729 | SOME (_, e) => e | |
1730 | |
1731 val p = | |
1732 foldl (fn ((t, v), p) => And (p, Reln (Sql t, [rvOf v]))) True (#From r) | |
1733 | |
1734 val expIn = expIn rv [] rvOf | |
1735 in | |
1736 And (Reln (Sql "$Old", [rvOf "Old"]), | |
1737 case #Where r of | |
1738 NONE => p | |
1739 | SOME e => | |
1740 case expIn (e, rvN) of | |
1741 (inr p', _) => And (p, p') | |
1742 | _ => p) | |
1743 end | |
1744 | _ => default () | |
1745 end | |
1746 | |
1747 fun updateProp rvN rv e = | |
1748 let | |
1749 fun default () = (print ("Warning: Information flow checker can't parse SQL query at " | |
1750 ^ ErrorMsg.spanToString (#2 e) ^ "\n"); | |
1751 Unknown) | |
1752 in | |
1753 case parse query e of | |
1754 SOME (Query1 r) => | |
1755 let | |
1756 val (rvs, rvN) = ListUtil.foldlMap (fn ((_, v), rvN) => | |
1757 let | |
1758 val (rvN, e) = rv rvN | |
1759 in | |
1760 ((v, e), rvN) | |
1761 end) rvN (#From r) | |
1762 | |
1763 fun rvOf v = | |
1764 case List.find (fn (v', _) => v' = v) rvs of | |
1765 NONE => raise Fail "Iflow.insertProp: Bad table variable" | |
1766 | SOME (_, e) => e | |
1767 | |
1768 val p = | |
1769 foldl (fn ((t, v), p) => | |
1770 let | |
1771 val t = | |
1772 case v of | |
1773 "New" => t ^ "$New" | |
1774 | _ => t | |
1775 in | |
1776 And (p, Reln (Sql t, [rvOf v])) | |
1777 end) True (#From r) | |
1778 | |
1779 val expIn = expIn rv [] rvOf | |
1780 in | |
1781 And (Reln (Sql "$Old", [rvOf "Old"]), | |
1782 case #Where r of | |
1783 NONE => p | |
1784 | SOME e => | |
1785 case expIn (e, rvN) of | |
1786 (inr p', _) => And (p, p') | |
1787 | _ => p) | |
1788 end | |
1789 | _ => default () | |
1790 end | |
1791 | |
1792 fun evalPat env e (pt, _) = | 1584 fun evalPat env e (pt, _) = |
1793 case pt of | 1585 case pt of |
1794 PWild => (env, True) | 1586 PWild => env |
1795 | PVar _ => (e :: env, True) | 1587 | PVar _ => e :: env |
1796 | PPrim _ => (env, True) | 1588 | PPrim _ => env |
1797 | PCon (_, pc, NONE) => (env, Reln (PCon0 (patCon pc), [e])) | 1589 | PCon (_, pc, NONE) => (St.assert [AReln (PCon0 (patCon pc), [e])]; env) |
1798 | PCon (_, pc, SOME pt) => | 1590 | PCon (_, pc, SOME pt) => |
1799 let | 1591 let |
1800 val (env, p) = evalPat env (Func (UnCon (patCon pc), [e])) pt | 1592 val env = evalPat env (Func (UnCon (patCon pc), [e])) pt |
1801 in | 1593 in |
1802 (env, And (p, Reln (PCon1 (patCon pc), [e]))) | 1594 St.assert [AReln (PCon1 (patCon pc), [e])]; |
1595 env | |
1803 end | 1596 end |
1804 | PRecord xpts => | 1597 | PRecord xpts => |
1805 foldl (fn ((x, pt, _), (env, p)) => | 1598 foldl (fn ((x, pt, _), env) => evalPat env (Proj (e, x)) pt) env xpts |
1806 let | 1599 | PNone _ => (St.assert [AReln (PCon0 "None", [e])]; env) |
1807 val (env, p') = evalPat env (Proj (e, x)) pt | |
1808 in | |
1809 (env, And (p', p)) | |
1810 end) (env, True) xpts | |
1811 | PNone _ => (env, Reln (PCon0 "None", [e])) | |
1812 | PSome (_, pt) => | 1600 | PSome (_, pt) => |
1813 let | 1601 let |
1814 val (env, p) = evalPat env (Func (UnCon "Some", [e])) pt | 1602 val env = evalPat env (Func (UnCon "Some", [e])) pt |
1815 in | 1603 in |
1816 (env, And (p, Reln (PCon1 "Some", [e]))) | 1604 St.assert [AReln (PCon1 "Some", [e])]; |
1605 env | |
1817 end | 1606 end |
1818 | 1607 |
1819 fun peq (p1, p2) = | 1608 fun evalExp env (e as (_, loc)) k = |
1820 case (p1, p2) of | |
1821 (True, True) => true | |
1822 | (False, False) => true | |
1823 | (Unknown, Unknown) => true | |
1824 | (And (x1, y1), And (x2, y2)) => peq (x1, x2) andalso peq (y1, y2) | |
1825 | (Or (x1, y1), Or (x2, y2)) => peq (x1, x2) andalso peq (y1, y2) | |
1826 | (Reln (r1, es1), Reln (r2, es2)) => r1 = r2 andalso ListPair.allEq eeq (es1, es2) | |
1827 | (Cond (e1, p1), Cond (e2, p2)) => eeq (e1, e2) andalso peq (p1, p2) | |
1828 | _ => false | |
1829 | |
1830 fun removeRedundant p1 = | |
1831 let | 1609 let |
1832 fun rr p2 = | 1610 (*val () = Print.preface ("evalExp", MonoPrint.p_exp MonoEnv.empty e)*) |
1833 if peq (p1, p2) then | 1611 |
1834 True | 1612 fun default () = k (Var (St.nextVar ())) |
1835 else | |
1836 case p2 of | |
1837 And (x, y) => And (rr x, rr y) | |
1838 | Or (x, y) => Or (rr x, rr y) | |
1839 | _ => p2 | |
1840 in | |
1841 rr | |
1842 end | |
1843 | |
1844 datatype cflow = Case | Where | |
1845 datatype flow = Data | Control of cflow | |
1846 type check = ErrorMsg.span * exp * prop | |
1847 type dml = ErrorMsg.span * prop | |
1848 | |
1849 structure St :> sig | |
1850 type t | |
1851 val create : {Var : int, | |
1852 Ambient : prop} -> t | |
1853 | |
1854 val curVar : t -> int | |
1855 val nextVar : t -> t * int | |
1856 | |
1857 val ambient : t -> prop | |
1858 val setAmbient : t * prop -> t | |
1859 | |
1860 val paths : t -> (check * cflow) list | |
1861 val addPath : t * (check * cflow) -> t | |
1862 val addPaths : t * (check * cflow) list -> t | |
1863 val clearPaths : t -> t | |
1864 val setPaths : t * (check * cflow) list -> t | |
1865 | |
1866 val sent : t -> (check * flow) list | |
1867 val addSent : t * (check * flow) -> t | |
1868 val setSent : t * (check * flow) list -> t | |
1869 | |
1870 val inserted : t -> dml list | |
1871 val addInsert : t * dml -> t | |
1872 | |
1873 val deleted : t -> dml list | |
1874 val addDelete : t * dml -> t | |
1875 | |
1876 val updated : t -> dml list | |
1877 val addUpdate : t * dml -> t | |
1878 end = struct | |
1879 | |
1880 type t = {Var : int, | |
1881 Ambient : prop, | |
1882 Path : (check * cflow) list, | |
1883 Sent : (check * flow) list, | |
1884 Insert : dml list, | |
1885 Delete : dml list, | |
1886 Update : dml list} | |
1887 | |
1888 fun create {Var = v, Ambient = p} = {Var = v, | |
1889 Ambient = p, | |
1890 Path = [], | |
1891 Sent = [], | |
1892 Insert = [], | |
1893 Delete = [], | |
1894 Update = []} | |
1895 | |
1896 fun curVar (t : t) = #Var t | |
1897 fun nextVar (t : t) = ({Var = #Var t + 1, | |
1898 Ambient = #Ambient t, | |
1899 Path = #Path t, | |
1900 Sent = #Sent t, | |
1901 Insert = #Insert t, | |
1902 Delete = #Delete t, | |
1903 Update = #Update t}, #Var t) | |
1904 | |
1905 fun ambient (t : t) = #Ambient t | |
1906 fun setAmbient (t : t, p) = {Var = #Var t, | |
1907 Ambient = p, | |
1908 Path = #Path t, | |
1909 Sent = #Sent t, | |
1910 Insert = #Insert t, | |
1911 Delete = #Delete t, | |
1912 Update = #Update t} | |
1913 | |
1914 fun paths (t : t) = #Path t | |
1915 fun addPath (t : t, c) = {Var = #Var t, | |
1916 Ambient = #Ambient t, | |
1917 Path = c :: #Path t, | |
1918 Sent = #Sent t, | |
1919 Insert = #Insert t, | |
1920 Delete = #Delete t, | |
1921 Update = #Update t} | |
1922 fun addPaths (t : t, cs) = {Var = #Var t, | |
1923 Ambient = #Ambient t, | |
1924 Path = cs @ #Path t, | |
1925 Sent = #Sent t, | |
1926 Insert = #Insert t, | |
1927 Delete = #Delete t, | |
1928 Update = #Update t} | |
1929 fun clearPaths (t : t) = {Var = #Var t, | |
1930 Ambient = #Ambient t, | |
1931 Path = [], | |
1932 Sent = #Sent t, | |
1933 Insert = #Insert t, | |
1934 Delete = #Delete t, | |
1935 Update = #Update t} | |
1936 fun setPaths (t : t, cs) = {Var = #Var t, | |
1937 Ambient = #Ambient t, | |
1938 Path = cs, | |
1939 Sent = #Sent t, | |
1940 Insert = #Insert t, | |
1941 Delete = #Delete t, | |
1942 Update = #Update t} | |
1943 | |
1944 fun sent (t : t) = #Sent t | |
1945 fun addSent (t : t, c) = {Var = #Var t, | |
1946 Ambient = #Ambient t, | |
1947 Path = #Path t, | |
1948 Sent = c :: #Sent t, | |
1949 Insert = #Insert t, | |
1950 Delete = #Delete t, | |
1951 Update = #Update t} | |
1952 fun setSent (t : t, cs) = {Var = #Var t, | |
1953 Ambient = #Ambient t, | |
1954 Path = #Path t, | |
1955 Sent = cs, | |
1956 Insert = #Insert t, | |
1957 Delete = #Delete t, | |
1958 Update = #Update t} | |
1959 | |
1960 fun inserted (t : t) = #Insert t | |
1961 fun addInsert (t : t, c) = {Var = #Var t, | |
1962 Ambient = #Ambient t, | |
1963 Path = #Path t, | |
1964 Sent = #Sent t, | |
1965 Insert = c :: #Insert t, | |
1966 Delete = #Delete t, | |
1967 Update = #Update t} | |
1968 | |
1969 fun deleted (t : t) = #Delete t | |
1970 fun addDelete (t : t, c) = {Var = #Var t, | |
1971 Ambient = #Ambient t, | |
1972 Path = #Path t, | |
1973 Sent = #Sent t, | |
1974 Insert = #Insert t, | |
1975 Delete = c :: #Delete t, | |
1976 Update = #Update t} | |
1977 | |
1978 fun updated (t : t) = #Update t | |
1979 fun addUpdate (t : t, c) = {Var = #Var t, | |
1980 Ambient = #Ambient t, | |
1981 Path = #Path t, | |
1982 Sent = #Sent t, | |
1983 Insert = #Insert t, | |
1984 Delete = #Delete t, | |
1985 Update = c :: #Update t} | |
1986 | |
1987 end | |
1988 | |
1989 fun havocReln r = | |
1990 let | |
1991 fun hr p = | |
1992 case p of | |
1993 True => p | |
1994 | False => p | |
1995 | Unknown => p | |
1996 | And (p1, p2) => And (hr p1, hr p2) | |
1997 | Or (p1, p2) => Or (hr p1, hr p2) | |
1998 | Reln (r', _) => if r' = r then True else p | |
1999 | Cond (e, p) => Cond (e, hr p) | |
2000 in | |
2001 hr | |
2002 end | |
2003 | |
2004 fun evalExp env (e as (_, loc), st) = | |
2005 let | |
2006 fun default () = | |
2007 let | |
2008 val (st, nv) = St.nextVar st | |
2009 in | |
2010 (*Print.prefaces "default" [("e", MonoPrint.p_exp MonoEnv.empty e), | |
2011 ("nv", p_exp (Var nv))];*) | |
2012 (Var nv, st) | |
2013 end | |
2014 | |
2015 fun addSent (p, e, st) = | |
2016 let | |
2017 val st = if isKnown e then | |
2018 st | |
2019 else | |
2020 St.addSent (st, ((loc, e, p), Data)) | |
2021 | |
2022 val st = foldl (fn ((c, fl), st) => St.addSent (st, (c, Control fl))) st (St.paths st) | |
2023 in | |
2024 St.clearPaths st | |
2025 end | |
2026 | 1613 |
2027 fun doFfi (m, s, es) = | 1614 fun doFfi (m, s, es) = |
2028 if m = "Basis" andalso SS.member (writers, s) then | 1615 if m = "Basis" andalso SS.member (writers, s) then |
2029 let | 1616 let |
2030 val (es, st) = ListUtil.foldlMap (evalExp env) st es | 1617 fun doArgs es = |
1618 case es of | |
1619 [] => k (Recd []) | |
1620 | e :: es => | |
1621 evalExp env e (fn e => (St.send (e, loc); doArgs es)) | |
2031 in | 1622 in |
2032 (Recd [], foldl (fn (e, st) => addSent (St.ambient st, e, st)) st es) | 1623 doArgs es |
2033 end | 1624 end |
2034 else if Settings.isEffectful (m, s) andalso not (Settings.isBenignEffectful (m, s)) then | 1625 else if Settings.isEffectful (m, s) andalso not (Settings.isBenignEffectful (m, s)) then |
2035 default () | 1626 default () |
2036 else | 1627 else |
2037 let | 1628 let |
2038 val (es, st) = ListUtil.foldlMap (evalExp env) st es | 1629 fun doArgs (es, acc) = |
1630 case es of | |
1631 [] => k (Func (Other (m ^ "." ^ s), rev acc)) | |
1632 | e :: es => | |
1633 evalExp env e (fn e => doArgs (es, e :: acc)) | |
2039 in | 1634 in |
2040 (Func (Other (m ^ "." ^ s), es), st) | 1635 doArgs (es, []) |
2041 end | 1636 end |
2042 in | 1637 in |
2043 case #1 e of | 1638 case #1 e of |
2044 EPrim p => (Const p, st) | 1639 EPrim p => k (Const p) |
2045 | ERel n => (List.nth (env, n), st) | 1640 | ERel n => k (List.nth (env, n)) |
2046 | ENamed _ => default () | 1641 | ENamed _ => default () |
2047 | ECon (_, pc, NONE) => (Func (DtCon0 (patCon pc), []), st) | 1642 | ECon (_, pc, NONE) => k (Func (DtCon0 (patCon pc), [])) |
2048 | ECon (_, pc, SOME e) => | 1643 | ECon (_, pc, SOME e) => evalExp env e (fn e => k (Func (DtCon1 (patCon pc), [e]))) |
2049 let | 1644 | ENone _ => k (Func (DtCon0 "None", [])) |
2050 val (e, st) = evalExp env (e, st) | 1645 | ESome (_, e) => evalExp env e (fn e => k (Func (DtCon1 "Some", [e]))) |
2051 in | |
2052 (Func (DtCon1 (patCon pc), [e]), st) | |
2053 end | |
2054 | ENone _ => (Func (DtCon0 "None", []), st) | |
2055 | ESome (_, e) => | |
2056 let | |
2057 val (e, st) = evalExp env (e, st) | |
2058 in | |
2059 (Func (DtCon1 "Some", [e]), st) | |
2060 end | |
2061 | EFfi _ => default () | 1646 | EFfi _ => default () |
2062 | 1647 |
2063 | EFfiApp x => doFfi x | 1648 | EFfiApp x => doFfi x |
2064 | EApp ((EFfi (m, s), _), e) => doFfi (m, s, [e]) | 1649 | EApp ((EFfi (m, s), _), e) => doFfi (m, s, [e]) |
2065 | 1650 |
2066 | EApp (e1, e2) => | 1651 | EApp (e1, e2) => evalExp env e1 (fn _ => evalExp env e2 (fn _ => default ())) |
2067 let | |
2068 val (e1, st) = evalExp env (e1, st) | |
2069 in | |
2070 case e1 of | |
2071 Finish => (Finish, st) | |
2072 | _ => default () | |
2073 end | |
2074 | 1652 |
2075 | EAbs _ => default () | 1653 | EAbs _ => default () |
2076 | EUnop (s, e1) => | 1654 | EUnop (s, e1) => evalExp env e1 (fn e1 => k (Func (Other s, [e1]))) |
2077 let | 1655 | EBinop (s, e1, e2) => evalExp env e1 (fn e1 => evalExp env e2 (fn e2 => k (Func (Other s, [e1, e2])))) |
2078 val (e1, st) = evalExp env (e1, st) | |
2079 in | |
2080 (Func (Other s, [e1]), st) | |
2081 end | |
2082 | EBinop (s, e1, e2) => | |
2083 let | |
2084 val (e1, st) = evalExp env (e1, st) | |
2085 val (e2, st) = evalExp env (e2, st) | |
2086 in | |
2087 (Func (Other s, [e1, e2]), st) | |
2088 end | |
2089 | ERecord xets => | 1656 | ERecord xets => |
2090 let | 1657 let |
2091 val (xes, st) = ListUtil.foldlMap (fn ((x, e, _), st) => | 1658 fun doFields (xes, acc) = |
2092 let | 1659 case xes of |
2093 val (e, st) = evalExp env (e, st) | 1660 [] => k (Recd (rev acc)) |
2094 in | 1661 | (x, e, _) :: xes => |
2095 ((x, e), st) | 1662 evalExp env e (fn e => doFields (xes, (x, e) :: acc)) |
2096 end) st xets | |
2097 in | 1663 in |
2098 (Recd xes, st) | 1664 doFields (xets, []) |
2099 end | 1665 end |
2100 | EField (e, s) => | 1666 | EField (e, s) => evalExp env e (fn e => k (Proj (e, s))) |
2101 let | |
2102 val (e, st) = evalExp env (e, st) | |
2103 in | |
2104 (Proj (e, s), st) | |
2105 end | |
2106 | ECase (e, pes, {result = res, ...}) => | 1667 | ECase (e, pes, {result = res, ...}) => |
2107 let | 1668 evalExp env e (fn e => |
2108 val (e, st) = evalExp env (e, st) | |
2109 val (st, r) = St.nextVar st | |
2110 val orig = St.ambient st | |
2111 val origPaths = St.paths st | |
2112 | |
2113 val st = St.addPath (st, ((loc, e, orig), Case)) | |
2114 | |
2115 (*val () = Print.prefaces "Case" [("loc", Print.PD.string (ErrorMsg.spanToString loc)), | |
2116 ("e", Print.p_list (MonoPrint.p_exp MonoEnv.empty o #2) pes), | |
2117 ("orig", p_prop orig)]*) | |
2118 | |
2119 val (st, ambients, paths) = | |
2120 foldl (fn ((pt, pe), (st, ambients, paths)) => | |
2121 let | 1669 let |
2122 val (env, pp) = evalPat env e pt | 1670 val () = St.addPath (e, loc) |
2123 val (pe, st') = evalExp env (pe, St.setAmbient (st, And (orig, pp))) | |
2124 | |
2125 val this = And (removeRedundant orig (St.ambient st'), | |
2126 Reln (Eq, [Var r, pe])) | |
2127 in | 1671 in |
2128 (St.setPaths (st', origPaths), | 1672 app (fn (p, pe) => |
2129 Or (ambients, this), | 1673 let |
2130 St.paths st' @ paths) | 1674 val saved = St.stash () |
2131 end) (st, False, []) pes | 1675 |
2132 | 1676 val env = evalPat env e p |
2133 val st = case #1 res of | 1677 in |
2134 TRecord [] => St.setPaths (st, origPaths) | 1678 evalExp env pe k; |
2135 | _ => St.setPaths (st, paths) | 1679 St.reinstate saved |
2136 in | 1680 end) pes |
2137 (Var r, St.setAmbient (st, And (orig, ambients))) | 1681 end handle Cc.Contradiction => ()) |
2138 end | |
2139 | EStrcat (e1, e2) => | 1682 | EStrcat (e1, e2) => |
2140 let | 1683 evalExp env e1 (fn e1 => |
2141 val (e1, st) = evalExp env (e1, st) | 1684 evalExp env e2 (fn e2 => |
2142 val (e2, st) = evalExp env (e2, st) | 1685 k (Func (Other "cat", [e1, e2])))) |
2143 in | 1686 | EError (e, _) => evalExp env e (fn e => St.send (e, loc)) |
2144 (Func (Other "cat", [e1, e2]), st) | |
2145 end | |
2146 | EError _ => (Finish, st) | |
2147 | EReturnBlob {blob = b, mimeType = m, ...} => | 1687 | EReturnBlob {blob = b, mimeType = m, ...} => |
2148 let | 1688 evalExp env b (fn b => |
2149 val (b, st) = evalExp env (b, st) | 1689 (St.send (b, loc); |
2150 val (m, st) = evalExp env (m, st) | 1690 evalExp env m |
2151 in | 1691 (fn m => St.send (m, loc)))) |
2152 (Finish, addSent (St.ambient st, b, addSent (St.ambient st, m, st))) | |
2153 end | |
2154 | ERedirect (e, _) => | 1692 | ERedirect (e, _) => |
2155 let | 1693 evalExp env e (fn e => St.send (e, loc)) |
2156 val (e, st) = evalExp env (e, st) | |
2157 in | |
2158 (Finish, addSent (St.ambient st, e, st)) | |
2159 end | |
2160 | EWrite e => | 1694 | EWrite e => |
2161 let | 1695 evalExp env e (fn e => (St.send (e, loc); |
2162 val (e, st) = evalExp env (e, st) | 1696 k (Recd []))) |
2163 in | |
2164 (Recd [], addSent (St.ambient st, e, st)) | |
2165 end | |
2166 | ESeq (e1, e2) => | 1697 | ESeq (e1, e2) => |
2167 let | 1698 evalExp env e1 (fn _ => evalExp env e2 k) |
2168 val (_, st) = evalExp env (e1, st) | |
2169 in | |
2170 evalExp env (e2, st) | |
2171 end | |
2172 | ELet (_, _, e1, e2) => | 1699 | ELet (_, _, e1, e2) => |
2173 let | 1700 evalExp env e1 (fn e1 => evalExp (e1 :: env) e2 k) |
2174 val (e1, st) = evalExp env (e1, st) | |
2175 in | |
2176 evalExp (e1 :: env) (e2, st) | |
2177 end | |
2178 | EClosure (n, es) => | 1701 | EClosure (n, es) => |
2179 let | 1702 let |
2180 val (es, st) = ListUtil.foldlMap (evalExp env) st es | 1703 fun doArgs (es, acc) = |
1704 case es of | |
1705 [] => k (Func (Other ("Cl" ^ Int.toString n), rev acc)) | |
1706 | e :: es => | |
1707 evalExp env e (fn e => doArgs (es, e :: acc)) | |
2181 in | 1708 in |
2182 (Func (Other ("Cl" ^ Int.toString n), es), st) | 1709 doArgs (es, []) |
2183 end | 1710 end |
2184 | 1711 |
2185 | EQuery {query = q, body = b, initial = i, state = state, ...} => | 1712 | EQuery {query = q, body = b, initial = i, state = state, ...} => |
2186 let | 1713 evalExp env q (fn _ => |
2187 val (_, st) = evalExp env (q, st) | 1714 evalExp env i (fn i => |
2188 val (i, st) = evalExp env (i, st) | 1715 let |
2189 | 1716 val saved = St.stash () |
2190 val (st', r) = St.nextVar st | 1717 |
2191 val (st', acc) = St.nextVar st' | 1718 val r = Var (St.nextVar ()) |
2192 | 1719 val acc = Var (St.nextVar ()) |
2193 val (b, st') = evalExp (Var acc :: Var r :: env) (b, st') | 1720 in |
2194 val amb = removeRedundant (St.ambient st) (St.ambient st') | 1721 if MonoUtil.Exp.existsB {typ = fn _ => false, |
2195 | 1722 exp = fn (n, e) => |
2196 val (st', qp, used, _) = | 1723 case e of |
2197 queryProp env | 1724 ERel n' => n' = n |
2198 st' (fn st' => | 1725 | _ => false, |
2199 let | 1726 bind = fn (n, b) => |
2200 val (st', rv) = St.nextVar st' | 1727 case b of |
2201 in | 1728 MonoUtil.Exp.RelE _ => n + 1 |
2202 (st', Var rv) | 1729 | _ => n} |
2203 end) | 1730 0 b then |
2204 (AllCols (Var r)) q | 1731 doQuery {Env = env, |
2205 | 1732 NextVar = Var o St.nextVar, |
2206 val (st, res) = | 1733 Add = fn a => St.assert [a], |
2207 case #1 state of | 1734 Save = St.stash, |
2208 TRecord [] => | 1735 Restore = St.reinstate, |
2209 (st, Func (DtCon0 "unit", [])) | 1736 UsedExp = fn e => St.send (e, loc), |
2210 | _ => | 1737 Cont = AllCols (fn _ => (St.reinstate saved; |
2211 if varInP acc (St.ambient st') then | 1738 evalExp |
2212 let | 1739 (acc :: r :: env) |
2213 val (st, r) = St.nextVar st | 1740 b (fn _ => default ())))} q |
2214 in | 1741 else |
2215 (st, Var r) | 1742 doQuery {Env = env, |
2216 end | 1743 NextVar = Var o St.nextVar, |
2217 else | 1744 Add = fn a => St.assert [a], |
2218 let | 1745 Save = St.stash, |
2219 val (st', out) = St.nextVar st' | 1746 Restore = St.reinstate, |
2220 | 1747 UsedExp = fn e => St.send (e, loc), |
2221 val p = And (St.ambient st, | 1748 Cont = AllCols (fn x => |
2222 Or (Reln (Eq, [Var out, i]), | 1749 (St.assert [AReln (Eq, [r, x])]; |
2223 And (Reln (Eq, [Var out, b]), | 1750 evalExp (acc :: r :: env) b k))} q |
2224 And (qp, amb)))) | 1751 end)) |
2225 in | |
2226 (St.setAmbient (st', p), Var out) | |
2227 end | |
2228 | |
2229 val sent = map (fn ((loc, e, p), fl) => ((loc, e, And (qp, p)), fl)) (St.sent st') | |
2230 | |
2231 val p' = And (qp, St.ambient st') | |
2232 val paths = map (fn (p'', e) => ((loc, e, And (p', p'')), Where)) used | |
2233 in | |
2234 (res, St.addPaths (St.setSent (st, sent), paths)) | |
2235 end | |
2236 | EDml e => | 1752 | EDml e => |
2237 (case parse dml e of | 1753 (case parse dml e of |
2238 NONE => (print ("Warning: Information flow checker can't parse DML command at " | 1754 NONE => (print ("Warning: Information flow checker can't parse DML command at " |
2239 ^ ErrorMsg.spanToString loc ^ "\n"); | 1755 ^ ErrorMsg.spanToString loc ^ "\n"); |
2240 default ()) | 1756 default ()) |
2241 | SOME d => | 1757 | SOME d => |
2242 case d of | 1758 case d of |
2243 Insert (tab, es) => | 1759 Insert (tab, es) => |
2244 let | 1760 let |
2245 val (st, new) = St.nextVar st | 1761 val new = St.nextVar () |
2246 | 1762 |
2247 fun rv st = | 1763 val expIn = expIn (Var o St.nextVar) env |
2248 let | 1764 (fn _ => raise Fail "Iflow.evalExp: Bad field expression in INSERT [1]") |
2249 val (st, n) = St.nextVar st | 1765 |
2250 in | 1766 val es = map (fn (x, e) => |
2251 (st, Var n) | 1767 case expIn e of |
2252 end | 1768 inl e => (x, e) |
2253 | 1769 | inr _ => raise Fail "Iflow.evalExp: Bad field expression in INSERT [2]") |
2254 val expIn = expIn rv env (fn _ => raise Fail "Iflow.evalExp: Bad field expression in INSERT") | 1770 es |
2255 | 1771 |
2256 val (es, st) = ListUtil.foldlMap | 1772 val saved = St.stash () |
2257 (fn ((x, e), st) => | |
2258 let | |
2259 val (e, st) = case expIn (e, st) of | |
2260 (inl e, st) => (e, st) | |
2261 | (inr _, _) => raise Fail | |
2262 ("Iflow.evalExp: Selecting " | |
2263 ^ "boolean expression") | |
2264 in | |
2265 ((x, e), st) | |
2266 end) | |
2267 st es | |
2268 in | 1773 in |
2269 (Recd [], St.addInsert (st, (loc, And (St.ambient st, | 1774 St.assert [AReln (Sql (tab ^ "$New"), [Recd es])]; |
2270 Reln (Sql (tab ^ "$New"), [Recd es]))))) | 1775 St.insert loc; |
1776 St.reinstate saved; | |
1777 k (Recd []) | |
2271 end | 1778 end |
2272 | Delete (tab, e) => | 1779 | Delete (tab, e) => |
2273 let | 1780 let |
2274 val (st, old) = St.nextVar st | 1781 val old = St.nextVar () |
2275 | 1782 |
2276 fun rv st = | 1783 val expIn = expIn (Var o St.nextVar) env |
2277 let | 1784 (fn "T" => Var old |
2278 val (st, n) = St.nextVar st | 1785 | _ => raise Fail "Iflow.evalExp: Bad field expression in DELETE") |
2279 in | 1786 |
2280 (st, Var n) | 1787 val p = case expIn e of |
2281 end | 1788 inl e => raise Fail "Iflow.evalExp: DELETE with non-boolean" |
2282 | 1789 | inr p => p |
2283 val expIn = expIn rv env (fn "T" => Var old | 1790 |
2284 | _ => raise Fail "Iflow.evalExp: Bad field expression in DELETE") | 1791 val saved = St.stash () |
2285 | |
2286 val (p, st) = case expIn (e, st) of | |
2287 (inl e, _) => raise Fail "Iflow.evalExp: DELETE with non-boolean" | |
2288 | (inr p, st) => (p, st) | |
2289 | |
2290 val p = And (p, | |
2291 And (Reln (Sql "$Old", [Var old]), | |
2292 Reln (Sql tab, [Var old]))) | |
2293 | |
2294 val st = St.setAmbient (st, havocReln (Sql tab) (St.ambient st)) | |
2295 in | 1792 in |
2296 (Recd [], St.addDelete (st, (loc, And (St.ambient st, p)))) | 1793 St.assert [AReln (Sql "$Old", [Var old]), |
1794 AReln (Sql tab, [Var old])]; | |
1795 decomp {Save = St.stash, | |
1796 Restore = St.reinstate, | |
1797 Add = fn a => St.assert [a]} p | |
1798 (fn () => (St.delete loc; | |
1799 St.reinstate saved; | |
1800 St.havocReln (Sql tab); | |
1801 k (Recd [])) | |
1802 handle Cc.Contradiction => ()) | |
2297 end | 1803 end |
2298 | Update (tab, fs, e) => | 1804 | Update (tab, fs, e) => |
2299 let | 1805 let |
2300 val (st, new) = St.nextVar st | 1806 val new = St.nextVar () |
2301 val (st, old) = St.nextVar st | 1807 val old = St.nextVar () |
2302 | 1808 |
2303 fun rv st = | 1809 val expIn = expIn (Var o St.nextVar) env |
2304 let | 1810 (fn "T" => Var old |
2305 val (st, n) = St.nextVar st | 1811 | _ => raise Fail "Iflow.evalExp: Bad field expression in UPDATE") |
2306 in | 1812 |
2307 (st, Var n) | 1813 val fs = map |
2308 end | 1814 (fn (x, e) => |
2309 | 1815 (x, case expIn e of |
2310 val expIn = expIn rv env (fn "T" => Var old | 1816 inl e => e |
2311 | _ => raise Fail "Iflow.evalExp: Bad field expression in UPDATE") | 1817 | inr _ => raise Fail |
2312 | 1818 ("Iflow.evalExp: Selecting " |
2313 val (fs, st) = ListUtil.foldlMap | 1819 ^ "boolean expression"))) |
2314 (fn ((x, e), st) => | 1820 fs |
2315 let | |
2316 val (e, st) = case expIn (e, st) of | |
2317 (inl e, st) => (e, st) | |
2318 | (inr _, _) => raise Fail | |
2319 ("Iflow.evalExp: Selecting " | |
2320 ^ "boolean expression") | |
2321 in | |
2322 ((x, e), st) | |
2323 end) | |
2324 st fs | |
2325 | 1821 |
2326 val fs' = case SM.find (!tabs, tab) of | 1822 val fs' = case SM.find (!tabs, tab) of |
2327 NONE => raise Fail "Iflow.evalExp: Updating unknown table" | 1823 NONE => raise Fail "Iflow.evalExp: Updating unknown table" |
2328 | SOME (fs', _) => fs' | 1824 | SOME (fs', _) => fs' |
2329 | 1825 |
2331 if List.exists (fn (f', _) => f' = f) fs then | 1827 if List.exists (fn (f', _) => f' = f) fs then |
2332 fs | 1828 fs |
2333 else | 1829 else |
2334 (f, Proj (Var old, f)) :: fs) fs fs' | 1830 (f, Proj (Var old, f)) :: fs) fs fs' |
2335 | 1831 |
2336 val (p, st) = case expIn (e, st) of | 1832 val p = case expIn e of |
2337 (inl e, _) => raise Fail "Iflow.evalExp: UPDATE with non-boolean" | 1833 inl e => raise Fail "Iflow.evalExp: UPDATE with non-boolean" |
2338 | (inr p, st) => (p, st) | 1834 | inr p => p |
2339 | 1835 val saved = St.stash () |
2340 val p = And (p, | |
2341 And (Reln (Sql (tab ^ "$New"), [Recd fs]), | |
2342 And (Reln (Sql "$Old", [Var old]), | |
2343 Reln (Sql tab, [Var old])))) | |
2344 | |
2345 val st = St.setAmbient (st, havocReln (Sql tab) (St.ambient st)) | |
2346 in | 1836 in |
2347 (Recd [], St.addUpdate (st, (loc, And (St.ambient st, p)))) | 1837 St.assert [AReln (Sql (tab ^ "$New"), [Recd fs]), |
1838 AReln (Sql "$Old", [Var old]), | |
1839 AReln (Sql tab, [Var old])]; | |
1840 decomp {Save = St.stash, | |
1841 Restore = St.reinstate, | |
1842 Add = fn a => St.assert [a]} p | |
1843 (fn () => (St.update loc; | |
1844 St.reinstate saved; | |
1845 St.havocReln (Sql tab); | |
1846 k (Recd [])) | |
1847 handle Cc.Contradiction => ()) | |
2348 end) | 1848 end) |
2349 | 1849 |
2350 | ENextval (EPrim (Prim.String seq), _) => | 1850 | ENextval (EPrim (Prim.String seq), _) => |
2351 let | 1851 let |
2352 val (st, nv) = St.nextVar st | 1852 val nv = St.nextVar () |
2353 in | 1853 in |
2354 (Var nv, St.setAmbient (st, And (St.ambient st, Reln (Sql (String.extract (seq, 3, NONE)), [Var nv])))) | 1854 St.assert [AReln (Sql (String.extract (seq, 3, NONE)), [Var nv])]; |
1855 k (Var nv) | |
2355 end | 1856 end |
2356 | ENextval _ => default () | 1857 | ENextval _ => default () |
2357 | ESetval _ => default () | 1858 | ESetval _ => default () |
2358 | 1859 |
2359 | EUnurlify ((EFfiApp ("Basis", "get_cookie", _), _), _, _) => | 1860 | EUnurlify ((EFfiApp ("Basis", "get_cookie", _), _), _, _) => |
2360 let | 1861 let |
2361 val (st, nv) = St.nextVar st | 1862 val nv = St.nextVar () |
2362 in | 1863 in |
2363 (Var nv, St.setAmbient (st, And (St.ambient st, Reln (Known, [Var nv])))) | 1864 St.assert [AReln (Known, [Var nv])]; |
1865 k (Var nv) | |
2364 end | 1866 end |
2365 | 1867 |
2366 | EUnurlify _ => default () | 1868 | EUnurlify _ => default () |
2367 | EJavaScript _ => default () | 1869 | EJavaScript _ => default () |
2368 | ESignalReturn _ => default () | 1870 | ESignalReturn _ => default () |
2374 | ESpawn _ => default () | 1876 | ESpawn _ => default () |
2375 end | 1877 end |
2376 | 1878 |
2377 fun check file = | 1879 fun check file = |
2378 let | 1880 let |
1881 val () = St.reset () | |
1882 | |
2379 val file = MonoReduce.reduce file | 1883 val file = MonoReduce.reduce file |
2380 val file = MonoOpt.optimize file | 1884 val file = MonoOpt.optimize file |
2381 val file = Fuse.fuse file | 1885 val file = Fuse.fuse file |
2382 val file = MonoOpt.optimize file | 1886 val file = MonoOpt.optimize file |
2383 val file = MonoShake.shake file | 1887 val file = MonoShake.shake file |
2386 val exptd = foldl (fn ((d, _), exptd) => | 1890 val exptd = foldl (fn ((d, _), exptd) => |
2387 case d of | 1891 case d of |
2388 DExport (_, _, n, _, _, _) => IS.add (exptd, n) | 1892 DExport (_, _, n, _, _, _) => IS.add (exptd, n) |
2389 | _ => exptd) IS.empty file | 1893 | _ => exptd) IS.empty file |
2390 | 1894 |
2391 fun decl ((d, _), (vals, inserts, deletes, updates, client, insert, delete, update)) = | 1895 fun decl (d, _) = |
2392 case d of | 1896 case d of |
2393 DTable (tab, fs, pk, _) => | 1897 DTable (tab, fs, pk, _) => |
2394 let | 1898 let |
2395 val ks = | 1899 val ks = |
2396 case #1 pk of | 1900 case #1 pk of |
2399 [] => [] | 1903 [] => [] |
2400 | pk => [pk]) | 1904 | pk => [pk]) |
2401 | _ => [] | 1905 | _ => [] |
2402 in | 1906 in |
2403 if size tab >= 3 then | 1907 if size tab >= 3 then |
2404 (tabs := SM.insert (!tabs, String.extract (tab, 3, NONE), | 1908 tabs := SM.insert (!tabs, String.extract (tab, 3, NONE), |
2405 (map #1 fs, | 1909 (map #1 fs, |
2406 map (map (fn s => str (Char.toUpper (String.sub (s, 3))) | 1910 map (map (fn s => str (Char.toUpper (String.sub (s, 3))) |
2407 ^ String.extract (s, 4, NONE))) ks)); | 1911 ^ String.extract (s, 4, NONE))) ks)) |
2408 (vals, inserts, deletes, updates, client, insert, delete, update)) | |
2409 else | 1912 else |
2410 raise Fail "Table name does not begin with uw_" | 1913 raise Fail "Table name does not begin with uw_" |
2411 end | 1914 end |
2412 | DVal (_, n, _, e, _) => | 1915 | DVal (_, n, _, e, _) => |
2413 let | 1916 let |
2414 val isExptd = IS.member (exptd, n) | 1917 val isExptd = IS.member (exptd, n) |
2415 | 1918 |
2416 fun deAbs (e, env, nv, p) = | 1919 val saved = St.stash () |
1920 | |
1921 fun deAbs (e, env, ps) = | |
2417 case #1 e of | 1922 case #1 e of |
2418 EAbs (_, _, _, e) => deAbs (e, Var nv :: env, nv + 1, | 1923 EAbs (_, _, _, e) => |
2419 if isExptd then | 1924 let |
2420 And (p, Reln (Known, [Var nv])) | 1925 val nv = Var (St.nextVar ()) |
2421 else | 1926 in |
2422 p) | 1927 deAbs (e, nv :: env, |
2423 | _ => (e, env, nv, p) | 1928 if isExptd then |
2424 | 1929 AReln (Known, [nv]) :: ps |
2425 val (e, env, nv, p) = deAbs (e, [], 1, True) | 1930 else |
2426 | 1931 ps) |
2427 val (_, st) = evalExp env (e, St.create {Var = nv, | 1932 end |
2428 Ambient = p}) | 1933 | _ => (e, env, ps) |
1934 | |
1935 val (e, env, ps) = deAbs (e, [], []) | |
2429 in | 1936 in |
2430 (St.sent st @ vals, St.inserted st @ inserts, St.deleted st @ deletes, St.updated st @ updates, | 1937 St.assert ps; |
2431 client, insert, delete, update) | 1938 (evalExp env e (fn _ => ()) handle Cc.Contradiction => ()); |
1939 St.reinstate saved | |
2432 end | 1940 end |
2433 | 1941 |
2434 | DPolicy pol => | 1942 | DPolicy pol => |
2435 let | 1943 let |
2436 fun rv rvN = (rvN + 1, Lvar rvN) | 1944 val rvN = ref 0 |
1945 fun rv () = | |
1946 let | |
1947 val n = !rvN | |
1948 in | |
1949 rvN := n + 1; | |
1950 Lvar n | |
1951 end | |
1952 | |
1953 val atoms = ref ([] : atom list) | |
1954 fun doQ k = doQuery {Env = [], | |
1955 NextVar = rv, | |
1956 Add = fn a => atoms := a :: !atoms, | |
1957 Save = fn () => !atoms, | |
1958 Restore = fn ls => atoms := ls, | |
1959 UsedExp = fn _ => (), | |
1960 Cont = SomeCol (fn es => k (!atoms, es))} | |
2437 in | 1961 in |
2438 case pol of | 1962 case pol of |
2439 PolClient e => | 1963 PolClient e => |
2440 let | 1964 doQ (fn (ats, es) => St.allowSend (ats, es)) e |
2441 val (_, p, _, outs) = queryProp [] 0 rv SomeCol e | |
2442 in | |
2443 (vals, inserts, deletes, updates, (p, outs) :: client, insert, delete, update) | |
2444 end | |
2445 | PolInsert e => | 1965 | PolInsert e => |
2446 let | 1966 doQ (fn (ats, _) => St.allowInsert ats) e |
2447 val p = insertProp 0 rv e | |
2448 in | |
2449 (vals, inserts, deletes, updates, client, p :: insert, delete, update) | |
2450 end | |
2451 | PolDelete e => | 1967 | PolDelete e => |
2452 let | 1968 doQ (fn (ats, _) => St.allowDelete ats) e |
2453 val p = deleteProp 0 rv e | |
2454 in | |
2455 (vals, inserts, deletes, updates, client, insert, p :: delete, update) | |
2456 end | |
2457 | PolUpdate e => | 1969 | PolUpdate e => |
2458 let | 1970 doQ (fn (ats, _) => St.allowUpdate ats) e |
2459 val p = updateProp 0 rv e | |
2460 in | |
2461 (vals, inserts, deletes, updates, client, insert, delete, p :: update) | |
2462 end | |
2463 | PolSequence e => | 1971 | PolSequence e => |
2464 (case #1 e of | 1972 (case #1 e of |
2465 EPrim (Prim.String seq) => | 1973 EPrim (Prim.String seq) => |
2466 let | 1974 let |
2467 val p = Reln (Sql (String.extract (seq, 3, NONE)), [Lvar 0]) | 1975 val p = AReln (Sql (String.extract (seq, 3, NONE)), [Lvar 0]) |
2468 val outs = [Lvar 0] | 1976 val outs = [Lvar 0] |
2469 in | 1977 in |
2470 (vals, inserts, deletes, updates, (p, outs) :: client, insert, delete, update) | 1978 St.allowSend ([p], outs) |
2471 end | 1979 end |
2472 | _ => (vals, inserts, deletes, updates, client, insert, delete, update)) | 1980 | _ => ()) |
2473 end | 1981 end |
2474 | 1982 |
2475 | _ => (vals, inserts, deletes, updates, client, insert, delete, update) | 1983 | _ => () |
2476 | |
2477 val () = reset () | |
2478 | |
2479 val (vals, inserts, deletes, updates, client, insert, delete, update) = | |
2480 foldl decl ([], [], [], [], [], [], [], []) file | |
2481 | |
2482 | |
2483 val decompH = decomp true (fn (e1, e2) => e1 andalso e2 ()) | |
2484 val decompG = decomp false (fn (e1, e2) => e1 orelse e2 ()) | |
2485 | |
2486 fun doDml (cmds, pols) = | |
2487 app (fn (loc, p) => | |
2488 if decompH p | |
2489 (fn hyps => | |
2490 let | |
2491 val cc = ccOf hyps | |
2492 in | |
2493 List.exists (fn p' => | |
2494 if decompG p' | |
2495 (fn goals => imply (cc, hyps, goals, NONE)) then | |
2496 ((*reset (); | |
2497 Print.prefaces "Match" [("hyp", p_prop p), | |
2498 ("goal", p_prop p')];*) | |
2499 true) | |
2500 else | |
2501 false) | |
2502 pols | |
2503 end handle Cc.Contradiction => true) then | |
2504 () | |
2505 else | |
2506 (ErrorMsg.errorAt loc "The information flow policy may be violated here."; | |
2507 Print.preface ("The state satisifies this predicate:", p_prop p))) cmds | |
2508 in | 1984 in |
2509 app (fn ((loc, e, p), fl) => | 1985 app decl file |
2510 let | |
2511 fun doOne e = | |
2512 let | |
2513 val p = And (p, Reln (Eq, [Var 0, e])) | |
2514 in | |
2515 if decompH p | |
2516 (fn hyps => | |
2517 let | |
2518 val cc = ccOf hyps | |
2519 | |
2520 fun relevant () = | |
2521 let | |
2522 val avail = foldl (fn (AReln (Sql tab, _), avail) => | |
2523 SS.add (avail, tab) | |
2524 | (_, avail) => avail) SS.empty hyps | |
2525 | |
2526 val ls = List.filter | |
2527 (fn (g1, _) => | |
2528 decompG g1 | |
2529 (List.all (fn AReln (Sql tab, _) => | |
2530 SS.member (avail, tab) | |
2531 | _ => true))) client | |
2532 in | |
2533 (*print ("Max: " ^ Int.toString (length ls) ^ "\n");*) | |
2534 ls | |
2535 end | |
2536 | |
2537 fun tryCombos (maxLv, pols, g, outs) = | |
2538 case pols of | |
2539 [] => | |
2540 decompG g | |
2541 (fn goals => imply (cc, hyps, goals, SOME outs)) | |
2542 | (g1, outs1) :: pols => | |
2543 let | |
2544 val g1 = bumpLvarsP (maxLv + 1) g1 | |
2545 val outs1 = map (bumpLvars (maxLv + 1)) outs1 | |
2546 fun skip () = tryCombos (maxLv, pols, g, outs) | |
2547 in | |
2548 skip () | |
2549 orelse tryCombos (Int.max (maxLv, | |
2550 maxLvarP g1), | |
2551 pols, | |
2552 And (g1, g), | |
2553 outs1 @ outs) | |
2554 end | |
2555 in | |
2556 (fl <> Control Where | |
2557 andalso imply (cc, hyps, [AReln (Known, [Var 0])], SOME [Var 0])) | |
2558 orelse List.exists (fn (p', outs) => | |
2559 decompG p' | |
2560 (fn goals => imply (cc, hyps, goals, | |
2561 SOME outs))) | |
2562 client | |
2563 orelse tryCombos (0, relevant (), True, []) | |
2564 orelse (reset (); | |
2565 Print.preface ("Untenable hypotheses" | |
2566 ^ (case fl of | |
2567 Control Where => " (WHERE clause)" | |
2568 | Control Case => " (case discriminee)" | |
2569 | Data => " (returned data value)"), | |
2570 Print.p_list p_atom hyps); | |
2571 (*Print.preface ("DB", Cc.p_database cc);*) | |
2572 false) | |
2573 end handle Cc.Contradiction => true) then | |
2574 () | |
2575 else | |
2576 ErrorMsg.errorAt loc "The information flow policy may be violated here." | |
2577 end | |
2578 | |
2579 fun doAll e = | |
2580 case e of | |
2581 Const _ => () | |
2582 | Var _ => doOne e | |
2583 | Lvar _ => raise Fail "Iflow.doAll: Lvar" | |
2584 | Func (UnCon _, [_]) => doOne e | |
2585 | Func (_, es) => app doAll es | |
2586 | Recd xes => app (doAll o #2) xes | |
2587 | Proj _ => doOne e | |
2588 | Finish => () | |
2589 in | |
2590 doAll e | |
2591 end) vals; | |
2592 | |
2593 doDml (inserts, insert); | |
2594 doDml (deletes, delete); | |
2595 doDml (updates, update) | |
2596 end | 1986 end |
2597 | 1987 |
2598 val check = fn file => | 1988 val check = fn file => |
2599 let | 1989 let |
2600 val oldInline = Settings.getMonoInline () | 1990 val oldInline = Settings.getMonoInline () |