123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Union of two value abstractions *)openCore.AllopenSig.Abstraction.ValueopenCommonopenMopsa_utilsmoduleMake(V1:VALUE)(V2:VALUE):VALUEwithtypet=V1.t*V2.t=struct(** {2 Header of the abstraction} *)(** ***************************** *)includeLattices.Pair.Make(V1)(V2)letname="framework.combiners.value.union"letid=V_pair(V1.id,V2.id)letdisplay=V1.display^" ∪ "^V2.displayletaccept_typet=V1.accept_typet||V2.accept_typetletprintprinter(v1,v2)=matchV1.is_bottomv1,V2.is_bottomv2with|true,true->pp_stringprinterBot.bot_string|false,true->V1.printprinterv1|true,false->V2.printprinterv2|false,false->pp_obj_listprinter[pboxV1.printv1;pboxV2.printv2]~lopen:""~lsep:"∨"~lclose:""(** {2 Lattice operators} *)(** ********************* *)letis_bottom(v1,v2)=V1.is_bottomv1&&V2.is_bottomv2(** {2 Value managers} *)(** ****************** *)letv1_man(man:('v,t)value_man):('v,V1.t)value_man={manwithget=(funa->man.geta|>fst);set=(funxa->let(v1,v2)=man.getainifx==v1thenaelseman.set(x,v2)a);}letv2_man(man:('v,t)value_man):('v,V2.t)value_man={manwithget=(funa->man.geta|>snd);set=(funxa->let(v1,v2)=man.getainifx==v2thenaelseman.set(v1,x)a);}(** {2 Local semantics} *)(** ******************* *)(** Forward evaluation of expressions handled by [V1] or [V2] *)letevalmane:t=letman1=v1_manmaninletman2=v2_manmaninletaccept1=V1.accept_typee.etypinletaccept2=V2.accept_typee.etypinifaccept1&&accept2then(* Both domains can represent the value of the expression [e].
In this case, we just pair the returned values *)letr1=V1.evalman1einletr2=V2.evalman2ein(r1,r2)elseifaccept1then(* Only [V1] can represent the value of [e]. However, [V2] can handle the
expression in its extended semantics. So we need to combine the results
of [V1.eval] and [V2.eval_ext]. *)letr1=V1.evalman1einletr2=V2.eval_extman2einmatchr2with|None->(* Since [V2] can't represent the value of [e], its value is set to ⊥ *)(r1,V2.bottom)|Somev->(* When [V2.eval_ext] returns a value [v], we need to retrieve the part
of [V1] in [v] in order to refine it with the result of [V1.eval] *)(V1.meetr1(man1.getv),V2.bottom)elseifaccept2then(* Dual case of accept1 *)letr1=V1.eval_extman1einletr2=V2.evalman2einmatchr1with|None->(V1.bottom,r2)|Somev->(V1.bottom,V2.meetr2(man2.getv))elseassertfalse(** Filter of truth values *)letfilterbtv=letdoitfacceptvbot=ifaccepttthenfbtvelsebotinletr1=doitV1.filterV1.accept_type(fstv)V1.bottominletr2=doitV2.filterV2.accept_type(sndv)V2.bottomin(r1,r2)(** Backward evaluation of expressions *)letbackwardmanever:tvexpr=letman1=v1_manmaninletman2=v2_manmanin(** Sine we are refining the values of sub-expressions, we consider that a
domain accepts a backward evaluation iff all sub-expressions are accepted
*)letaccept1=for_all_child_expr(funee->V1.accept_typeee.etyp)(funs->false)einletaccept2=for_all_child_expr(funee->V2.accept_typeee.etyp)(funs->false)einifaccept1&&accept2then(* Both domains accept, so call [backward] on both of them *)letr1=V1.backwardman1e(map_vexprfstve)rinletr2=V2.backwardman2e(map_vexprsndve)rin(* Combine the values of each node in the tree *)map2_vexpr(funv1->assertfalse)(funv2->assertfalse)(funv1v2->(v1,v2))r1r2elseifaccept1then(* Similarly to [eval], when only one domain accepts the expression, we
need to call the dual extended function of the other domain *)letr1=V1.backwardman1e(map_vexprfstve)rinletr2=V2.backward_extman2e(map_vexpr(funv->man.setvman.top)ve)rinmatchr2with|None->(* Always put the refusing domain to ⊥ *)map_vexpr(funv1->(v1,V2.bottom))r1|Somerr2->(* Use the returned value to refine the result of [V1.backward] *)map2_vexpr(funv1->assertfalse)(funv2->assertfalse)(funv1v2->(V1.meetv1(man1.getv2),V2.bottom))r1rr2elseifaccept2thenletr1=V1.backward_extman1e(map_vexpr(funv->man.setvman.top)ve)rinletr2=V2.backwardman2e(map_vexprsndve)rinmatchr1with|None->map_vexpr(funv2->(V1.bottom,v2))r2|Somerr1->map2_vexpr(funv1->assertfalse)(funv2->assertfalse)(funv1v2->(V1.bottom,V2.meetv2(man2.getv1)))rr1r2elsefailwith(Format.asprintf"not accepting type %a %b %b"pp_type.etypaccept1accept2)(* assert false *)(** Backward refinement of values in a comparison *)letcomparemanopbe1v1e2v2:t*t=letman1=v1_manmaninletman2=v2_manmanin(* A domain needs to accepts both expressions *)letaccept1=V1.accept_typee1.etyp&&V1.accept_typee2.etypinletaccept2=V2.accept_typee1.etyp&&V2.accept_typee2.etypinifaccept1&&accept2thenlet(r11,r12)=V1.compareman1opbe1(fstv1)e2(fstv2)inlet(r21,r22)=V2.compareman2opbe1(sndv1)e2(sndv2)in(r11,r21),(r12,r22)elseifaccept1then(* Similar reasoning as [eval] and [backward] *)let(r11,r12)=V1.compareman1opbe1(fstv1)e2(fstv2)inletr2=V2.compare_extman2opbe1(man.setv1man.top)e2(man.setv2man.top)inmatchr2with|None->(r11,V2.bottom),(r12,V2.bottom)|Some(r21,r22)->(V1.meetr11(man1.getr21),man2.getr21),(V1.meetr12(man1.getr22),man2.getr22)elseifaccept2thenletr1=V1.compare_extman1opbe1(man.setv1man.top)e2(man.setv2man.top)inlet(r21,r22)=V2.compareman2opbe1(sndv1)e2(sndv2)inmatchr1with|None->(V1.bottom,r21),(V1.bottom,r22)|Some(r11,r12)->(man1.getr11,V2.meetr21(man2.getr11)),(man1.getr12,V2.meetr22(man2.getr12))elseassertfalse(** {2 Extended semantics} *)(** ********************** *)(** Extened evaluation of expressions, used when the expression can't be
repsented in neither [V1] not [V2] *)leteval_extmane=letr1=V1.eval_ext(v1_manman)einletr2=V2.eval_ext(v2_manman)einOptionExt.neutral2man.meetr1r2(** Extended backward evaluations, used when some sub-expressions can't be
represented by [V1] not [V2] *)letbackward_extmaneevr=letr1=V1.backward_ext(v1_manman)eevrinletr2=V2.backward_ext(v2_manman)eevrinOptionExt.neutral2(merge_vexprman.meet)r1r2(** Extended comparison between expressions outside the scope of [V1] and [V2] *)letcompare_extmanopbe1v1e2v2=letr1=V1.compare_ext(v1_manman)opbe1v1e2v2inletr2=V2.compare_ext(v2_manman)opbe1v1e2v2inOptionExt.neutral2(fun(r11,r12)(r21,r22)->(man.meetr11r21),(man.meetr12r22))r1r2(** {2 Communication handlers} *)(** ************************** *)(** Cast an abstract element to an avalue *)letavalueaval(v1,v2)=OptionExt.neutral2(join_avalueaval)(V1.avalueavalv1)(V2.avalueavalv2)(** Handle queries *)letaskmanquery=OptionExt.neutral2(join_queryquery)(V1.ask(v1_manman)query)(V2.ask(v2_manman)query)end(** Create a union of a list of domains *)letrecmake(values:(moduleVALUE)list):(moduleVALUE)=matchvalueswith|[]->assertfalse|[v]->v|hd::tl->(moduleMake(valhd:VALUE)(val(maketl):VALUE):VALUE)