123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** ToolBox module for Apron interfacing *)openMopsaopenCommonopenAstopenApron_managermoduleApronTransformer(ApronManager:APRONMANAGER)=structletdebugfmt=Debug.debug~channel:"universal.numeric.relational.apron_transformer"fmtletwith_contextctxa=a,ctxletis_numerical_var(v:var):bool=matchvtypvwith|T_bool|T_int|T_float_->true|_->falseletempty_env=Apron.Environment.make[||][||]letprint_env=Apron.Environment.print~first:("[")~sep:(",")~last:("]")letfilter_envint_filterreal_filterenv=letint_var,real_var=Apron.Environment.varsenvinletlist_int_var_to_keep=Array.fold_left(funlist_int_var_to_keepint_var->ifint_filterint_varthenint_var::list_int_var_to_keepelselist_int_var_to_keep)[]int_varinletlist_real_var_to_keep=Array.fold_left(funlist_real_var_to_keepreal_var->ifreal_filterreal_varthenreal_var::list_real_var_to_keepelselist_real_var_to_keep)[]real_varinletarray_int_res=Array.of_listlist_int_var_to_keepinletarray_real_res=Array.of_listlist_real_var_to_keepinApron.Environment.makearray_int_resarray_real_resletfold_envfenvacc=letint_var,real_var=Apron.Environment.varsenvinletacc'=Array.fold_left(funaccx->fxacc)accint_varinArray.fold_left(funaccx->fxacc)acc'real_varletexists_envfenv=letexceptionExistsintrylet()=fold_env(fune()->iffethenraiseExists)env()infalsewith|Exists->trueletgceab=filter_env(funint_var->Apron.Environment.mem_varbint_var)(funint_var->Apron.Environment.mem_varbint_var)aletdiffab=filter_env(funint_var->not(Apron.Environment.mem_varbint_var))(funint_var->not(Apron.Environment.mem_varbint_var))a(** Construct a list of linear constraints from an abstract value. *)letto_constraints(a,bnd)=letearray=Apron.Abstract1.to_lincons_arrayApronManager.manainletll=ref[]infori=0toApron.Lincons1.array_lengthearray-1doletl=ref[]inletcons=Apron.Lincons1.array_getearrayiinApron.Lincons1.iter(funcv->l:=(c,Binding.apron_to_mopsa_varvbnd)::!l)cons;ll:=(!l,Apron.Lincons1.get_cstcons,Apron.Lincons1.get_typcons)::!lldone;!ll(** Restrict linear constraints involving variable [v] *)letconstraints_of_varvconstraints=List.filter(fun(cons,_,_)->List.exists(fun(c,v')->(compare_varvv'=0)&¬(Apron.Coeff.is_zeroc))cons)constraints(** Get the list of variables with which [v] has numeric relations. Note that
this function performs only one search iteration and doesn't return all
related variables. *)letrelated_varsv(a,bnd)=to_constraints(a,bnd)|>constraints_of_varv|>List.fold_left(funacc(cons,_,_)->List.fold_left(funacc(c,v')->ifcompare_varvv'<>0&¬(Apron.Coeff.is_zeroc)thenv'::accelseacc)acccons)[](** Get the list of constant variables *)letconstant_vars(a,bnd)=letrecitercandidatel=matchlwith|[]->candidate|(c,v)::tl->ifApron.Coeff.is_zerocthenitercandidatetlelsematchcandidatewith|Somevv->None|None->iter(Somev)tlinto_constraints(a,bnd)|>List.fold_left(funacc(cons,c,t)->matchtwith|Apron.Lincons1.EQ->beginmatchiterNoneconswith|None->acc|Somev->v::accend|_->acc)[](** Similar to [get_related_vars], but ensures that all related variables are returned. *)letall_related_varsva=letreciteraccwq=ifVarSet.is_emptywqthenaccelseletv=VarSet.choosewqinletwq=VarSet.removevwqinifVarSet.memvacctheniteraccwqelseletacc=VarSet.addvaccinletrelated=related_varsva|>VarSet.of_listinletnew_related=VarSet.diffrelatedaccinletwq=VarSet.unionwqnew_relatediniteraccwqiniterVarSet.empty(VarSet.singletonv)|>VarSet.elementsexceptionUnsupportedExpression(* Raised when an expression is not part of the concrete semantics *)exceptionImpreciseExpression(* Raised when Apron doesn't have a precise transfer function for the expression *)letbinop_to_apron=function|O_plus->Apron.Texpr1.Add|O_minus->Apron.Texpr1.Sub|O_mult->Apron.Texpr1.Mul|O_div->Apron.Texpr1.Div|O_ediv->Apron.Texpr1.Div|O_mod->Apron.Texpr1.Mod|O_erem->Apron.Texpr1.Mod|_->raiseImpreciseExpressionlettyp_to_apron=function|T_bool->Apron.Texpr1.Int|T_int->Apron.Texpr1.Int|T_floatF_SINGLE->Apron.Texpr1.Single|T_floatF_DOUBLE->Apron.Texpr1.Double|T_floatF_LONG_DOUBLE->Apron.Texpr1.Extended|T_floatF_FLOAT128->Apron.Texpr1.Extended|T_floatF_REAL->Apron.Texpr1.Real|t->panic~loc:__LOC__"typ_to_apron: unsupported type %a"pp_typtletis_env_varv(abs,bnd)=letenv=Apron.Abstract1.envabsinApron.Environment.mem_varenv(Binding.mopsa_to_apron_varvbnd|>fst)letis_env_var_apronvabs=letenv=Apron.Abstract1.envabsinApron.Environment.mem_varenvvletremove_tmptmplabs=letenv=Apron.Abstract1.envabsinletvars=List.filter(funv->is_env_var_apronvabs)tmplinletenv=Apron.Environment.removeenv(Array.of_listvars)inApron.Abstract1.change_environmentApronManager.manabsenvtrueletrecexp_to_apronisnanexp(abs,bnd)l=ifnot(is_numeric_type(etypexp))thenraiseUnsupportedExpressionelsematchekindexpwith|E_constant(C_int_interval(ItvUtils.IntBound.Finitelo,ItvUtils.IntBound.Finitehi))whenZ.(lo=hi)->Apron.Texpr1.Cst(Apron.Coeff.Scalar(Apron.Scalar.of_mpq@@Mpq.of_string@@Z.to_stringlo)),abs,bnd,l|E_constantC_top_|E_constantC_int_interval_|E_constantC_float_interval_|E_unop(O_wrap_,_)->raiseImpreciseExpression|E_constant(C_booltrue)->Apron.Texpr1.Cst(Apron.Coeff.Scalar(Apron.Scalar.of_int1)),abs,bnd,l|E_constant(C_boolfalse)->Apron.Texpr1.Cst(Apron.Coeff.Scalar(Apron.Scalar.of_int0)),abs,bnd,l|E_constant(C_intn)->Apron.Texpr1.Cst(Apron.Coeff.Scalar(Apron.Scalar.of_mpq@@Mpq.of_string@@Z.to_stringn)),abs,bnd,l|E_constant(C_floatf)->Apron.Texpr1.Cst(Apron.Coeff.Scalar(Apron.Scalar.of_floatf)),abs,bnd,l|E_var(x,mode)whenvar_modexmode=STRONG->letxx,bnd=Binding.mopsa_to_apron_varxbndinApron.Texpr1.Var(xx),abs,bnd,l|E_var(x,mode)whenvar_modexmode=WEAK->letx'=mktmp~typ:exp.etyp()inletx_apr,bnd=Binding.mopsa_to_apron_varxbndinletx_apr',_=Binding.mopsa_to_apron_varx'bndinletabs=Apron.Abstract1.expandApronManager.manabsx_apr[|x_apr'|]in(Apron.Texpr1.Varx_apr',abs,bnd,x_apr'::l)|E_binop(O_convex_join,e1,e2)->(* add tmp variable *)lettmp=mktmp~typ:exp.etyp()inlettmp_apr,_=Binding.mopsa_to_apron_vartmpbndinletenv=Apron.Environment.add(Apron.Abstract1.envabs)[|tmp_apr|][||]inletabs=Apron.Abstract1.change_environmentApronManager.manabsenvfalseinlete1',abs,bnd,l=exp_to_apronisnane1(abs,bnd)linlete2',abs,bnd,l=exp_to_apronisnane2(abs,bnd)linlettyp'=typ_to_apronexp.etypinletround=iftyp'=Apron.Texpr1.IntthenApron.Texpr1.Zeroelse!opt_float_roundingin(* case 1: e1 <= tmp <= e2 *)letconstraints_1=tcons_array_of_tcons_listenv[Apron.Tcons1.make(Apron.Texpr1.binopApron.Texpr0.Sub(Apron.Texpr1.varenvtmp_apr)(Apron.Texpr1.of_exprenve1')typ'round)Apron.Lincons0.SUPEQ;Apron.Tcons1.make(Apron.Texpr1.binopApron.Texpr0.Sub(Apron.Texpr1.of_exprenve2')(Apron.Texpr1.varenvtmp_apr)typ'round)Apron.Lincons0.SUPEQ;]inletabs_1=Apron.Abstract1.meet_tcons_arrayApronManager.manabsconstraints_1in(* case 2: e2 <= tmp <= e1 *)letconstraints_2=tcons_array_of_tcons_listenv[Apron.Tcons1.make(Apron.Texpr1.binopApron.Texpr0.Sub(Apron.Texpr1.varenvtmp_apr)(Apron.Texpr1.of_exprenve2')typ'round)Apron.Lincons0.SUPEQ;Apron.Tcons1.make(Apron.Texpr1.binopApron.Texpr0.Sub(Apron.Texpr1.of_exprenve1')(Apron.Texpr1.varenvtmp_apr)typ'round)Apron.Lincons0.SUPEQ;]inletabs_2=Apron.Abstract1.meet_tcons_arrayApronManager.manabsconstraints_2inletabs=Apron.Abstract1.joinApronManager.manabs_1abs_2in(Apron.Texpr1.Vartmp_apr,abs,bnd,tmp_apr::l)|E_binop((O_ediv|O_erem)asbinop,e1,e2)->letbinop'=binop_to_apronbinopinlete1',abs,bnd,l=exp_to_apronisnane1(abs,bnd)linlete2',abs,bnd,l=exp_to_apronisnane2(abs,bnd)linlettyp'=typ_to_apronexp.etypinletround=iftyp'=Apron.Texpr1.IntthenApron.Texpr1.Downelse!opt_float_roundinginApron.Texpr1.Binop(binop',e1',e2',typ',round),abs,bnd,l|E_binop(binop,e1,e2)->letbinop'=binop_to_apronbinopinlete1',abs,bnd,l=exp_to_apronisnane1(abs,bnd)linlete2',abs,bnd,l=exp_to_apronisnane2(abs,bnd)linlettyp'=typ_to_apronexp.etypinletround=iftyp'=Apron.Texpr1.IntthenApron.Texpr1.Zeroelse!opt_float_roundinginApron.Texpr1.Binop(binop',e1',e2',typ',round),abs,bnd,l|E_unop(O_plus,e)->exp_to_apronisnane(abs,bnd)l|E_unop(O_cast,e)->lete',abs,bnd,l=exp_to_apronisnane(abs,bnd)linlettyp'=typ_to_apronexp.etypinletround=iftyp'=Apron.Texpr1.IntthenApron.Texpr1.Zeroelse!opt_float_roundinginApron.Texpr1.Unop(Apron.Texpr1.Cast,e',typ',round),abs,bnd,l|E_unop(O_minus,e)->lete',abs,bnd,l=exp_to_apronisnane(abs,bnd)linlettyp'=typ_to_aprone.etypinletround=iftyp'=Apron.Texpr1.IntthenApron.Texpr1.Zeroelse!opt_float_roundinginApron.Texpr1.Unop(Apron.Texpr1.Neg,e',typ',round),abs,bnd,l|E_unop(O_sqrt,e)->lete',abs,bnd,l=exp_to_apronisnane(abs,bnd)linlettyp'=typ_to_apronexp.etypinApron.Texpr1.Unop(Apron.Texpr1.Sqrt,e',typ',!opt_float_rounding),abs,bnd,l|_->raiseImpreciseExpressionandbexp_to_apronisnanexp(abs,bnd)l=matchekindexpwith|E_binop((O_gt|O_ge|O_lt|O_le|O_eq)ascomp_op,e0,e1)->if(is_float_type(etype0)&&isnane0)||(is_float_type(etype1)&&isnane1)thenraiseImpreciseExpression;lete0',abs,bnd,l=exp_to_apronisnane0(abs,bnd)linlete1',abs,bnd,l=exp_to_apronisnane1(abs,bnd)linletrev,apron_comp_op=matchcomp_opwith|O_gt->false,Apron.Tcons1.SUP|O_ge->false,Apron.Tcons1.SUPEQ|O_lt->true,Apron.Tcons1.SUP|O_le->true,Apron.Tcons1.SUPEQ|O_eq->false,Apron.Tcons1.EQ|_->assertfalseinlete0',t0,e1',t1=ifrevthene1',e1.etyp,e0',e0.etypelsee0',e0.etyp,e1',e1.etypinDnf.singleton(apron_comp_op,e0',t0,e1',t1),abs,bnd,l|E_binop(O_ne,e0,e1)->if(is_float_type(etype0)&&isnane0)||(is_float_type(etype1)&&isnane1)thenraiseImpreciseExpression;lete0',abs,bnd,l=exp_to_apronisnane0(abs,bnd)linlete1',abs,bnd,l=exp_to_apronisnane1(abs,bnd)linDnf.mk_or(Dnf.singleton(Apron.Tcons1.SUP,e0',e0.etyp,e1',e1.etyp))(Dnf.singleton(Apron.Tcons1.SUP,e1',e1.etyp,e0',e0.etyp)),abs,bnd,l|E_binop(O_log_or,e1,e2)->lete1',abs,bnd,l=bexp_to_apronisnane1(abs,bnd)linlete2',abs,bnd,l=bexp_to_apronisnane2(abs,bnd)linDnf.mk_ore1'e2',abs,bnd,l|E_binop(O_log_and,e1,e2)->lete1',abs,bnd,l=bexp_to_apronisnane1(abs,bnd)linlete2',abs,bnd,l=bexp_to_apronisnane2(abs,bnd)linDnf.mk_ande1'e2',abs,bnd,l|E_binop(O_log_xor,e1,e2)->lete1'=mk_binop~etyp:T_boole1O_eq(mk_zero~typ:T_intexp.erange)exp.erangeinlete2'=mk_binop~etyp:T_boole1O_eq(mk_zero~typ:T_intexp.erange)exp.erangeinlete1',abs,bnd,l=exp_to_apronisnane1'(abs,bnd)linlete2',abs,bnd,l=exp_to_apronisnane2'(abs,bnd)linDnf.singleton(Apron.Tcons1.DISEQ,e1',T_bool,e2',T_bool),abs,bnd,l|E_unop(O_log_not,exp')->letdnf,abs,bnd,l=bexp_to_apronisnanexp'(abs,bnd)linDnf.mk_neg(fun(op,e1,t1,e2,t2)->matchopwith|Apron.Tcons1.EQ->Dnf.mk_or(Dnf.singleton(Apron.Tcons1.SUP,e1,t1,e2,t2))(Dnf.singleton(Apron.Tcons1.SUP,e2,t2,e1,t1))|Apron.Tcons1.SUP->Dnf.singleton(Apron.Tcons1.SUPEQ,e2,t2,e1,t1)|Apron.Tcons1.SUPEQ->Dnf.singleton(Apron.Tcons1.SUP,e2,t2,e1,t1)|_->assertfalse)dnf,abs,bnd,l|_->lete0',abs,bnd,l=exp_to_apronisnanexp(abs,bnd)linlete1'=Apron.Texpr1.Cst(Apron.Coeff.s_of_int0)inDnf.mk_or(Dnf.singleton(Apron.Tcons1.SUP,e0',exp.etyp,e1',T_int))(Dnf.singleton(Apron.Tcons1.SUP,e1',T_int,e0',exp.etyp)),abs,bnd,landtcons_array_of_tcons_listenvl=letn=List.lengthlinletcond_array=Apron.Tcons1.array_makeenvninlet()=List.iteri(funic->Apron.Tcons1.array_setcond_arrayic;)lincond_arrayend