Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file postSolver.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333(** Extra constraint system evaluation pass for warning generation, verification, pruning, etc. *)openBatteriesopenConstrSysopenGobConfigmodulePretty=GoblintCil.PrettymoduleM=Messages(** Postsolver with hooks. *)moduletypeS=sigmoduleS:EqConstrSysmoduleVH:Hashtbl.Swithtypekey=S.vvalinit:unit->unitvalone_side:vh:S.Dom.tVH.t->x:S.v->y:S.v->d:S.Dom.t->unitvalone_constraint:vh:S.Dom.tVH.t->x:S.v->rhs:S.Dom.t->unitvalfinalize:vh:S.Dom.tVH.t->reachable:unitVH.t->unitend(** Functorial postsolver for any system. *)moduletypeF=functor(S:EqConstrSys)(VH:Hashtbl.Swithtypekey=S.v)->SwithmoduleS=SandmoduleVH=VH(** Base implementation for postsolver. *)moduleUnit:F=functor(S:EqConstrSys)(VH:Hashtbl.Swithtypekey=S.v)->structmoduleS=SmoduleVH=VHletinit()=()letone_side~vh~x~y~d=()letone_constraint~vh~x~rhs=()letfinalize~vh~reachable=()end(** Sequential composition of two postsolvers. *)moduleCompose(PS1:S)(PS2:SwithmoduleS=PS1.SandmoduleVH=PS1.VH):SwithmoduleS=PS1.SandmoduleVH=PS1.VH=struct(* Assumes PS1 and PS2 have actually same modules!
Module constraint only gives type-wise equality. *)moduleS=PS1.SmoduleVH=PS1.VHletinit()=PS1.init();PS2.init()letone_side~vh~x~y~d=PS1.one_side~vh~x~y~d;PS2.one_side~vh~x~y~dletone_constraint~vh~x~rhs=PS1.one_constraint~vh~x~rhs;PS2.one_constraint~vh~x~rhsletfinalize~vh~reachable=PS1.finalize~vh~reachable;PS2.finalize~vh~reachableend(** Postsolver for pruning solution using reachability. *)modulePrune:F=functor(S:EqConstrSys)(VH:Hashtbl.Swithtypekey=S.v)->structincludeUnit(S)(VH)letfinalize~vh~reachable=Logs.debug"Pruning result";VH.filteri_inplace(funx_->VH.memreachablex)vhend(** Postsolver for verifying solution in demand-driven fashion. *)moduleVerify:F=functor(S:EqConstrSys)(VH:Hashtbl.Swithtypekey=S.v)->structincludeUnit(S)(VH)letinit()=AnalysisState.verified:=Sometrueletcomplain_constraintx~lhs~rhs=AnalysisState.verified:=Somefalse;M.msg_finalError~category:Unsound"Fixpoint not reached";Logs.error"Fixpoint not reached at %a\n @[Solver computed:\n%a\nRight-Hand-Side:\n%a\nDifference: %a\n@]"S.Var.pretty_tracexS.Dom.prettylhsS.Dom.prettyrhsS.Dom.pretty_diff(rhs,lhs)letcomplain_sidexy~lhs~rhs=AnalysisState.verified:=Somefalse;M.msg_finalError~category:Unsound"Fixpoint not reached";Logs.error"Fixpoint not reached at %a\nOrigin: %a\n @[Solver computed:\n%a\nSide-effect:\n%a\nDifference: %a\n@]"S.Var.pretty_traceyS.Var.pretty_tracexS.Dom.prettylhsS.Dom.prettyrhsS.Dom.pretty_diff(rhs,lhs)letone_side~vh~x~y~d=lety_lhs=tryVH.findvhywithNot_found->S.Dom.bot()inifS.Var.is_write_onlyythenVH.replacevhy(S.Dom.joiny_lhsd)(* HACK: allow warnings/accesses to be added without complaining *)elseifnot(S.Dom.leqdy_lhs)thencomplain_sidexy~lhs:y_lhs~rhs:dletone_constraint~vh~x~rhs=letlhs=tryVH.findvhxwithNot_found->S.Dom.bot()inifnot(S.Dom.leqrhslhs)thencomplain_constraintx~lhs~rhsend(** Postsolver for enabling messages (warnings) output. *)moduleWarn:F=functor(S:EqConstrSys)(VH:Hashtbl.Swithtypekey=S.v)->structincludeUnit(S)(VH)letold_should_warn=refNoneletinit()=old_should_warn:=Some!AnalysisState.should_warn;AnalysisState.should_warn:=trueletfinalize~vh~reachable=AnalysisState.should_warn:=Option.get!old_should_warnend(** Postsolver for save_run option. *)moduleSaveRun:F=functor(S:EqConstrSys)(VH:Hashtbl.Swithtypekey=S.v)->structincludeUnit(S)(VH)letfinalize~vh~reachable=(* copied from Control.solve_and_postprocess *)letsolver_file="solver.marshalled"inletgobview=get_bool"gobview"inletsave_run_str=leto=get_string"save_run"inifo=""then(ifgobviewthen"run"else"")elseoinletsave_run=Fpath.vsave_run_strinletsolver=Fpath.(save_run/solver_file)inLogs.Format.debug"Saving the solver result to %a"Fpath.ppsolver;GobSys.mkdir_or_existssave_run;Serialize.marshalvhsolverend(** [EqConstrSys] together with start values to be used. *)moduletypeStartEqConstrSys=sigincludeEqConstrSysvalstarts:(v*d)listend(** Join start values into right-hand sides.
This simplifies start handling in [Make]. *)moduleEqConstrSysFromStartEqConstrSys(S:StartEqConstrSys):EqConstrSyswithtypev=S.vandtyped=S.dandmoduleVar=S.VarandmoduleDom=S.Dom=structincludeSmoduleVH=Hashtbl.Make(S.Var)(* starts as Hashtbl for quick lookup *)letstarth=VH.of_listS.startsletsystemx=matchS.systemx,VH.find_optionstarthxwith|f_opt,None->f_opt|None,Somed->Some(fun__->d)|Somef,Somed->Some(fungetset->S.Dom.join(fgetset)d)end(** Postsolver for incremental. *)moduletypeIncrS=sigincludeSvalinit_reachable:vh:S.Dom.tVH.t->unitVH.tend(** Make incremental postsolving function from incremental postsolver. *)moduleMakeIncr(PS:IncrS)=structmoduleS=PS.SmoduleVH=PS.VHletpostxsvsvh=Logs.debug"Postsolving";letmoduleStartS=structincludeSletstarts=xsendinletmoduleS=EqConstrSysFromStartEqConstrSys(StartS)inAnalysisState.postsolving:=true;PS.init();letreachable=PS.init_reachable~vhinletrecone_varx=ifM.tracingthenM.trace"postsolver""one_var %a reachable=%B system=%B"S.Var.pretty_tracex(VH.memreachablex)(Option.is_some(S.systemx));ifnot(VH.memreachablex)then(VH.replacereachablex();Option.may(one_constraintx)(S.systemx))andone_constraintxf=letgety=one_vary;tryVH.findvhywithNot_found->S.Dom.bot()inletsetyd=ifM.tracingthenM.trace"postsolver""one_side %a %a %a"S.Var.pretty_tracexS.Var.pretty_traceyS.Dom.prettyd;PS.one_side~vh~x~y~d;(* check before recursing *)one_varyinletrhs=fgetsetinifM.tracingthenM.trace"postsolver""one_constraint %a %a"S.Var.pretty_tracexS.Dom.prettyrhs;PS.one_constraint~vh~x~rhsin(Timing.wrap"postsolver_iter"(List.iterone_var))vs;PS.finalize~vh~reachable;AnalysisState.postsolving:=falseletpostxsvsvh=Timing.wrap"postsolver"(postxsvs)vhend(** List of postsolvers. *)moduletypeMakeListArg=sig(* Specify S and VH here to constrain all postsolvers to use the same. *)moduleS:EqConstrSysmoduleVH:Hashtbl.Swithtypekey=S.v(* Auxiliary module type because first-class module types cannot contain module constraints. *)moduletypeM=SwithmoduleS=SandmoduleVH=VHvalpostsolvers:(moduleM)listend(** List of postsolvers for incremental. *)moduletypeMakeIncrListArg=sigincludeMakeListArgvalinit_reachable:vh:S.Dom.tVH.t->unitVH.tend(** Make incremental postsolving function from incremental list of postsolvers.
If list is empty, no postsolving is performed. *)moduleMakeIncrList(Arg:MakeIncrListArg)=structmoduleS=Arg.SmoduleVH=Arg.VHletpostsolver_opt:(moduleArg.M)option=matchArg.postsolverswith|[]->None|postsolvers->letcompose(modulePS1:Arg.M)(modulePS2:Arg.M)=(module(Compose(PS1)(PS2)):Arg.M)inSome(List.reducecomposepostsolvers)letpostxsvsvh=matchpostsolver_optwith|None->()|Some(modulePS)->letmoduleIncrPS=structincludePSletinit_reachable=Arg.init_reachableendinletmoduleM=MakeIncr(IncrPS)inM.postxsvsvhend(** Make complete (non-incremental) postsolving function from list of postsolvers.
If list is empty, no postsolving is performed. *)moduleMakeList(Arg:MakeListArg)=structmoduleIncrArg=structincludeArgletinit_reachable~vh=VH.create(VH.lengthvh)endincludeMakeIncrList(IncrArg)end(** Standard postsolver options. *)moduletypeMakeStdArg=sigvalshould_prune:boolvalshould_verify:boolvalshould_warn:boolvalshould_save_run:boolend(** List of standard postsolvers. *)moduleListArgFromStdArg(S:EqConstrSys)(VH:Hashtbl.Swithtypekey=S.v)(Arg:MakeStdArg):MakeListArgwithmoduleS=SandmoduleVH=VH=structopenArgmoduleS=SmoduleVH=VHmoduletypeM=SwithmoduleS=SandmoduleVH=VHletpostsolvers:(bool*(moduleF))list=[(should_prune,(modulePrune));(should_verify,(moduleVerify));(should_warn,(moduleWarn));(should_save_run,(moduleSaveRun));]letpostsolvers=postsolvers|>List.filterfst|>List.mapsnd|>List.map(fun(moduleF:F)->(moduleF(S)(VH):M))end(* Here to avoid module cycle between ConstrSys and PostSolver. *)(** Convert a non-incremental solver into an "incremental" solver.
It will solve from scratch, perform standard postsolving and have no marshal data. *)moduleEqIncrSolverFromEqSolver(Sol:GenericEqSolver):GenericEqIncrSolver=functor(Arg:IncrSolverArg)(S:EqConstrSys)(VH:Hashtbl.Swithtypekey=S.v)->structmoduleSol=Sol(S)(VH)modulePost=MakeList(ListArgFromStdArg(S)(VH)(Arg))typemarshal=unitletcopy_marshal()=()letrelift_marshal()=()letsolvexsvs_=letvh=Sol.solvexsvsinPost.postxsvsvh;(vh,())end