package goblint
Static analysis framework for C
Install
dune-project
Dependency
Authors
Maintainers
Sources
goblint-2.6.0.tbz
sha256=20d5b7332a9f6072ab9ba86c4a53b898eaf681286c56a8805c41850bbf3ddf41
sha512=7c7685cfcd9aa866bc40e813df2bfcb3c79b3d40e615d8d6d0939c5798b9d70dd7f2ba87a741f5ba0ce891e9d254627207fb28057f1f2f6611e4e0d128fd6a71
doc/src/goblint.solver/td_simplified.ml.html
Source file td_simplified.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
(** Top-down solver with side effects. Simplified version of the td3 solver ([td_simplified]).*) (** Top down solver that uses the box-operator for widening/narrowing at widening points. *) open Batteries open Goblint_constraint.ConstrSys open Goblint_constraint.SolverTypes open Messages module M = Messages module Base : GenericEqSolver = functor (S:EqConstrSys) -> functor (HM:Hashtbl.S with type key = S.v) -> struct open SolverBox.Warrow (S.Dom) include Generic.SolverStats (S) (HM) module VS = Set.Make (S.Var) let solve st vs = let called = HM.create 10 in let infl = HM.create 10 in let rho = HM.create 10 in let wpoint = HM.create 10 in let stable = HM.create 10 in let () = print_solver_stats := fun () -> Logs.debug "|rho|=%d" (HM.length rho); Logs.debug "|stable|=%d" (HM.length stable); Logs.debug "|infl|=%d" (HM.length infl); Logs.debug "|wpoint|=%d" (HM.length wpoint); Logs.info "|called|=%d" (HM.length called); print_context_stats rho in let add_infl y x = if tracing then trace "infl" "add_infl %a %a" S.Var.pretty_trace y S.Var.pretty_trace x; HM.replace infl y (VS.add x (HM.find_default infl y VS.empty)); in let init x = if not (HM.mem rho x) then ( new_var_event x; if tracing then trace "init" "init %a" S.Var.pretty_trace x; HM.replace rho x (S.Dom.bot ()) ) in let eq x get set = if tracing then trace "eq" "eq %a" S.Var.pretty_trace x; match S.system x with | None -> S.Dom.bot () | Some f -> f get set in let rec destabilize x = if tracing then trace "destab" "destabilize %a" S.Var.pretty_trace x; let w = HM.find_default infl x VS.empty in HM.replace infl x VS.empty; VS.iter (fun y -> if tracing then trace "destab" "stable remove %a" S.Var.pretty_trace y; HM.remove stable y; destabilize y ) w in let rec query x y = (* ~eval in td3 *) if tracing then trace "solver_query" "entering query for %a; stable %b; called %b" S.Var.pretty_trace y (HM.mem stable y) (HM.mem called y); get_var_event y; if not (HM.mem called y) then ( if S.system y = None then ( init y; HM.replace stable y () ) else ( HM.replace called y (); if tracing then trace "iter" "iterate called from query"; iterate y; HM.remove called y) ) else ( if tracing && not (HM.mem wpoint y) then trace "wpoint" "query adding wpoint %a" S.Var.pretty_trace y; HM.replace wpoint y (); ); let tmp = HM.find rho y in add_infl y x; if tracing then trace "answer" "exiting query for %a\nanswer: %a" S.Var.pretty_trace y S.Dom.pretty tmp; tmp and side x y d = (* side from x to y; only to variables y w/o rhs; x only used for trace *) if tracing then trace "side" "side to %a (wpx: %b) from %a; value: %a" S.Var.pretty_trace y (HM.mem wpoint y) S.Var.pretty_trace x S.Dom.pretty d; assert (S.system y = None); init y; let widen a b = if M.tracing then M.trace "wpoint" "side widen %a" S.Var.pretty_trace y; S.Dom.widen a (S.Dom.join a b) in let op a b = if HM.mem wpoint y then widen a b else S.Dom.join a b in let old = HM.find rho y in let tmp = op old d in HM.replace stable y (); if not (S.Dom.leq tmp old) then ( if tracing && not (S.Dom.is_bot old) then trace "update" "side to %a (wpx: %b) from %a new: %a" S.Var.pretty_trace y (HM.mem wpoint y) S.Var.pretty_trace x S.Dom.pretty tmp; HM.replace rho y tmp; destabilize y; (* make y a widening point. This will only matter for the next side _ y. *) if tracing && not (HM.mem wpoint y) then trace "wpoint" "side adding wpoint %a" S.Var.pretty_trace y; HM.replace wpoint y () ) and iterate x = (* ~(inner) solve in td3*) if tracing then trace "iter" "begin iterate %a, called: %b, stable: %b, wpoint: %b" S.Var.pretty_trace x (HM.mem called x) (HM.mem stable x) (HM.mem wpoint x); init x; assert (S.system x <> None); if not (HM.mem stable x) then ( HM.replace stable x (); let wp = HM.mem wpoint x in (* if x becomes a wpoint during eq, checking this will delay widening until next iterate *) let eqd = eq x (query x) (side x) in (* d from equation/rhs *) let old = HM.find rho x in (* d from older iterate *) let wpd = (* d after widen/narrow (if wp) *) if not wp then eqd else ( if M.tracing then M.trace "wpoint" "widen %a" S.Var.pretty_trace x; box old eqd) in if not (Timing.wrap "S.Dom.equal" (fun () -> S.Dom.equal old wpd) ()) then ( (* old != wpd *) if tracing && not (S.Dom.is_bot old) then trace "update" "%a (wpx: %b): %a" S.Var.pretty_trace x (HM.mem wpoint x) S.Dom.pretty_diff (wpd, old); update_var_event x old wpd; HM.replace rho x wpd; destabilize x; if tracing then trace "iter" "iterate changed %a" S.Var.pretty_trace x; (iterate[@tailcall]) x ) else ( (* old == wpd *) if not (HM.mem stable x) then ( (* value unchanged, but not stable, i.e. destabilized itself during rhs *) if tracing then trace "iter" "iterate still unstable %a" S.Var.pretty_trace x; (iterate[@tailcall]) x ) else ( (* this makes e.g. nested loops precise, ex. tests/regression/34-localization/01-nested.c - if we do not remove wpoint, the inner loop head will stay a wpoint and widen the outer loop variable. *) if tracing && (HM.mem wpoint x) then trace "wpoint" "iterate removing wpoint %a" S.Var.pretty_trace x; HM.remove wpoint x ) ) ) in let set_start (x,d) = init x; HM.replace rho x d; HM.replace stable x (); in (* beginning of main solve *) start_event (); List.iter set_start st; List.iter init vs; (* If we have multiple start variables vs, we might solve v1, then while solving v2 we side some global which v1 depends on with a new value. Then v1 is no longer stable and we have to solve it again. *) let i = ref 0 in let rec solver () = (* as while loop in paper *) incr i; let unstable_vs = List.filter (neg (HM.mem stable)) vs in if unstable_vs <> [] then ( if Logs.Level.should_log Debug then ( if !i = 1 then Logs.newline (); Logs.debug "Unstable solver start vars in %d. phase:" !i; List.iter (fun v -> Logs.debug "\t%a" S.Var.pretty_trace v) unstable_vs; Logs.newline (); flush_all (); ); List.iter (fun x -> HM.replace called x (); if tracing then trace "multivar" "solving for %a" S.Var.pretty_trace x; iterate x; HM.remove called x ) unstable_vs; solver (); ) in solver (); (* After termination, only those variables are stable which are * - reachable from any of the queried variables vs, or * - effected by side-effects and have no constraints on their own (this should be the case for all of our analyses). *) stop_event (); if Logs.Level.should_log Debug then ( Logs.debug "Data after iterate completed"; Logs.debug "|rho|=%d" (HM.length rho); Logs.debug "|stable|=%d" (HM.length stable); Logs.debug "|infl|=%d" (HM.length infl); Logs.debug "|wpoint|=%d" (HM.length wpoint) ); if GobConfig.get_bool "dbg.print_wpoints" then ( Logs.newline (); Logs.debug "Widening points:"; HM.iter (fun k () -> Logs.debug "%a" S.Var.pretty_trace k) wpoint; Logs.newline (); ); rho end let () = Selector.add_solver ("td_simplified", (module PostSolver.DemandEqIncrSolverFromEqSolver (Base)));
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>