123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: you can redistribute it and/or modify *)(* it under the terms of the GNU Lesser General Public License as published *)(* by the Free Software Foundation, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(** Effect are logs of all statements executed during the computation of
a post-state *)openAst.VaropenAst.StmtopenAst.ExpropenMopsa_utilstypeeffect=|Effect_empty|Effect_blockofstmtlist|Effect_seqofeffectlist|Effect_joinofeffect*effect|Effect_meetofeffect*effectletrecpp_effectfmt=function|Effect_empty->()|Effect_blockb->Format.fprintffmt"@[<hv2>{ %a }@]"(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt";@ ")pp_stmt)b|Effect_seqseq->Format.fprintffmt"@[<hv2>{ %a }@]"(Format.pp_print_list~pp_sep:(funfmt()->Format.fprintffmt"⨟@ ")pp_effect)seq|Effect_join(e1,e2)->Format.fprintffmt"@[<hv2>( %a ∨ @ %a )@]"pp_effecte1pp_effecte2|Effect_meet(e1,e2)->Format.fprintffmt"@[<hv2>( %a ∧: @ %a )@]"pp_effecte1pp_effecte2letreccompare_effecte1e2=ife1==e2then0elsematche1,e2with|Effect_empty,Effect_empty->0|Effect_blocks1,Effect_blocks2->Compare.listcompare_stmts1s2|Effect_seqs1,Effect_seqs2->Compare.listcompare_effects1s2|Effect_join(e1,e2),Effect_join(f1,f2)->Compare.paircompare_effectcompare_effect(e1,e2)(f1,f2)|Effect_meet(e1,e2),Effect_meet(f1,f2)->Compare.paircompare_effectcompare_effect(e1,e2)(f1,f2)|_->comparee1e2letempty_effect=Effect_emptyletrecis_empty_effect=function|Effect_empty->true|Effect_block_->false|Effect_seql->List.for_allis_empty_effectl|Effect_join(e1,e2)->is_empty_effecte1&&is_empty_effecte2|Effect_meet(e1,e2)->is_empty_effecte1&&is_empty_effecte2letjoin_effecte1e2=ife1==e2thene1elseifis_empty_effecte1thene2elseifis_empty_effecte2thene1elsematche1,e2with|Effect_empty,x->x|x,Effect_empty->x|_->Effect_join(e1,e2)letmeet_effecte1e2=ife1==e2thene1elseifis_empty_effecte1thene2elseifis_empty_effecte2thene1elsematche1,e2with|Effect_empty,x->x|x,Effect_empty->x|_->Effect_meet(e1,e2)letadd_stmt_to_effects=function|Effect_empty->Effect_block[s]|Effect_blockb->Effect_block(s::b)|Effect_seql->Effect_seq(Effect_block[s]::l)|e->Effect_seq[Effect_block[s];e]letrecconcat_effect~old~recent=ifis_empty_effectoldthenrecentelseifis_empty_effectrecentthenoldelsematchold,recentwith|Effect_empty,Effect_empty->Effect_empty|Effect_blockb1,Effect_blockb2->Effect_block(b2@b1)|Effect_seql1,Effect_seql2->Effect_seq(l2@l1)|Effect_seql,x->Effect_seq(x::l)|x,Effect_seql->Effect_seq(l@[x])|_->Effect_seq[recent;old]letrecfold_stmt_effectfacc=function|Effect_empty->acc|Effect_blocks->List.fold_leftfaccs|Effect_seql->List.fold_left(fold_stmt_effectf)accl|Effect_join(e1,e2)|Effect_meet(e1,e2)->letacc'=fold_stmt_effectfacce1infold_stmt_effectfacc'e2typeteffect=|Teffect_empty|Teffect_nodeofeffect*teffect*teffectletempty_teffect=Teffect_emptyletrecpp_teffectfmt=function|Teffect_empty->()|Teffect_node(e,l,r)->Format.fprintffmt"@[<v2>%a@,%a@,%a@]"pp_effectepp_teffectlpp_teffectrletrecis_empty_teffect=function|Teffect_empty->true|Teffect_node(e,l,r)->is_empty_effecte&&is_empty_teffectl&&is_empty_teffectrletreccompare_teffectte1te2=ifte1==te2then0elsematchte1,te2with|Teffect_empty,Teffect_empty->0|Teffect_node(e1,left1,right1),Teffect_node(e2,left2,right2)->Compare.triplecompare_effectcompare_teffectcompare_teffect(e1,left1,right1)(e2,left2,right2)|_->comparete1te2letempty_teffect=Teffect_emptyletmk_teffecteleftright=Teffect_node(e,left,right)letget_root_effect=function|Teffect_empty->Effect_empty|Teffect_node(e,_,_)->eletget_left_teffect=function|Teffect_empty->Teffect_empty|Teffect_node(_,left,_)->leftletget_right_teffect=function|Teffect_empty->Teffect_empty|Teffect_node(_,_,right)->rightletset_left_teffectleft=function|Teffect_empty->Teffect_node(Effect_empty,left,Teffect_empty)|Teffect_node(e,l,right)aste->ifl==leftthenteelseTeffect_node(e,left,right)letset_right_teffectright=function|Teffect_empty->Teffect_node(Effect_empty,Teffect_empty,right)|Teffect_node(e,left,r)aste->ifright==rthenteelseTeffect_node(e,left,right)letmap_left_teffectf=function|Teffect_empty->Teffect_node(Effect_empty,fTeffect_empty,Teffect_empty)|Teffect_node(e,left,right)->Teffect_node(e,fleft,right)letmap_right_teffectf=function|Teffect_empty->Teffect_node(Effect_empty,Teffect_empty,fTeffect_empty)|Teffect_node(e,left,right)->Teffect_node(e,left,fright)letadd_stmt_to_teffectstmt=function|Teffect_empty->Teffect_node(Effect_block[stmt],Teffect_empty,Teffect_empty)|Teffect_node(e,left,right)->Teffect_node(add_stmt_to_effectstmte,left,right)letrecmerge_teffectf1f2fteffect1teffect2=ifteffect1==teffect2thenteffect1elsematchteffect1,teffect2with|Teffect_empty,Teffect_empty->Teffect_empty|Teffect_empty,Teffect_node(e,left,right)->letee=f1einifee==ethenteffect2elseTeffect_node(ee,left,right)|Teffect_node(e,left,right),Teffect_empty->letee=f2einifee==ethenteffect1elseTeffect_node(ee,left,right)|Teffect_node(e1,left1,right1),Teffect_node(e2,left2,right2)->lete=fe1e2inletl=merge_teffectf1f2fleft1left2inletr=merge_teffectf1f2fright1right2inife==e1&&l==left1&&r==right1thenteffect1elseife==e2&&l==left2&&r==right2thenteffect2elseTeffect_node(e,l,r)letconcat_teffect~old~recent=merge_teffect(funold->old)(funrecent->recent)(funoldrecent->concat_effect~old~recent)oldrecentletmeet_teffectteffect1teffect2=merge_teffect(fune1->e1)(fune2->e2)(fune1e2->meet_effecte1e2)teffect1teffect2letjoin_teffectteffect1teffect2=merge_teffect(fune1->e1)(fune2->e2)(fune1e2->join_effecte1e2)teffect1teffect2letrecfold_stmt_teffectfacc=function|Teffect_empty->acc|Teffect_node(e,l,r)->letacc'=fold_stmt_effectfacceinletacc''=fold_stmt_teffectfacc'linfold_stmt_teffectfacc''r(** {2 Generic merge} *)(** ***************** *)(** Effect of a statement in terms of modified and removed variables *)typevar_effect={modified:VarSet.t;removed:VarSet.t;}letcompare_var_effectve1ve2=Compare.pairVarSet.compareVarSet.compare(ve1.modified,ve1.removed)(ve2.modified,ve2.removed)letis_empty_var_effecte=VarSet.is_emptye.modified&&VarSet.is_emptye.removed(** Get the effect of a statement *)letrecget_stmt_var_effect~customstmt:var_effect=matchcustomstmtwith|Someve->ve|None->matchskindstmtwith|S_add{ekind=E_var(var,_)}->{modified=VarSet.singletonvar;removed=VarSet.empty}|S_remove{ekind=E_var(var,_)}->{modified=VarSet.empty;removed=VarSet.singletonvar;}|S_assign({ekind=E_var(var,_)},_)->{modified=VarSet.singletonvar;removed=VarSet.empty}|S_assume(e)->{modified=VarSet.empty;removed=VarSet.empty}|S_rename({ekind=E_var(var1,_)},{ekind=E_var(var2,_)})->{modified=VarSet.singletonvar2;removed=VarSet.singletonvar1}|S_expand({ekind=E_var(var,_)},vl)->{modified=VarSet.of_list(List.map(function{ekind=E_var(v,_)}->v|_->assertfalse)vl);removed=VarSet.empty}|S_fold({ekind=E_var(var,_)},vl)->{modified=VarSet.singletonvar;removed=VarSet.of_list(List.map(function{ekind=E_var(v,_)}->v|_->assertfalse)vl)}|S_forget{ekind=E_var(var,_)}->{modified=VarSet.singletonvar;removed=VarSet.empty}|_->Exceptions.panic"generic merge: unsupported statement %a"pp_stmtstmtletrecget_var_effect~custom=function|Effect_empty->{modified=VarSet.empty;removed=VarSet.empty}|Effect_blockb->(* Fold from the right because effects are stored in reverse order
(head of the list is the last recorded effect) *)List.fold_right(funsacc->leteffect=get_stmt_var_effect~customsin{modified=VarSet.unioneffect.modified(VarSet.diffacc.modifiedeffect.removed);removed=VarSet.unioneffect.removed(VarSet.diffacc.removedeffect.modified);})b{modified=VarSet.empty;removed=VarSet.empty}|Effect_seql->(* Fold from the right because effects are stored in reverse order
(head of the list is the last recorded effect) *)List.fold_right(funeacc->leteffect=get_var_effect~customein{modified=VarSet.unioneffect.modified(VarSet.diffacc.modifiedeffect.removed);removed=VarSet.unioneffect.removed(VarSet.diffacc.removedeffect.modified);})l{modified=VarSet.empty;removed=VarSet.empty}|Effect_join(e1,e2)->letve1=get_var_effect~custome1andve2=get_var_effect~custome2in{modified=VarSet.unionve1.modifiedve2.modified;removed=VarSet.union(VarSet.diffve1.removedve2.modified)(VarSet.diffve2.removedve1.modified);}|Effect_meet(e1,e2)->letve1=get_var_effect~custome1andve2=get_var_effect~custome2in{modified=VarSet.unionve1.modifiedve2.modified;removed=VarSet.union(VarSet.diffve1.removedve2.modified)(VarSet.diffve2.removedve1.modified);}(** Apply the effect of a log on an abstract element *)letapply_var_effecteffect~add~remove~find(other:'a)(this:'a):'a=leta=VarSet.fold(funvacc->tryaddv(findvother)accwith_->Exceptions.panic"generic merge: error while adding variable %a"pp_varv)effect.modifiedthisinVarSet.fold(funvacc->tryremovevaccwith_->Exceptions.panic"generic merge: error while removing variable %a"pp_varv)effect.removeda(** Generic merge operator for non-relational domains *)letgeneric_merge~add~find~remove?(custom=(funstmt->None))(a1,e1)(a2,e2)=ife1==e2thena1,a1elseletve1=get_var_effect~custome1inletve2=get_var_effect~custome2inifcompare_var_effectve1ve2=0thena1,a2elseleta2'=apply_var_effectve1a1a2~add~remove~findinleta1'=apply_var_effectve2a2a1~add~remove~findina1',a2'letopt_effects_enabled=reffalseletenable_effects()=opt_effects_enabled:=trueletdisable_effects()=opt_effects_enabled:=falseletare_effects_enabled()=!opt_effects_enabledletset_effects_stateb=opt_effects_enabled:=bletwith_effectsf=letold=are_effects_enabled()inenable_effects();letret=f()inset_effects_stateold;ret