123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Abstract Syntax Tree extension for the simple Universal language. *)openMopsaopenFormat(** {2 Universal types} *)(* ******************* *)typefloat_prec=|F_SINGLE(** IEEE single-precision 32-bit *)|F_DOUBLE(** IEEE double-precision 64-bit *)|F_LONG_DOUBLE(** extended precision, abstracted as double *)|F_FLOAT128(** quadruple precision, abstracted as double *)|F_REAL(** no rounding, abstracted as double *)typetyp+=|T_int(** Mathematical integers with arbitrary precision. *)|T_floatoffloat_prec(** Floating-point real numbers. *)|T_string(** Strings. *)|T_arrayoftyp(** Array of [typ] *)|T_unit(** Unit type *)|T_charletpp_float_precfmt=function|F_SINGLE->pp_print_stringfmt"float"|F_DOUBLE->pp_print_stringfmt"double"|F_LONG_DOUBLE->pp_print_stringfmt"long double"|F_FLOAT128->pp_print_stringfmt"__float128"|F_REAL->pp_print_stringfmt"real"letpp_float_opoprealopfloatfmt=function|F_SINGLE->fprintffmt"%sf"opfloat|F_DOUBLE->fprintffmt"%sd"opfloat|F_LONG_DOUBLE->fprintffmt"%sl"opreal|F_FLOAT128->fprintffmt"%sq"opreal|F_REAL->pp_print_stringfmtopreallet()=register_typ{compare=(funnextt1t2->matcht1,t2with|T_arrayt1,T_arrayt2->compare_typt1t2|_->nextt1t2);print=(fundefaultfmttyp->matchtypwith|T_unit->pp_print_stringfmt"unit"|T_int->pp_print_stringfmt"int"|T_floatp->pp_float_precfmtp|T_string->pp_print_stringfmt"string"|T_addr->pp_print_stringfmt"addr"|T_char->pp_print_stringfmt"char"|T_arrayt->Format.fprintffmt"[%a]"pp_typt|_->defaultfmttyp);}(** {2 Universal constants} *)(* *********************** *)typeconstant+=|C_unit|C_intofZ.t(** Integer numbers, with arbitrary precision. *)|C_floatoffloat(** Floating-point numbers. *)|C_stringofstring(** String constants. *)|C_int_intervalofItvUtils.IntBound.t*ItvUtils.IntBound.t(** Integer ranges. *)|C_float_intervaloffloat*float(** Float ranges. *)(** Constants. *)let()=register_constant{compare=(funnextc1c2->matchc1,c2with|C_intz1,C_intz2->Z.comparez1z2|C_floatf1,C_floatf2->Stdlib.comparef1f2|C_strings1,C_strings2->Stdlib.compares1s2|C_int_interval(z1,z1'),C_int_interval(z2,z2')->Compare.compose[(fun()->ItvUtils.IntBound.comparez1z2);(fun()->ItvUtils.IntBound.comparez1'z2')]|C_float_interval(f1,f1'),C_float_interval(f2,f2')->Compare.compose[(fun()->Stdlib.comparef1f2);(fun()->Stdlib.comparef1'f2')]|_->nextc1c2);print=(fundefaultfmt->function|C_unit->fprintffmt"()"|C_string(s)->fprintffmt"\"%s\""s|C_int(n)->Z.pp_printfmtn|C_float(f)->pp_print_floatfmtf|C_int_interval(a,b)->fprintffmt"[%a,%a]"ItvUtils.IntBound.fprintaItvUtils.IntBound.fprintb|C_float_interval(a,b)->fprintffmt"[%a,%a]"pp_print_floatapp_print_floatb|c->defaultfmtc);}(** {2 Universal operators} *)(* *********************** *)typefloat_class={float_valid:bool;(* normal, denormal, +0 or -0 float *)float_inf:bool;(* +∞ or -∞ *)float_nan:bool;(* not-a-number *)}letpp_float_classfmtc=pp_print_list~pp_sep:(funfmt()->pp_print_stringfmt",")pp_print_stringfmt((ifc.float_validthen["valid"]else[])@(ifc.float_infthen["inf"]else[])@(ifc.float_nanthen["nan"]else[]))typeoperator+=(* Unary operators *)|O_sqrt(** square root *)|O_abs(** absolute value *)|O_bit_invert(** bitwise ~ *)|O_wrapofZ.t*Z.t(** wrap *)|O_filter_float_classoffloat_class(** filter float by class *)(* Binary operators *)|O_plus(** + *)|O_minus(** - *)|O_mult(** * *)|O_div(** / *)|O_mod(** % where the remainder can be negative, following C *)|O_ediv(** euclidian division *)|O_erem(** remainder for euclidian division *)|O_pow(** power *)|O_bit_and(** & *)|O_bit_or(** | *)|O_bit_xor(** ^ *)|O_bit_rshift(** >> *)|O_bit_lshift(** << *)|O_concat(** concatenation of arrays and strings *)|O_convex_join(** convex join of arithmetic expressions *)(* Float predicates *)|O_float_classoffloat_classlet()=register_operator{compare=(funnextop1op2->matchop1,op2with|O_wrap(l1,u1),O_wrap(l2,u2)->Compare.compose[(fun()->Z.comparel1l2);(fun()->Z.compareu1u2)]|_->nextop1op2);print=(fundefaultfmtop->matchopwith|O_plus->pp_print_stringfmt"+"|O_minus->pp_print_stringfmt"-"|O_mult->pp_print_stringfmt"*"|O_div->pp_print_stringfmt"/"|O_mod->pp_print_stringfmt"%"|O_ediv->pp_print_stringfmt"/↓"|O_erem->pp_print_stringfmt"%↓"|O_pow->pp_print_stringfmt"**"|O_sqrt->pp_print_stringfmt"sqrt"|O_abs->pp_print_stringfmt"abs"|O_bit_invert->pp_print_stringfmt"~"|O_wrap(l,u)->fprintffmt"wrap(%a, %a)"Z.pp_printlZ.pp_printu|O_concat->pp_print_stringfmt"@"|O_bit_and->pp_print_stringfmt"&"|O_bit_or->pp_print_stringfmt"|"|O_bit_xor->pp_print_stringfmt"^"|O_bit_rshift->pp_print_stringfmt">>"|O_bit_lshift->pp_print_stringfmt"<<"|O_convex_join->pp_print_stringfmt"⋓"|O_float_classc->Format.fprintffmt"float_class[%a]"pp_float_classc|O_filter_float_classc->Format.fprintffmt"filter_float_class[%a]"pp_float_classc|op->defaultfmtop);}(** {2 Universal functions} *)(* *********************** *)(** Function definition *)typefundec={fun_orig_name:string;(** original name of the function *)fun_uniq_name:string;(** unique name of the function *)fun_range:range;(** function range *)fun_parameters:varlist;(** list of parameters *)fun_locvars:varlist;(** list of local variables *)mutablefun_body:stmt;(** body of the function *)fun_return_type:typoption;(** return type *)fun_return_var:varoption;(** variable storing the return value *)}typefun_builtin={name:string;args:typoptionlist;output:typ}typefun_expr=|User_definedoffundec|Builtinoffun_builtinletcompare_fun_exprxy=matchx,ywith|User_defineda,User_definedb->Stdlib.comparea.fun_uniq_nameb.fun_uniq_name|Builtina,Builtinb->Stdlib.compareab|_->1(** {2 Universal program} *)(* ********************* *)typeu_program={universal_gvars:varlist;universal_fundecs:fundeclist;universal_main:stmt;}typeprog_kind+=|P_universalofu_programlet()=register_program{compare=(funnext->next);print=(fundefaultfmtprg->matchprg.prog_kindwith|P_universal(u_prog)->Format.fprintffmt"@[<v>%a@,%a@]"(pp_print_list~pp_sep:(funfmt()->fprintffmt"@\n")(funfmtf->fprintffmt"%a %a(%a) {@\n@[<v 4> %a@]@\n}"(funfmtot->matchotwith|None->pp_print_stringfmt"void"|Somet->pp_typfmtt)f.fun_return_typeFormat.pp_print_stringf.fun_orig_name(pp_print_list~pp_sep:(funfmt()->fprintffmt", ")(funfmtv->Format.fprintffmt"%a %a"pp_typv.vtyppp_varv))f.fun_parameterspp_stmtf.fun_body))u_prog.universal_fundecspp_stmtu_prog.universal_main|_->defaultfmtprg);}moduleUProgramKey=GenContextKey(structtype'at=u_programletprintppfmtprog=Format.fprintffmt"U program"end)(** Flow-insensitive context to keep the analyzed C program *)letu_program_ctx=UProgramKey.key(** Set the C program in the flow *)letset_u_programprogflow=Flow.set_ctx(Flow.get_ctxflow|>add_ctxu_program_ctxprog)flow(** Get the C program from the flow *)letget_u_programflow=Flow.get_ctxflow|>find_ctxu_program_ctx(** {2 Universal expressions} *)(* ************************* *)typeexpr_kind+=(** Function expression *)|E_functionoffun_expr(** Function calls *)|E_callofexpr(** Function expression *)*exprlist(** List of arguments *)(** Array value as a list of expressions *)|E_arrayofexprlist(** Subscript access to an indexed object (arrays) *)|E_subscriptofexpr*expr(** Length of array or string *)|E_lenofexprlet()=register_expr_with_visitor{compare=(funnexte1e2->matchekinde1,ekinde2with|E_function(f1),E_function(f2)->compare_fun_exprf1f2|E_call(f1,args1),E_call(f2,args2)->Compare.compose[(fun()->compare_exprf1f2);(fun()->Compare.listcompare_exprargs1args2)]|E_array(el1),E_array(el2)->Compare.listcompare_exprel1el2|E_subscript(a1,i1),E_subscript(a2,i2)->Compare.compose[(fun()->compare_expra1a2);(fun()->compare_expri1i2);]|E_len(a1),E_len(a2)->compare_expra1a2|_->nexte1e2);print=(fundefaultfmtexp->matchekindexpwith|E_array(el)->fprintffmt"[@[<h>%a@]]"(pp_print_list~pp_sep:(funfmt()->pp_print_stringfmt", ")pp_expr)el|E_subscript(v,e)->fprintffmt"%a[%a]"pp_exprvpp_expre|E_function(f)->fprintffmt"fun %s"(matchfwith|User_definedf->f.fun_orig_name|Builtinf->f.name)|E_call(f,args)->fprintffmt"%a(%a)"pp_exprf(pp_print_list~pp_sep:(funfmt()->fprintffmt", ")pp_expr)args|E_lenexp->Format.fprintffmt"|%a|"pp_exprexp|_->defaultfmtexp);visit=(fundefaultexp->matchekindexpwith|E_function_->leafexp|E_subscript(v,e)->{exprs=[v;e];stmts=[]},(funparts->{expwithekind=(E_subscript(List.hdparts.exprs,List.hd@@List.tlparts.exprs))})|E_array(el)->{exprs=el;stmts=[]},(funparts->{expwithekind=E_arrayparts.exprs})|E_call(f,args)->{exprs=f::args;stmts=[]},(funparts->{expwithekind=E_call(List.hdparts.exprs,List.tlparts.exprs)})|E_len(e)->{exprs=[e];stmts=[]},(funparts->{expwithekind=E_len(List.hdparts.exprs)})|_->defaultexp);}(** {2 Universal statements} *)(* ************************ *)typestmt_kind+=|S_expressionofexpr(** Expression statement, useful for calling functions without a return value *)|S_ifofexpr(** condition *)*stmt(** then branch *)*stmt(** else branch *)|S_returnofexproption(** Function return with an optional return expression *)|S_whileofexpr(** loop condition *)*stmt(** loop body *)(** While loops *)|S_break(** Loop break *)|S_continue(** Loop continue *)|S_unit_testsof(string*stmt)list(** list of unit tests and their names *)(** Unit tests suite *)|S_assertofexpr(** Unit tests assertions *)|S_satisfyofexpr(** Unit tests satisfiability check *)|S_print_state(** Print the abstract flow map at current location *)|S_print_exprofexprlist(** Pretty print the values of expressions *)|S_freeofaddr(** Release a heap address *)let()=register_stmt_with_visitor{compare=(funnexts1s2->matchskinds1,skinds2with|S_expression(e1),S_expression(e2)->compare_expre1e2|S_if(c1,then1,else1),S_if(c2,then2,else2)->Compare.compose[(fun()->compare_exprc1c2);(fun()->compare_stmtthen1then2);(fun()->compare_stmtelse1else2);]|S_return(e1),S_return(e2)->Compare.optioncompare_expre1e2|S_while(c1,body1),S_while(c2,body2)->Compare.compose[(fun()->compare_exprc1c2);(fun()->compare_stmtbody1body2)]|S_unit_tests(tl1),S_unit_tests(tl2)->Compare.list(fun(t1,_)(t2,_)->Stdlib.comparet1t2)tl1tl2|S_assert(e1),S_assert(e2)->compare_expre1e2|S_satisfy(e1),S_satisfy(e2)->compare_expre1e2|S_free(a1),S_free(a2)->compare_addra1a2|S_print_exprel1,S_print_exprel2->Compare.listcompare_exprel1el2|_->nexts1s2);print=(fundefaultfmtstmt->matchskindstmtwith|S_expression(e)->fprintffmt"%a;"pp_expre|S_if(e,s1,s2)->fprintffmt"@[<v 4>if (%a) {@,%a@]@,@[<v 4>} else {@,%a@]@,}"pp_exprepp_stmts1pp_stmts2|S_return(None)->pp_print_stringfmt"return;"|S_return(Somee)->fprintffmt"return %a;"pp_expre|S_while(e,s)->fprintffmt"@[<v 4>while %a {@,%a@]@,}"pp_exprepp_stmts|S_break->pp_print_stringfmt"break;"|S_continue->pp_print_stringfmt"continue;"|S_unit_tests(tests)->pp_print_list~pp_sep:(funfmt()->fprintffmt"@\n")(funfmt(name,test)->fprintffmt"test %s:@\n @[%a@]"namepp_stmttest)fmttests|S_asserte->fprintffmt"assert(%a);"pp_expre|S_satisfye->fprintffmt"sat(%a);"pp_expre|S_print_state->fprintffmt"print();"|S_print_exprel->fprintffmt"print_expr(%a);"(pp_print_list~pp_sep:(funfmt()->pp_print_stringfmt", ")pp_expr)el|S_free(a)->fprintffmt"free(%a);"pp_addra|_->defaultfmtstmt);visit=(fundefaultstmt->matchskindstmtwith|S_break|S_continue->leafstmt|S_expression(e)->{exprs=[e];stmts=[]},(funparts->{stmtwithskind=S_expression(List.hdparts.exprs)})|S_if(e,s1,s2)->{exprs=[e];stmts=[s1;s2]},(funparts->{stmtwithskind=S_if(List.hdparts.exprs,List.hdparts.stmts,List.nthparts.stmts1)})|S_while(e,s)->{exprs=[e];stmts=[s]},(funparts->{stmtwithskind=S_while(List.hdparts.exprs,List.hdparts.stmts)})|S_return(None)->leafstmt|S_return(Somee)->{exprs=[e];stmts=[]},(function{exprs=[e]}->{stmtwithskind=S_return(Somee)}|_->assertfalse)|S_assert(e)->{exprs=[e];stmts=[]},(function{exprs=[e]}->{stmtwithskind=S_assert(e)}|_->assertfalse)|S_satisfy(e)->{exprs=[e];stmts=[]},(function{exprs=[e]}->{stmtwithskind=S_satisfy(e)}|_->assertfalse)|S_unit_tests(tests)->lettests_names,tests_bodies=List.splittestsin{exprs=[];stmts=tests_bodies},(function{stmts=tests_bodies}->lettests=List.combinetests_namestests_bodiesin{stmtwithskind=S_unit_tests(tests)})|S_print_state->leafstmt|S_print_exprel->{exprs=el;stmts=[]},(function{exprs}->{stmtwithskind=S_print_exprexprs})|S_free_->leafstmt|_->defaultstmt);}(** {2 Utility functions} *)(* ********************* *)letrecis_universal_typet=matchtwith|T_bool|T_int|T_float_|T_string|T_addr|T_unit|T_char->true|T_arraytt->is_universal_typett|_->falseletmk_inti?(typ=T_int)erange=mk_constant~etyp:typ(C_int(Z.of_inti))erangeletmk_zi?(typ=T_int)erange=mk_constant~etyp:typ(C_inti)erangeletmk_float?(prec=F_DOUBLE)ferange=mk_constant~etyp:(T_floatprec)(C_floatf)erangeletmk_int_intervalab?(typ=T_int)range=mk_constant~etyp:typ(C_int_interval(ItvUtils.IntBound.of_inta,ItvUtils.IntBound.of_intb))rangeletmk_int_general_intervalab?(typ=T_int)range=mk_constant~etyp:typ(C_int_interval(a,b))rangeletmk_z_intervalab?(typ=T_int)range=mk_constant~etyp:typ(C_int_interval(ItvUtils.IntBound.Finitea,ItvUtils.IntBound.Finiteb))rangeletmk_float_interval?(prec=F_DOUBLE)abrange=mk_constant~etyp:(T_floatprec)(C_float_interval(a,b))rangeletmk_string?(etyp=T_string)s=mk_constant~etyp:etyp(C_strings)letmk_in?(strict=false)?(left_strict=false)?(right_strict=false)?(etyp=T_bool)ve1e2erange=matchstrict,left_strict,right_strictwith|true,_,_|false,true,true->mk_binop(mk_binope1O_ltv~etyperange)O_log_and(mk_binopvO_lte2~etyperange)~etyperange|false,true,false->mk_binop(mk_binope1O_ltv~etyperange)O_log_and(mk_binopvO_lee2~etyperange)~etyperange|false,false,true->mk_binop(mk_binope1O_lev~etyperange)O_log_and(mk_binopvO_lte2~etyperange)~etyperange|false,false,false->mk_binop(mk_binope1O_lev~etyperange)O_log_and(mk_binopvO_lee2~etyperange)~etyperangeletmk_zero=mk_int0letmk_one=mk_int1letmk_minus_one=mk_int(-1)letuniversal_constants_range=tag_range(mk_fresh_range())"universal-constants"letzero=mk_zerouniversal_constants_rangeletone=mk_oneuniversal_constants_rangeletminus_one=mk_minus_oneuniversal_constants_rangeletof_z=mk_zletof_int=mk_intletadde1e2?(typ=e1.etyp)range=mk_binope1O_pluse2range~etyp:typletsube1e2?(typ=e1.etyp)range=mk_binope1O_minuse2range~etyp:typletmule1e2?(typ=e1.etyp)range=mk_binope1O_multe2range~etyp:typletdive1e2?(typ=e1.etyp)range=mk_binope1O_dive2range~etyp:typletedive1e2?(typ=e1.etyp)range=mk_binope1O_edive2range~etyp:typlet_mod_e1e2?(typ=e1.etyp)range=mk_binope1O_mode2range~etyp:typletereme1e2?(typ=e1.etyp)range=mk_binope1O_ereme2range~etyp:typletsuccerange=addeonerangeletprederange=subeonerangeletmk_succ=succletmk_pred=predleteqe1e2?(etyp=T_bool)range=mk_binope1O_eqe2~etyprangeletnee1e2?(etyp=T_bool)range=mk_binope1O_nee2~etyprangeletlte1e2?(etyp=T_bool)range=mk_binope1O_lte2~etyprangeletlee1e2?(etyp=T_bool)range=mk_binope1O_lee2~etyprangeletgte1e2?(etyp=T_bool)range=mk_binope1O_gte2~etyprangeletgee1e2?(etyp=T_bool)range=mk_binope1O_gee2~etyprangeletmk_eq=eqletmk_ne=neletmk_lt=ltletmk_le=leletmk_gt=gtletmk_ge=geletlog_ore1e2?(etyp=T_bool)range=mk_binope1O_log_ore2~etyprangeletlog_ande1e2?(etyp=T_bool)range=mk_binope1O_log_ande2~etyprangeletlog_xore1e2?(etyp=T_bool)range=mk_binope1O_log_xore2~etyprangeletmk_log_or=log_orletmk_log_and=log_andletmk_log_xor=log_xor(* float classes *)letfloat_class?(valid=false)?(inf=false)?(nan=false)()={float_valid=valid;float_inf=inf;float_nan=nan;}letinv_float_classc=float_class~valid:(notc.float_valid)~inf:(notc.float_inf)~nan:(notc.float_nan)()letfloat_valid=float_class~valid:true()letfloat_inf=float_class~inf:true()letfloat_nan=float_class~nan:true()letmk_float_class(c:float_class)erange=mk_unop(O_float_classc)e~etyp:T_boolrangeletmk_filter_float_class(c:float_class)erange=mk_unop(O_filter_float_classc)e~etyp:(etype)rangeletmk_unitrange=mk_constantC_unit~etyp:T_unitrangeletmk_boolbrange=mk_constant~etyp:T_bool(C_boolb)rangeletmk_true=mk_booltrueletmk_false=mk_boolfalseletis_int_type=function|T_int|T_bool->true|_->falseletis_float_type=function|T_float_->true|_->falseletis_numeric_type=function|T_bool|T_int|T_float_->true|_->falseletis_math_type=function|T_int|T_float_|T_bool->true|_->falseletis_predicate_op=function|O_float_class_->true|_->falseletmk_asserterange=mk_stmt(S_asserte)rangeletmk_satisfyerange=mk_stmt(S_satisfye)rangeletmk_blockblock?(vars=[])range=mk_stmt(S_block(block,vars))rangeletmk_noprange=mk_block[]rangeletmk_ifcondbodyorelserange=mk_stmt(S_if(cond,body,orelse))rangeletmk_whilecondbodyrange=mk_stmt(S_while(cond,body))rangeletmk_callfundecargsrange=mk_expr(E_call(mk_expr(E_function(User_definedfundec))range,args))~etyp:(matchfundec.fun_return_typewithNone->T_any|Somet->t)rangeletmk_expr_stmte=mk_stmt(S_expressione)letmk_freeaddrrange=mk_stmt(S_freeaddr)rangeletmk_remove_addrarange=mk_remove(mk_addrarange)rangeletmk_invalidate_addrarange=mk_invalidate(mk_addrarange)rangeletmk_rename_addra1a2range=mk_rename(mk_addra1range)(mk_addra2range)rangeletmk_expand_addraalrange=mk_expand(mk_addrarange)(List.map(funaa->mk_addraarange)al)rangeletmk_fold_addraalrange=mk_fold(mk_addrarange)(List.map(funaa->mk_addraarange)al)rangeletrecexpr_to_conste:constantoption=ifnot(is_numeric_typee.etyp)thenNoneelsematchekindewith|E_constantc->Somec|E_unop(O_log_not,ee)->beginmatchexpr_to_consteewith|None->None|Some(C_boolb)->Some(C_bool(notb))|Some(C_topT_bool)asx->x|_->Noneend|E_unop(O_minus,e')->beginmatchexpr_to_conste'with|None->None|Some(C_intn)->Some(C_int(Z.negn))|Some(C_topT_int)asx->x|_->Noneend|E_binop(op,e1,e2)whenis_comparison_opop->beginmatchop,expr_to_conste1,expr_to_conste2with|O_eq,Some(C_intn1),Some(C_intn2)->Some(C_boolZ.(n1=n2))|O_eq,Some(C_intn),Some(C_int_interval(a,b))|O_eq,Some(C_int_interval(a,b)),Some(C_intn)->letn=ItvUtils.IntBound.Finiteninletc=ifItvUtils.IntBound.leqan&&ItvUtils.IntBound.leqnbthenC_topT_boolelseC_boolfalseinSomec|O_ne,Some(C_intn1),Some(C_intn2)->Some(C_boolZ.(n1<>n2))|O_ne,Some(C_intn),Some(C_int_interval(a,b))|O_ne,Some(C_int_interval(a,b)),Some(C_intn)->letn=ItvUtils.IntBound.Finiteninletc=ifItvUtils.IntBound.leqan&&ItvUtils.IntBound.leqnbthenC_topT_boolelseC_booltrueinSomec|O_le,Some(C_intn1),Some(C_intn2)|O_ge,Some(C_intn2),Some(C_intn1)->Some(C_boolZ.(n1<=n2))|O_le,Some(C_intn),Some(C_int_interval(a,b))|O_ge,Some(C_int_interval(a,b)),Some(C_intn)->letn=ItvUtils.IntBound.Finiteninletc=ifItvUtils.IntBound.leqnathenC_booltrueelseifItvUtils.IntBound.gtnbthenC_boolfalseelseC_topT_boolinSomec|O_le,Some(C_int_interval(a,b)),Some(C_intn)|O_ge,Some(C_intn),Some(C_int_interval(a,b))->letn=ItvUtils.IntBound.Finiteninletc=ifItvUtils.IntBound.leqbnthenC_booltrueelseifItvUtils.IntBound.gtanthenC_boolfalseelseC_topT_boolinSomec|O_lt,Some(C_intn1),Some(C_intn2)|O_gt,Some(C_intn2),Some(C_intn1)->Some(C_boolZ.(n1<n2))|O_lt,Some(C_intn),Some(C_int_interval(a,b))|O_gt,Some(C_int_interval(a,b)),Some(C_intn)->letn=ItvUtils.IntBound.Finiteninletc=ifItvUtils.IntBound.ltnathenC_booltrueelseifItvUtils.IntBound.geqnbthenC_boolfalseelseC_topT_boolinSomec|O_lt,Some(C_int_interval(a,b)),Some(C_intn)|O_gt,Some(C_intn),Some(C_int_interval(a,b))->letn=ItvUtils.IntBound.Finiteninletc=ifItvUtils.IntBound.ltbnthenC_booltrueelseifItvUtils.IntBound.geqanthenC_boolfalseelseC_topT_boolinSomec|_->Noneend|E_binop(O_log_and,e1,e2)->beginmatchexpr_to_conste1,expr_to_conste2with|Some(C_boolb1),Some(C_boolb2)->Some(C_bool(b1&&b2))|Some(C_topT_bool),Some(C_boolfalse)|Some(C_boolfalse),Some(C_topT_bool)->Some(C_boolfalse)|Some(C_topT_bool),Some(C_booltrue)|Some(C_booltrue),Some(C_topT_bool)|Some(C_topT_bool),Some(C_topT_bool)->Some(C_topT_bool)|_->Noneend|E_binop(O_log_or,e1,e2)->beginmatchexpr_to_conste1,expr_to_conste2with|Some(C_boolb1),Some(C_boolb2)->Some(C_bool(b1||b2))|Some(C_topT_bool),Some(C_booltrue)|Some(C_booltrue),Some(C_topT_bool)->Some(C_booltrue)|Some(C_topT_bool),Some(C_boolfalse)|Some(C_boolfalse),Some(C_topT_bool)|Some(C_topT_bool),Some(C_topT_bool)->Some(C_topT_bool)|_->Noneend|E_binop(O_log_xor,e1,e2)->beginmatchexpr_to_conste1,expr_to_conste2with|Some(C_boolb1),Some(C_boolb2)->Some(C_bool(ifb1thennotb2elseb2))|Some(C_topT_bool),_|_,Some(C_topT_bool)->Some(C_topT_bool)|_->Noneend|E_binop(O_plus|O_minus|O_mult|O_div|O_mod|O_ediv|O_eremasop,e1,e2)->beginmatchexpr_to_conste1,expr_to_conste2with|Some(C_intn1),Some(C_intn2)->beginmatchopwith|O_plus->Some(C_int(Z.addn1n2))|O_minus->Some(C_int(Z.subn1n2))|O_mult->Some(C_int(Z.muln1n2))|O_div->ifZ.equaln2Z.zerothenNoneelseSome(C_int(Z.divn1n2))|O_mod->ifZ.equaln2Z.zerothenNoneelseSome(C_int(Z.remn1n2))|O_ediv->ifZ.equaln2Z.zerothenNoneelseSome(C_int(Z.edivn1n2))|O_erem->ifZ.equaln2Z.zerothenNoneelseSome(C_int(Z.eremn1n2))|_->Noneend|_->Noneend|_->Noneletexpr_to_z(e:expr):Z.toption=matchexpr_to_constewith|Some(C_intn)->Somen|Some(C_booltrue)->SomeZ.one|Some(C_boolfalse)->SomeZ.zero|_->NonemoduleAddr=structtypet=addrletcompare=compare_addrletprint=unformatpp_addrletfrom_expre=matchekindewith|E_addr(addr,_)->addr|_->assertfalseendmoduleAddrSet=structincludeSetExt.Make(Addr)letprintprinters=pp_listAddr.printprinter(elementss)~lopen:"{"~lsep:","~lclose:"}"end