123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Reduced product of simplified (leaf) domains *)openMopsa_utilsopenCore.AllopenCommonopenSig.Reduction.SimplifiedopenSig.Combiner.Simplified(** Create a product of two domains *)moduleMakeDomainPair(D1:SIMPLIFIED_COMBINER)(D2:SIMPLIFIED_COMBINER):SIMPLIFIED_COMBINERwithtypet=D1.t*D2.t=structtypet=D1.t*D2.tletid=C_pair(Product,D1.id,D2.id)letname=D1.name^" ∧ "^D2.nameletdomains=DomainSet.unionD1.domainsD2.domainsletsemantics=SemanticSet.unionD1.semanticsD2.semanticsletrouting_table=join_routing_tableD1.routing_tableD2.routing_tableletbottom:t=D1.bottom,D2.bottomlettop:t=D1.top,D2.topletis_bottom((a,b):t):bool=D1.is_bottoma||D2.is_bottombletsubset((a1,b1):t)((a2,b2):t):bool=D1.subseta1a2&&D2.subsetb1b2letapplyf1f2((v1,v2)asv)=letr1=f1v1inletr2=f2v2inifr1==v1&&r2==v2thenvelse(r1,r2)letapply2f1f2((v1,v2)asv)((w1,w2)asw)=letr1=f1v1w1inletr2=f2v2w2inifr1==v1&&r2==v2thenvelseifr1==w1&&r2==w2thenwelse(r1,r2)letjoin((v1,v2)asv:t)((w1,w2)asw:t):t=ifv1==w1&&v2==w2thenvelseapply2D1.joinD2.joinvwletmeet((v1,v2)asv:t)((w1,w2)asw:t):t=ifv1==w1&&v2==w2thenvelseapply2D1.meetD2.meetvwletwidenctx((v1,v2)asv:t)((w1,w2)asw:t):t=ifv1==w1&&v2==w2thenvelseapply2(D1.widenctx)(D2.widenctx)vwletmergepath(p1,p2)(a1,e1)(a2,e2)=apply2(funv1w1->D1.mergepathp1(v1,e1)(w1,e2))(funv2w2->D2.mergepathp2(v2,e1)(w2,e2))a1a2lethdman(man:('a,t)Sig.Abstraction.Simplified.simplified_man):(('a,D1.t)Sig.Abstraction.Simplified.simplified_man)={manwithexec=(funstmt->man.execstmt|>fst);}lettlman(man:('a,t)Sig.Abstraction.Simplified.simplified_man):(('a,D2.t)Sig.Abstraction.Simplified.simplified_man)={manwithexec=(funstmt->man.execstmt|>snd);}letinitprog=D1.initprog,D2.initprogletexectargets=letrecompose_pair((a1,a2)asa)r1r2=matchr1,r2with|None,None->None|Somer1,None->ifa1==r1thenSomeaelseSome(r1,a2)|None,Somer2->ifa2==r2thenSomeaelseSome(a1,r2)|Somer1,Somer2->ifr1==a1&&r2==a2thenSomeaelseSome(r1,r2)inmatchsat_targets~targets~domains:D1.domains,sat_targets~targets~domains:D2.domainswith|false,false->raiseNot_found|true,false->letf1=D1.exectargetsin(funstmtmanctx((a1,a2)asa)->recompose_paira(f1stmt(hdmanman)ctxa1)None)|false,true->letf2=D2.exectargetsin(funstmtmanctx((a1,a2)asa)->recompose_pairaNone(f2stmt(tlmanman)ctxa2))|true,true->letf1=D1.exectargetsinletf2=D2.exectargetsin(funstmtmanctx((a1,a2)asa)->recompose_paira(f1stmt(hdmanman)ctxa1)(f2stmt(tlmanman)ctxa2))letasktargets=matchsat_targets~targets~domains:D1.domains,sat_targets~targets~domains:D2.domainswith|false,false->raiseNot_found|true,false->letf1=D1.asktargetsin(funqmanctx(a1,_)->f1q(hdmanman)ctxa1)|false,true->letf2=D2.asktargetsin(funqmanctx(_,a2)->f2q(tlmanman)ctxa2)|true,true->letf1=D1.asktargetsinletf2=D2.asktargetsin(funqmanctx(a1,a2)->OptionExt.neutral2(meet_queryq)(f1q(hdmanman)ctxa1)(f2q(tlmanman)ctxa2))letprint_statetargets=matchsat_targets~targets~domains:D1.domains,sat_targets~targets~domains:D2.domainswith|false,false->raiseNot_found|true,false->letf1=D1.print_statetargetsin(funprinter(a1,_)->f1printera1)|false,true->letf2=D2.print_statetargetsin(funprinter(_,a2)->f2printera2)|true,true->letf1=D1.print_statetargetsinletf2=D2.print_statetargetsin(funprinter(a1,a2)->f1printera1;f2printera2)letprint_exprtargets=matchsat_targets~targets~domains:D1.domains,sat_targets~targets~domains:D2.domainswith|false,false->raiseNot_found|true,false->letf1=D1.print_exprtargetsin(funmanctx(a1,_)printere->f1(hdmanman)ctxa1printere)|false,true->letf2=D2.print_exprtargetsin(funmanctx(_,a2)printere->f2(tlmanman)ctxa2printere)|true,true->letf1=D1.print_exprtargetsinletf2=D2.print_exprtargetsin(funmanctx(a1,a2)printere->f1(hdmanman)ctxa1printere;f2(tlmanman)ctxa2printere)end(** Create a reduced product from a domain representing a product of
domains and a list of reduction rules *)moduleMake(D:SIMPLIFIED_COMBINER)(R:sigvalrules:(moduleSIMPLIFIED_REDUCTION)listend):SIMPLIFIED_COMBINERwithtypet=D.t=structincludeDletreduction_manman:('a,D.t)simplified_reduction_man={(* Get the abstract element of a domain *)get_env=(fun(typea)(idx:aid)(a:t)->letrecaux:typeb.bid->b->a=funidyaa->matchidy,aawith|C_empty,()->raiseNot_found|C_pair(_,hd,tl),(ahd,atl)->beginmatchequal_idhdidxwith|SomeEq->ahd|None->auxtlatlend|_->matchequal_ididxidywith|SomeEq->aa|None->raiseNot_foundinauxida);(* Set the abstract element of a domain *)set_env=(fun(typea)(idx:aid)(x:a)(a:t)->letrecaux:typeb.bid->b->b=funidyaa->matchidy,aawith|C_empty,()->raiseNot_found|C_pair(_,hd,tl),(ahd,atl)->beginmatchequal_idhdidxwith|SomeEq->x,atl|None->ahd,auxtlatlend|_->matchequal_ididxidywith|SomeEq->x|None->raiseNot_foundinauxida);(* Get the abstract value of a variable *)get_value=(fun(typev)(idx:vid)vara->letopenValue.NonrelinletopenBot_topinletopenLattices.Partial_mapinletrecaux:typea.aid->a->v=funidyaa->matchidy,aawith(* The value is extracted from non-relational environments *)|D_nonrelvmodule,aa->letmoduleV=(valvmodule)in(* Extract the value of the variable. This is not the
final result, as the required value may be embedded
in a product *)letv=matchaawith|TOP->V.top|BOT->V.bottom|Nbtmap->PMap.findvarmapin(* Iterate over combiners to find the required id *)letreciter:typew.wid->w->v=funid'v'->(* Check if id' corresponds to what we are searching for *)matchequal_idid'idxwith|SomeEq->v'|None->(* Otherwise, search in the arguments of the combiner *)matchid',v'with|V_pair(id1,id2),(v1,v2)->begintryiterid1v1withNot_found->iterid2v2end|_->raiseNot_foundiniterV.idv|C_pair(_,hd,tl),(ahd,atl)->begintryauxhdahdwithNot_found->auxtlatlend|_->raiseNot_foundinauxida);set_value=(fun(typev)(idx:vid)var(v:v)a->letopenValue.NonrelinletopenBot_topinletopenLattices.Partial_mapinletrecaux:typea.aid->a->a=funidyaa->matchidy,aawith(* The value is set in non-relational environments *)|D_nonrelvmodule,aa->letmoduleV=(valvmodule)in(* Get the old value of the variable. The given
value [v] will be put *inside* it (in case of composed values). *)letold=matchaawith|TOP->V.top|BOT->V.bottom|Nbtmap->PMap.findvarmapin(* Iterate over the structure of [old] to put [v] in the right place *)letreciter:typew.wid->w->w=funid'v'->(* Check if id' corresponds to what we are searching for *)matchequal_idid'idxwith|SomeEq->v|None->(* Otherwise, search in the operands of value combiners *)matchid',v'with|V_pair(id1,id2),(v1,v2)->begintryiterid1v1,v2withNot_found->v1,iterid2v2end|_->raiseNot_foundinletupdate=iterV.idoldinifV.is_bottomupdatethenBOTelsebeginmatchaawith|TOP->TOP|BOT->BOT|Nbtmap->Nbt(PMap.addvarupdatemap)end|C_pair(_,hd,tl),(ahd,atl)->begintryauxhdahd,atlwithNot_found->ahd,auxtlatlend|_->raiseNot_foundinauxida);ask=(funqctxa->matchD.askNoneqmanctxawithNone->raiseNot_found|Somer->r);}letreducestmtmanctxprepost=letrman=reduction_manmaninList.fold_left(funaccrule->letmoduleRule=(valrule:SIMPLIFIED_REDUCTION)inRule.reducestmtrmanctxpreacc)postR.rulesletexectargets=letf=D.exectargetsin(funstmtmanctxa->matchfstmtmanctxawith|None->None|Somer->Some(reducestmtmanctxar))endletmake(domains:(moduleSIMPLIFIED_COMBINER)list)~(rules:(moduleSIMPLIFIED_REDUCTION)list):(moduleSIMPLIFIED_COMBINER)=letrecaux=function|[]->assertfalse|[d]->d|hd::tl->(moduleMakeDomainPair(valhd:SIMPLIFIED_COMBINER)(val(auxtl):SIMPLIFIED_COMBINER):SIMPLIFIED_COMBINER)in(moduleMake(val(auxdomains):SIMPLIFIED_COMBINER)(structletrules=rulesend))