123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692(***************************************************************************)(* This file is part of the third-party OCaml library `smtml`. *)(* Copyright (C) 2023-2024 formalsec *)(* *)(* This program is free software: you can redistribute it and/or modify *)(* it under the terms of the GNU 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 General Public License for more details. *)(* *)(* You should have received a copy of the GNU General Public License *)(* along with this program. If not, see <https://www.gnu.org/licenses/>. *)(***************************************************************************)includeMappings_intfmoduleMake(M_with_make:M_with_make):S_with_fresh=structmoduleMake_(M:M):S=structopenTytypesym_tbl=(Symbol.t,M.term)Hashtbl.ttypemodel={model:M.model;symbol_table:sym_tbl}typesolver={solver:M.solver;symbol_table:sym_tbl}typehandle=M.handletypeoptimize={opt:M.optimizer;symbol_table:sym_tbl}leterr=Log.errleti8=M.Types.bitv8leti32=M.Types.bitv32leti64=M.Types.bitv64letf32=M.Types.float824letf64=M.Types.float1153letget_type=function|Ty_int->M.Types.int|Ty_real->M.Types.real|Ty_bool->M.Types.bool|Ty_str->M.Types.string|Ty_bitv8->i8|Ty_bitv32->i32|Ty_bitv64->i64|Ty_fp32->f32|Ty_fp64->f64|Ty_bitv_|Ty_fp_|Ty_list|Ty_array|Ty_tuple->assertfalseletmake_symbol(symbol_table:sym_tbl)(s:Symbol.t):M.term=matchHashtbl.find_optsymbol_tableswith|Somesym->sym|None->letsym=M.consts.name(get_types.ty)inHashtbl.replacesymbol_tablessym;symmoduleBool_impl=structlettrue_=M.true_letfalse_=M.false_letunop=function|Not->M.not_|op->err{|Bool: Unsupported Z3 unop operator "%a"|}Ty.pp_unopopletbinop=function|And->M.and_|Or->M.or_|Xor->M.xor|op->err{|Bool: Unsupported Z3 binop operator "%a"|}Ty.pp_binopoplettriop=function|Ite->M.ite|op->err{|Bool: Unsupported Z3 triop operator "%a"|}Ty.pp_triopopletrelopope1e2=matchopwith|Eq->M.eqe1e2|Ne->M.distinct[e1;e2]|_->err{|Bool: Unsupported Z3 relop operator "%a"|}Ty.pp_relopopletcvtop_op_e=assertfalseendmoduleInt_impl=structletvi=M.inti[@@inline]letunop=function|Neg->M.Int.neg|op->err{|Int: Unsupported unop operator "%a"|}Ty.pp_unopopletbinop=function|Add->M.Int.add|Sub->M.Int.sub|Mul->M.Int.mul|Div->M.Int.div|Rem->M.Int.rem|Pow->M.Int.pow|op->err{|Int: Unsupported binop operator "%a"|}Ty.pp_binopopletrelop=function|Eq|Ne->assertfalse|Lt->M.Int.lt|Gt->M.Int.gt|Le->M.Int.le|Ge->M.Int.ge|op->err{|Int: Unsupported relop operator "%a"|}Ty.pp_relopop(* TODO: Uninterpreted cvtops *)letcvtopope=matchopwith|ToString->assertfalse|OfString->assertfalse|Reinterpret_float->M.Real.to_inte|op->err{|Int: Unsupported cvtop operator "%a"|}Ty.pp_cvtopopendmoduleReal_impl=structletvf=M.realf[@@inline]letunopope=letopenMinmatchopwith|Neg->Real.nege|Abs->ite(Real.gte(real0.))e(Real.nege)|Sqrt->Real.powe(v0.5)|Ceil->letx_int=M.Real.to_inteinite(eq(Int.to_realx_int)e)x_int(Int.addx_int(int1))|Floor->Real.to_inte|Nearest|Is_nan|_->err{|Real: Unsupported unop operator "%a"|}Ty.pp_unopopletbinopope1e2=matchopwith|Add->M.Real.adde1e2|Sub->M.Real.sube1e2|Mul->M.Real.mule1e2|Div->M.Real.dive1e2|Pow->M.Real.powe1e2|Min->M.ite(M.Real.lee1e2)e1e2|Max->M.ite(M.Real.gee1e2)e1e2|_->err{|Real: Unsupported binop operator "%a"|}Ty.pp_binopopletrelopope1e2=matchopwith|Eq->M.eqe1e2|Ne->M.distinct[e1;e2]|Lt->M.Real.lte1e2|Gt->M.Real.gte1e2|Le->M.Real.lee1e2|Ge->M.Real.gee1e2|_->err{|Real: Unsupported relop operator "%a"|}Ty.pp_relopop(* TODO: Uninterpreted cvtops *)letcvtopope=matchopwith|ToString->assertfalse|OfString->assertfalse|ConvertUI32->assertfalse|Reinterpret_int->M.Int.to_reale|op->err{|Real: Unsupported cvtop operator "%a"|}Ty.pp_cvtopopendmoduleString_impl=structletvs=M.String.vs[@@inline](* let trim = FuncDecl.mk_func_decl_s ctx "Trim" [ str_sort ] str_sort *)letunop=function|Seq_length->M.String.length|Trim->(* FuncDecl.apply trim [ e ] *)assertfalse|op->err{|String: Unsupported unop operator "%a"|}Ty.pp_unopopletbinopope1e2=matchopwith|Seq_at->M.String.ate1~pos:e2|Seq_concat->M.String.concate1e2|Seq_contains->M.String.containse1~sub:e2|Seq_prefix->M.String.is_prefixe1~prefix:e2|Seq_suffix->M.String.is_suffixe1~suffix:e2|_->err{|String: Unsupported binop operator "%a"|}Ty.pp_binopoplettriopope1e2e3=matchopwith|Seq_extract->M.String.sube1~pos:e2~len:e3|Seq_index->M.String.index_ofe1~sub:e2~pos:e3|Seq_replace->M.String.replacee1~pattern:e2~with_:e3|_->err{|String: Unsupported triop operator "%a"|}Ty.pp_triopopletrelopope1e2=matchopwith|Eq->M.eqe1e2|Ne->M.distinct[e1;e2]|_->err{|String: Unsupported relop operator "%a"|}Ty.pp_relopopletcvtop=function|String_to_code->M.String.to_code|String_from_code->M.String.of_code|String_to_int->M.String.to_int|String_from_int->M.String.of_int|op->err{|String: Unsupported cvtop operator "%a"|}Ty.pp_cvtopopendmoduletypeBitv_sig=sigtypeeltvalv:elt->M.termvalbitwidth:intmoduleIxx:sigvalof_int:int->eltvalshift_left:elt->int->eltendendmoduleBitv_impl(B:Bitv_sig)=structopenMincludeB(* Stolen from @krtab in OCamlPro/owi#195 *)letclzn=letrecloop(lb:int)(ub:int)=ifub=lb+1thenv@@Ixx.of_int(bitwidth-ub)elseletmid=(lb+ub)/2inletpow_two_mid=vIxx.(shift_left(of_int1)mid)inite(Bitv.lt_unpow_two_mid)(looplbmid)(loopmidub)inite(eqn(v@@Ixx.of_int0))(v@@Ixx.of_intbitwidth)(loop0bitwidth)(* Stolen from @krtab in OCamlPro/owi #195 *)letctzn=letzero=v(Ixx.of_int0)inletrecloop(lb:int)(ub:int)=ifub=lb+1thenv(Ixx.of_intlb)elseletmid=(lb+ub)/2inletpow_two_mid=vIxx.(shift_left(of_int1)mid)inM.ite(eq(Bitv.remnpow_two_mid)zero)(loopmidub)(looplbmid)inite(eqnzero)(v@@Ixx.of_intbitwidth)(loop0bitwidth)letunop=function|Clz->clz|Ctz->ctz|Neg->Bitv.neg|Not->Bitv.lognot|op->err{|Bitv: Unsupported unary operator "%a"|}Ty.pp_unopopletbinop=function|Add->Bitv.add|Sub->Bitv.sub|Mul->Bitv.mul|Div->Bitv.div|DivU->Bitv.div_u|And->Bitv.logand|Xor->Bitv.logxor|Or->Bitv.logor|Shl->Bitv.shl|ShrA->Bitv.ashr|ShrL->Bitv.lshr|Rem->Bitv.rem|RemU->Bitv.rem_u|Rotl->Bitv.rotate_left|Rotr->Bitv.rotate_right|op->err{|Bitv: Unsupported binary operator "%a"|}Ty.pp_binopoplettriopop_=err{|Bitv: Unsupported triop operator "%a"|}Ty.pp_triopopletrelopope1e2=matchopwith|Eq|Ne->assertfalse|Lt->Bitv.lte1e2|LtU->Bitv.lt_ue1e2|Le->Bitv.lee1e2|LeU->Bitv.le_ue1e2|Gt->Bitv.gte1e2|GtU->Bitv.gt_ue1e2|Ge->Bitv.gee1e2|GeU->Bitv.ge_ue1e2letcvtopope=matchopwith|WrapI64->Bitv.extracte~high:(bitwidth-1)~low:0|Sign_extendn->Bitv.sign_extendne|Zero_extendn->Bitv.zero_extendne|TruncSF32|TruncSF64->Float.to_sbvbitwidth~rm:Float.Rounding_mode.rtze|TruncUF32|TruncUF64->Float.to_ubvbitwidth~rm:Float.Rounding_mode.rtze|Reinterpret_float->Float.to_ieee_bve|ToBool->M.distinct[e;v@@Ixx.of_int0]|OfBool->itee(v@@Ixx.of_int1)(v@@Ixx.of_int0)|_->assertfalseendmoduleI8=Bitv_impl(structtypeelt=intletvi=M.Bitv.v(string_of_inti)8letbitwidth=8moduleIxx=structletof_inti=i[@@inline]letshift_leftvi=vlsli[@@inline]endend)moduleI32=Bitv_impl(structtypeelt=int32letvi=M.Bitv.v(Int32.to_stringi)32letbitwidth=32moduleIxx=Int32end)moduleI64=Bitv_impl(structtypeelt=int64letvi=M.Bitv.v(Int64.to_stringi)64letbitwidth=64moduleIxx=Int64end)moduletypeFloat_sig=sigtypeeltvaleb:intvalsb:intvalv:elt->M.term(* TODO: *)(* val to_string : Z3.FuncDecl.func_decl *)(* val of_string : Z3.FuncDecl.func_decl *)endmoduleFloat_impl(F:Float_sig)=structopenMincludeFletunopope=matchopwith|Neg->Float.nege|Abs->Float.abse|Sqrt->Float.sqrt~rm:Float.Rounding_mode.rnee|Is_nan->Float.is_nane|Ceil->Float.round_to_integral~rm:Float.Rounding_mode.rtpe|Floor->Float.round_to_integral~rm:Float.Rounding_mode.rtne|Trunc->Float.round_to_integral~rm:Float.Rounding_mode.rtze|Nearest->Float.round_to_integral~rm:Float.Rounding_mode.rnee|_->err{|Fp: Unsupported Z3 unary operator "%a"|}Ty.pp_unopopletbinopope1e2=matchopwith|Add->Float.add~rm:Float.Rounding_mode.rnee1e2|Sub->Float.sub~rm:Float.Rounding_mode.rnee1e2|Mul->Float.mul~rm:Float.Rounding_mode.rnee1e2|Div->Float.div~rm:Float.Rounding_mode.rnee1e2|Min->Float.mine1e2|Max->Float.maxe1e2|Rem->Float.reme1e2|_->err{|Fp: Unsupported Z3 binop operator "%a"|}Ty.pp_binopoplettriopop_=err{|Fp: Unsupported Z3 triop operator "%a"|}Ty.pp_triopopletrelopope1e2=matchopwith|Eq->Float.eqe1e2|Ne->not_@@Float.eqe1e2|Lt->Float.lte1e2|Le->Float.lee1e2|Gt->Float.gte1e2|Ge->Float.gee1e2|_->err{|Fp: Unsupported Z3 relop operator "%a"|}Ty.pp_relopopletcvtopope=matchopwith|PromoteF32|DemoteF64->Float.to_fpebsb~rm:Float.Rounding_mode.rnee|ConvertSI32|ConvertSI64->Float.sbv_to_fpebsb~rm:Float.Rounding_mode.rnee|ConvertUI32|ConvertUI64->Float.ubv_to_fpebsb~rm:Float.Rounding_mode.rnee|Reinterpret_int->Float.of_ieee_bvebsbe|ToString->(* TODO: FuncDecl.apply to_string [ e ] *)assertfalse|OfString->(* TODO: FuncDecl.apply of_string [ e ] *)assertfalse|_->err{|Fp: Unsupported Z3 cvtop operator "%a"|}Ty.pp_cvtopopendmoduleFloat32_impl=Float_impl(structtypeelt=int32leteb=8letsb=24letvf=M.Float.v(Int32.float_of_bitsf)ebsb(* TODO: *)(* let to_string = *)(* Z3.FuncDecl.mk_func_decl_s ctx "F32ToString" [ fp32_sort ] str_sort *)(* let of_string = *)(* Z3.FuncDecl.mk_func_decl_s ctx "StringToF32" [ str_sort ] fp32_sort *)end)moduleFloat64_impl=Float_impl(structtypeelt=int64leteb=11letsb=53letvf=M.Float.v(Int64.float_of_bitsf)ebsb(* TODO: *)(* let to_string = *)(* Z3.FuncDecl.mk_func_decl_s ctx "F64ToString" [ fp64_sort ] str_sort *)(* let of_string = *)(* Z3.FuncDecl.mk_func_decl_s ctx "StringToF64" [ str_sort ] fp64_sort *)end)letv:Value.t->M.term=function|True->Bool_impl.true_|False->Bool_impl.false_|Intv->Int_impl.vv|Realv->Real_impl.vv|Strv->String_impl.vv|Num(I8x)->I8.vx|Num(I32x)->I32.vx|Num(I64x)->I64.vx|Num(F32x)->Float32_impl.vx|Num(F64x)->Float64_impl.vxletunop=function|Ty.Ty_int->Int_impl.unop|Ty.Ty_real->Real_impl.unop|Ty.Ty_bool->Bool_impl.unop|Ty.Ty_str->String_impl.unop|Ty.Ty_bitv8->I8.unop|Ty.Ty_bitv32->I32.unop|Ty.Ty_bitv64->I64.unop|Ty.Ty_fp32->Float32_impl.unop|Ty.Ty_fp64->Float64_impl.unop|Ty.Ty_bitv_|Ty_fp_|Ty_list|Ty_array|Ty_tuple->assertfalseletbinop=function|Ty.Ty_int->Int_impl.binop|Ty.Ty_real->Real_impl.binop|Ty.Ty_bool->Bool_impl.binop|Ty.Ty_str->String_impl.binop|Ty.Ty_bitv8->I8.binop|Ty.Ty_bitv32->I32.binop|Ty.Ty_bitv64->I64.binop|Ty.Ty_fp32->Float32_impl.binop|Ty.Ty_fp64->Float64_impl.binop|Ty.Ty_bitv_|Ty_fp_|Ty_list|Ty_array|Ty_tuple->assertfalselettriop=function|Ty.Ty_int|Ty.Ty_real->assertfalse|Ty.Ty_bool->Bool_impl.triop|Ty.Ty_str->String_impl.triop|Ty.Ty_bitv8->I8.triop|Ty.Ty_bitv32->I32.triop|Ty.Ty_bitv64->I64.triop|Ty.Ty_fp32->Float32_impl.triop|Ty.Ty_fp64->Float64_impl.triop|Ty.Ty_bitv_|Ty_fp_|Ty_list|Ty_array|Ty_tuple->assertfalseletrelop=function|Ty.Ty_int->Int_impl.relop|Ty.Ty_real->Real_impl.relop|Ty.Ty_bool->Bool_impl.relop|Ty.Ty_str->String_impl.relop|Ty.Ty_bitv8->I8.relop|Ty.Ty_bitv32->I32.relop|Ty.Ty_bitv64->I64.relop|Ty.Ty_fp32->Float32_impl.relop|Ty.Ty_fp64->Float64_impl.relop|Ty.Ty_bitv_|Ty_fp_|Ty_list|Ty_array|Ty_tuple->assertfalseletcvtop=function|Ty.Ty_int->Int_impl.cvtop|Ty.Ty_real->Real_impl.cvtop|Ty.Ty_bool->Bool_impl.cvtop|Ty.Ty_str->String_impl.cvtop|Ty.Ty_bitv8->I8.cvtop|Ty.Ty_bitv32->I32.cvtop|Ty.Ty_bitv64->I64.cvtop|Ty.Ty_fp32->Float32_impl.cvtop|Ty.Ty_fp64->Float64_impl.cvtop|Ty.Ty_bitv_|Ty_fp_|Ty_list|Ty_array|Ty_tuple->assertfalseletrecencode_exprsymbol_table(hte:Expr.t):M.term=matchExpr.viewhtewith|Valvalue->vvalue|Ptr(base,offset)->letbase'=v(Num(I32base))inletoffset'=encode_exprsymbol_tableoffsetinI32.binopAddbase'offset'|Symbolsym->make_symbolsymbol_tablesym|Unop(ty,op,e)->lete=encode_exprsymbol_tableeinunoptyope|Binop(ty,op,e1,e2)->lete1=encode_exprsymbol_tablee1inlete2=encode_exprsymbol_tablee2inbinoptyope1e2|Triop(ty,op,e1,e2,e3)->lete1=encode_exprsymbol_tablee1inlete2=encode_exprsymbol_tablee2inlete3=encode_exprsymbol_tablee3intrioptyope1e2e3|Relop(ty,op,e1,e2)->lete1=encode_exprsymbol_tablee1inlete2=encode_exprsymbol_tablee2inreloptyope1e2|Cvtop(ty,op,e)->lete=encode_exprsymbol_tableeincvtoptyope|Extract(e,h,l)->lete=encode_exprsymbol_tableeinM.Bitv.extracte~high:((h*8)-1)~low:(l*8)|Concat(e1,e2)->lete1=encode_exprsymbol_tablee1inlete2=encode_exprsymbol_tablee2inM.Bitv.concate1e2|List_|Array_|Tuple_|App_->assertfalse(* TODO: pp_smt *)letpp_smt?status:___=assertfalseletvalue_of_termmodeltyterm=letv=M.Model.eval~completion:truemodelterm|>Option.getinmatchtywith|Ty_int->Value.Int(M.Interp.to_intv)|Ty_real->Value.Real(M.Interp.to_realv)|Ty_bool->ifM.Interp.to_boolvthenValue.TrueelseValue.False|Ty_str->letstr=M.Interp.to_stringvinValue.Strstr|Ty_bitv8->leti8=M.Interp.to_bitvv8inValue.Num(I8(Int64.to_inti8))|Ty_bitv32->leti32=M.Interp.to_bitvv32inValue.Num(I32(Int64.to_int32i32))|Ty_bitv64->leti64=M.Interp.to_bitvv64inValue.Num(I64i64)|Ty_fp32->letfloat=M.Interp.to_floatv824inValue.Num(F32(Int32.bits_of_floatfloat))|Ty_fp64->letfloat=M.Interp.to_floatv1153inValue.Num(F64(Int64.bits_of_floatfloat))|Ty_bitv_|Ty_fp_|Ty_list|Ty_array|Ty_tuple->assertfalseletvalue({model=m;symbol_table}:model)(c:Expr.t):Value.t=value_of_termm(Expr.tyc)(encode_exprsymbol_tablec)letvalues_of_model?symbols({model;symbol_table}asmodel0)=letm=Hashtbl.create512in(matchsymbolswith|Somesymbols->List.iter(funsym->letv=valuemodel0(Expr.mk_symbolsym)inHashtbl.replacemsymv)symbols|None->Hashtbl.iter(fun(sym:Symbol.t)term->letv=value_of_termmodelsym.tyterminHashtbl.replacemsymv)symbol_table);mletset_debug_=()moduleSolver=structletmake?params?logic()={solver=M.Solver.make?params?logic();symbol_table=Hashtbl.create16}letclone{solver;symbol_table}={solver=M.Solver.clonesolver;symbol_table=Hashtbl.copysymbol_table}letpush{solver;_}=M.Solver.pushsolverletpop{solver;_}n=M.Solver.popsolvernletreset{solver;_}=M.Solver.resetsolverletadd{solver;symbol_table}(exprs:Expr.tlist)=M.Solver.addsolver(List.map(encode_exprsymbol_table)exprs)letcheck{solver;symbol_table}~assumptions=letassumptions=List.map(encode_exprsymbol_table)assumptionsinM.Solver.checksolver~assumptionsletmodel{solver;symbol_table}=M.Solver.modelsolver|>Option.map(funm->{model=m;symbol_table})letadd_simplifier{solver;symbol_table}={solver=M.Solver.add_simplifiersolver;symbol_table}letinterrupt_=M.Solver.interrupt()letpp_statisticsfmt{solver;_}=M.Solver.pp_statisticsfmtsolverendmoduleOptimizer=structletmake()={opt=M.Optimizer.make();symbol_table=Hashtbl.create16}letpush{opt;_}=M.Optimizer.pushoptletpop{opt;_}=M.Optimizer.popoptletadd{opt;symbol_table}exprs=M.Optimizer.addopt(List.map(encode_exprsymbol_table)exprs)letcheck{opt;_}=M.Optimizer.checkoptletmodel{opt;symbol_table}=M.Optimizer.modelopt|>Option.map(funm->{model=m;symbol_table})letmaximize{opt;symbol_table}(expr:Expr.t)=M.Optimizer.maximizeopt(encode_exprsymbol_tableexpr)letminimize{opt;symbol_table}(expr:Expr.t)=M.Optimizer.minimizeopt(encode_exprsymbol_tableexpr)letinterrupt_=M.Optimizer.interrupt()letpp_statisticsfmt{opt;_}=M.Optimizer.pp_statisticsfmtoptendendmoduleFresh=structmoduleMake()=Make_(M_with_make.Make())endletis_available=M_with_make.is_availableincludeMake_(M_with_make)end