123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Interval abstraction of integer values. *)openMopsaopenAstopenBotopenSig.Abstraction.Simplified_valueopenCommon(** Use the simplified signature for handling homogenous operators *)moduleSimplifiedValue=structtypet=Common.int_itvmoduleI=ItvUtils.IntItvmoduleFI=ItvUtils.FloatItvincludeGenValueId(structtypenonrect=tletname="universal.numeric.values.intervals.integer"letdisplay="int-itv"end)letaccept_type=function|T_int|T_bool->true|_->falseletbottom=BOTlettop=Nb(I.minf_inf)lettop_of_typ=function|T_int->top|T_bool->Nb(I.of_int01)|_->assertfalseletis_bottomabs=bot_dfl1true(funitv->not(I.is_validitv))absletsubset(a1:t)(a2:t):bool=I.included_bota1a2letjoin(a1:t)(a2:t):t=I.join_bota1a2letmeet(a1:t)(a2:t):t=I.meet_bota1a2letwidenctx(a1:t)(a2:t):t=(* Retrieve thresholds if any *)matchfind_ctx_optCommon.widening_thresholds_ctx_keyctxwith|None->I.widen_bota1a2|Somethresholds->bot_neutral2(fun(a,b)(c,d)->(* Translate constants to bounds *)letthresholds=SetExt.ZSet.elementsthresholds|>List.map(funn->I.B.Finiten)in(* Apply the definition of the widening with thresholds *)(ifI.B.leqacthenaelseList.filter(I.B.geqc)thresholds|>List.fold_leftI.B.maxI.B.MINF),(ifI.B.geqbdthenbelseList.filter(I.B.leqd)thresholds|>List.fold_leftI.B.minI.B.PINF))a1a2letprintprinter(a:t)=unformatI.fprint_botprinteraletconstantct=matchcwith|C_booltrue->Nb(I.cst_int1)|C_boolfalse->Nb(I.cst_int0)|C_topT_bool->Nb(I.of_int01)|C_inti->Nb(I.of_zii)|C_int_interval(i1,i2)->Nb(I.of_boundi1i2)|C_avalue(V_int_interval,itv)->itv|C_avalue(V_int_interval_fast,itv)->itv|_->top_of_typtletunopoptatr=matchopwith|O_log_not->bot_lift1I.log_nota|O_minus->bot_lift1I.nega|O_plus->a|O_abs->bot_lift1I.absa|O_wrap(l,u)->bot_lift1(funitv->I.wrapitvlu)a|O_bit_invert->bot_lift1I.bit_nota|_->top_of_typtrletbinopopt1a1t2a2tr=matchopwith|O_plus->bot_lift2I.adda1a2|O_minus->bot_lift2I.suba1a2|O_mult->bot_lift2I.mula1a2|O_div->bot_absorb2I.diva1a2|O_ediv->bot_absorb2I.ediva1a2|O_pow->bot_lift2I.powa1a2|O_eq->bot_lift2I.log_eqa1a2|O_ne->bot_lift2I.log_neqa1a2|O_lt->bot_lift2I.log_lta1a2|O_le->bot_lift2I.log_leqa1a2|O_gt->bot_lift2I.log_gta1a2|O_ge->bot_lift2I.log_geqa1a2|O_log_or->bot_lift2I.log_ora1a2|O_log_and->bot_lift2I.log_anda1a2|O_log_xor->bot_lift2I.log_xora1a2|O_mod->bot_absorb2I.rema1a2|O_erem->bot_absorb2I.erema1a2|O_bit_and->bot_lift2I.bit_anda1a2|O_bit_or->bot_lift2I.bit_ora1a2|O_bit_xor->bot_lift2I.bit_xora1a2|O_bit_rshift->bot_absorb2I.shift_righta1a2|O_bit_lshift->bot_absorb2I.shift_lefta1a2|O_convex_join->bot_lift2I.joina1a2|_->top_of_typtrletfilterbta=ifbthenbot_absorb1I.meet_nonzeroaelsebot_absorb1I.meet_zeroaletbackward_unopoptatr=tryleta,r=bot_to_exna,bot_to_exnrinletaa=matchopwith|O_minus->bot_to_exn(I.bwd_negar)|O_wrap(l,u)->bot_to_exn(I.bwd_wrapa(l,u)r)|O_bit_invert->bot_to_exn(I.bwd_bit_notar)|_->bot_to_exn(I.bwd_default_unaryar)inNbaawithFound_BOT->bottomletbackward_binopopt1a1t2a2trr=tryleta1,a2,r=bot_to_exna1,bot_to_exna2,bot_to_exnrinletaa1,aa2=matchopwith|O_plus->bot_to_exn(I.bwd_adda1a2r)|O_minus->bot_to_exn(I.bwd_suba1a2r)|O_mult->bot_to_exn(I.bwd_mula1a2r)|O_div->bot_to_exn(I.bwd_diva1a2r)|O_ediv->bot_to_exn(I.bwd_ediva1a2r)|O_mod->bot_to_exn(I.bwd_rema1a2r)|O_erem->bot_to_exn(I.bwd_erema1a2r)|O_pow->bot_to_exn(I.bwd_powa1a2r)|O_eq->bot_to_exn(I.bwd_log_eqa1a2r)|O_ne->bot_to_exn(I.bwd_log_neqa1a2r)|O_lt->bot_to_exn(I.bwd_log_lta1a2r)|O_le->bot_to_exn(I.bwd_log_leqa1a2r)|O_gt->bot_to_exn(I.bwd_log_gta1a2r)|O_ge->bot_to_exn(I.bwd_log_geqa1a2r)|O_bit_and->bot_to_exn(I.bwd_bit_anda1a2r)|O_bit_or->bot_to_exn(I.bwd_bit_ora1a2r)|O_bit_xor->bot_to_exn(I.bwd_bit_xora1a2r)|O_bit_rshift->bot_to_exn(I.bwd_shift_righta1a2r)|O_bit_lshift->bot_to_exn(I.bwd_shift_lefta1a2r)|O_convex_join->bot_to_exn(I.bwd_convex_joina1a2r)|_->Exceptions.panic"bwd_binop: unknown operator %a"pp_operatoropinNbaa1,Nbaa2withFound_BOT->bottom,bottomletcompareopbt1a1t2a2=tryleta1,a2=bot_to_exna1,bot_to_exna2inletop=ifbthenopelsenegate_comparison_opopinletaa1,aa2=matchopwith|O_eq->bot_to_exn(I.filter_eqa1a2)|O_ne->bot_to_exn(I.filter_neqa1a2)|O_lt->bot_to_exn(I.filter_lta1a2)|O_gt->bot_to_exn(I.filter_gta1a2)|O_le->bot_to_exn(I.filter_leqa1a2)|O_ge->bot_to_exn(I.filter_geqa1a2)|_->Exceptions.panic"compare: unknown operator %a"pp_operatoropinNbaa1,Nbaa2withFound_BOT->bottom,bottomletavalue:typer.ravalue_kind->t->roption=funavala->matchavalwith|Common.V_int_interval->Somea|Common.V_int_interval_fast->Somea|Common.V_int_congr_interval->Some(a,Bot.NbCommon.C.minf_inf)|_->Noneend(** We lift now to the advanced signature to handle casts and queries *)openSig.Abstraction.ValuemoduleValue=structincludeSimplifiedValuemoduleV=MakeValue(SimplifiedValue)includeV(** Cast a non-integer value to an integer *)letcastmane=matche.etypwith|T_floatp->(* Get the value of the float *)letv=man.evalein(* Convert it to a float interval *)letfloat_itv=man.avalue(Common.V_float_intervalp)vin(* Perform the cast to an integer interval *)ItvUtils.FloatItvNan.to_int_itvfloat_itv|_->top(* Evaluation of integer expressions *)letevalmane=matchekindewith(* Casts *)|E_unop(O_cast,ee)->castmanee|_->(* Other expressions are handled by the simplified domain *)letr=V.evalmanein(* Ensure that boolean values are in [0,1] *)matche.etypwith|T_bool->meetr(top_of_typT_bool)|_->r(* Extended backward refinement of casts to integers. *)letbackward_ext_castmanever=matche.etypwith|T_floatp->beginmatchrwith|BOT->None|Nbiitv->(* Get the float value *)letv,_=find_vexprevein(* Convert it to a float interval *)letfitv=man.avalue(Common.V_float_intervalp)vin(* Refine it with the integer result *)letfitv'=ItvUtils.FloatItvNan.bwd_to_int_itvfitviitvin(* Evaluate the float interval to a float value *)letv'=man.eval(mk_avalue_expr(Common.V_float_intervalp)fitv'e.erange)in(* Refine the expression [e] with the new value [v'] *)refine_vexpre(man.meetvv')ve|>OptionExt.returnend|_->None(* Extended backward evaluations *)letbackward_extmanever=matchekindewith|E_unop(O_cast,ee)->(* We use the extended transfer function because we need to refine
a non-integer value *)backward_ext_castmaneeve(man.getr)|_->V.backward_extmanever(** {2 Utility functions} *)letzero=Nb(I.zero)letone=Nb(I.one)letof_zz1z2:t=Nb(I.of_zz1z2)letof_intn1n2:t=Nb(I.of_intn1n2)letz_of_z2zz'round=letopenZinletd,r=div_remzz'inifequalrzerothendelsebeginifroundthend+oneelsedendletz_of_mpzfmp=Z.of_string(Mpzf.to_stringmp)letz_of_mpqfmpround=letopenMpqfinletl,r=to_mpzf2mpinletlz,rz=z_of_mpzfl,z_of_mpzfrinz_of_z2lzrzroundletz_of_apron_scalarar=letopenApron.Scalarinmatcha,rwith|Floatf,true->Z.of_float(ceilf)|Floatf,false->Z.of_float(floorf)|Mpqfq,_->z_of_mpqfqr|Mpfrfmpf,_->z_of_mpqf(Mpfr.to_mpqmpf)rletof_apron(itv:Apron.Interval.t):t=ifApron.Interval.is_bottomitvthenbottomelseletmi=itv.Apron.Interval.infinletma=itv.Apron.Interval.supinletto_bmr=letx=Apron.Scalar.is_inftyminifx=0thenI.B.Finite(z_of_apron_scalarmr)elseifx>0thenI.B.PINFelseI.B.MINFinNb(to_bmifalse,to_bmatrue)letto_apron(itv:t):Apron.Interval.t=matchitvwith|BOT->Apron.Interval.bottom|Nb(a,b)->letbound_to_scalarb=matchbwith|I.B.MINF->Apron.Scalar.of_infty(-1)|I.B.PINF->Apron.Scalar.of_infty1|I.B.Finitez->Apron.Scalar.of_float(Z.to_floatz)inApron.Interval.of_infsup(bound_to_scalara)(bound_to_scalarb)letis_bounded(itv:t):bool=bot_dfl1trueI.is_boundeditvletbounds(itv:t):Z.t*Z.t=bot_dfl1(Z.one,Z.zero)(function|I.B.Finitea,I.B.Finiteb->(a,b)|_->panic"bounds called on a unbounded interval %a"(formatprint)itv)itvletbounds_opt(itv:t):Z.toption*Z.toption=bot_dfl1(None,None)(function|I.B.Finitea,I.B.Finiteb->(Somea,Someb)|I.B.Finitea,_->(Somea,None)|_,I.B.Finiteb->(None,Someb)|_->(None,None))itvletmem(i:Z.t)(itv:t):bool=bot_dfl1true(fun(a,b)->letopenI.Binleti=Finiteiingeqia&&leqib)itvletcompare_intervalitv1itv2=bot_compare(I.compare)itv1itv2letmap(f:Z.t->'a)(itv:t):'alist=ifnot(is_boundeditv)thenpanic~loc:__LOC__"map: unbounded interval %a"(formatprint)itvelseifis_bottomitvthen[]elseleta,b=boundsitvinletreciteri=ifZ.equalibthen[fi]elsefi::iter(Z.succi)initeraendlet()=register_value_abstraction(moduleValue)