123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647(**************************************************************************)(* This file is part of BINSEC. *)(* *)(* Copyright (C) 2016-2024 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* 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, version 2.1. *)(* *)(* It 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. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file licenses/LGPLv2.1). *)(* *)(**************************************************************************)letsolvers=letopenFormula_optionsin[Bitwuzla;Boolector;Z3;CVC4;Yices]letmap=letopenFormula_optionsinletopenSmt_optionsinfunction|Auto|Bitwuzla_native->assertfalse|Bitwuzla_smtlib->Bitwuzla|Boolector_smtlib->Boolector|Z3_smtlib->Z3|CVC4_smtlib->CVC4|Yices_smtlib->Yicesletget_solver_factory()=letopenFormula_optionsinletopenSmt_optionsinmatchSmt_options.SMTSolver.get()with|(Smt_options.Auto|Smt_options.Bitwuzla_native)whenSmt_bitwuzla.available->Logger.debug"Use native Bitwuzla binding.";(moduleNative_solver.Solver:Solver_sig.FACTORY)|Auto->(tryletsolver=List.findProver.pingsolversinLogger.info"Found %a in the path."Prover.ppsolver;Solver.setsolver;(moduleSmt2_solver.Solver:Solver_sig.FACTORY)withNot_found->Logger.fatal"No SMT solver found.")|Bitwuzla_native->Logger.fatal"Native bitwuzla binding is required but not available."|solverwhenProver.ping(mapsolver)->Logger.debug"Found %a in the path."Prover.pp(mapsolver);Solver.set(mapsolver);(moduleSmt2_solver.Solver:Solver_sig.FACTORY)|solver->Logger.fatal"%a is required but not available in path."Prover.pp(mapsolver)exceptionUndef=Types.UndefexceptionUninterp=Types.UninterpexceptionUnknown=Types.UnknownexceptionNon_unique=Types.Non_uniqueexceptionNon_mergeable=Types.Non_mergeabletype'atest='aTypes.test=|Trueof'a|Falseof'a|Bothof{t:'a;f:'a}(* utils *)moduleBiMap=Basic_types.BigInt.MapmoduleNiTbl=Basic_types.Int.HtblopenSexprmoduleBiItM=ImapmoduleS=Basic_types.String.MapmoduleI=Basic_types.Int.MapmoduleR=Basic_types.Int.HtblmoduleK=Basic_types.Int.Settype_Types.value+=Term:Sexpr.Expr.tTypes.valuemoduleState(D:Domains.S)(F:Solver_sig.FACTORY)(QS:Types.QUERY_STATISTICS)=structmoduleUid=structtypet=Suid.tletzero=Suid.incrSuid.zero(* zero is reserved for initial memory *)letsucc=Suid.incrletcompare=Suid.compareendtypet={constraints:Expr.tlist;(* reversed sequence of assertions *)mutabledeps:BvSet.tBvMap.t;mutabledomains:D.tBvMap.t;mutableanchors:K.t;vsymbols:Expr.tI.t;(* collection of visible symbols *)varrays:Memory.tS.t;(* collection of visible arrays *)vmemory:Memory.t;(* visible memory *)ilocs:(Z.t*Loader_buf.t)BiItM.t;(* set of initialized memory locations *)alocs:(Z.t*char)listref;(* shared list of already accessed initialized memory locations *)model:Model.t;(* a model that satisfy constraints *)}moduleC:Ai.CONTEXTwithtypet=tandtypev:=D.t=structtypenonrect=tletadd_dependencyt~parente=t.deps<-BvMap.adde(BvSet.addparent(tryBvMap.findet.depswithNot_found->BvSet.empty))t.depsletfind_dependencyte=BvMap.findet.depsletaddtev=t.domains<-BvMap.addevt.domainsletfindte=BvMap.findet.domainsendmoduleOverapprox:Memory_manager.CONTEXTwithtypet=tandtypev:=D.t=structincludeAi.Make(D)(C)letanchort(m:Memory.t)=matchmwith|Root|Symbol_->()|Layer{id;_}->t.anchors<-K.addidt.anchorsletanchoredt(m:Memory.t)=matchmwith|Root|Symbol_->true|Layer{id;_}->K.memidt.anchorsendmoduleMMU=Memory_manager.Make(D)(Overapprox)letppppfstate=Model.ppppfstate.modelletempty()={constraints=[];deps=BvMap.empty;domains=BvMap.empty;anchors=K.empty;vsymbols=I.empty;varrays=S.empty;vmemory=Memory.root;ilocs=BiItM.empty;alocs=ref[];model=Model.empty(Kernel_options.Machine.word_size());}letalloc~arraystate=letsymbol=Memory.fresharrayin{statewithvarrays=S.addarraysymbolstate.varrays}letassign({id;_}:Types.Var.t)valuestate={statewithvsymbols=I.addidvaluestate.vsymbols}letwrite~addrvaluedirstate=letvmemory=MMU.writestate~addrvaluedirstate.vmemoryin{statewithvmemory}letstorename~addrvaluedirstate=tryletar=S.findnamestate.varraysinletvarrays=S.addname(MMU.writestate~addrvaluedirar)state.varraysin{statewithvarrays}withNot_found->raise_notrace(Uninterpname)letlookup({id;_}asvar:Types.Var.t)t=tryI.findidt.vsymbolswithNot_found->raise_notrace(Undefvar)letread~addrbytesdirstate=letbytes=MMU.readstate~addrbytesdirstate.vmemoryin(bytes,state)letselectname~addrbytesdirstate=tryletarray=S.findnamestate.varraysinletbytes=MMU.readstate~addrbytesdirarrayin(bytes,state)withNot_found->raise_notrace(Uninterpname)letmemcpy~addrlenorigstate=letbase=Bv.value_ofaddrinletilocs=BiItM.add~baselen(Bv.value_ofaddr,orig)state.ilocsinletvmemory=MMU.sourcestate~addr:(Expr.constantaddr)~lenorigstate.vmemoryin{statewithilocs;vmemory}moduleEngine(Solver:Solver_sig.S)=structtyperesult=Unsat|Satoftletextract_memorystate=matchSolver.get_arrayMemory.rootwith|(exceptionNot_found)|[||]->(BiTbl.create0,!(state.alocs))|assignment->letmemory=BiTbl.create(Array.lengthassignment)inletalocs=Array.fold_left(funalocs(addr,value)->matchBiItM.findaddrstate.ilocswith|exceptionNot_found->BiTbl.addmemoryaddrvalue;alocs|base,img->letoffset=Z.to_int(Z.subaddrbase)inletvalue'=Char.unsafe_chr(ifoffset<Bigarray.Array1.dimimgthenBigarray.Array1.getimgoffsetelse0)inifvalue<>value'then(addr,value')::alocselsealocs)!(state.alocs)assignmentin(memory,alocs)letextract_arrayname=matchSolver.get_arraynamewith|(exceptionNot_found)|[||]->BiTbl.create0|assignment->letarray=BiTbl.create(Array.lengthassignment)inArray.iter(fun(addr,value)->BiTbl.addarrayaddrvalue)assignment;arrayletextract_arrays()=letarrays=StTbl.create5inSolver.iter_free_arrays(funnamesymbol->StTbl.addarraysname(extract_arraysymbol));arraysletextract_vars()=letvars=StTbl.create8andvalues=BvTbl.create32inSolver.iter_free_variables(funnamebv->StTbl.addvarsnamebv;BvTbl.addvaluesbv(Bitvector.createSolver.(get_value(Solver.getbv))(Expr.sizeofbv)));(vars,values)letrecforce_lazy_initalocsstate=ifalocs==!(state.alocs)=falsethenmatchalocswith|[]->()|(addr,value)::alocs->Solver.set_memory~addr(Z.of_int(Char.codevalue));force_lazy_initalocsstateletenumerate=letreciterstateeexprsizenenum=ifn=0thenenumelsematchSolver.check_sat()with|Unknown->QS.Solver.incr_err();raiseUnknown|Unsat->QS.Solver.incr_unsat();enum|Sat->QS.Solver.incr_sat();letmemory,alocs=extract_memorystateinifalocs==!(state.alocs)=falsethen(force_lazy_initalocsstate;state.alocs:=alocs;iterstateeexprsizenenum)elseletx=Solver.get_valueexprinletb=Bv.createxsizeinletcond=Expr.equale(Expr.constantb)inletvars,values=extract_vars()inletstate'={statewithconstraints=cond::state.constraints;model=(vars,values,memory,extract_arrays(),Kernel_options.Machine.word_size());}inignore(Overapprox.evalstate'cond);Overapprox.refinestate'condD.one;Solver.neqexprx;iterstateeexprsize(n-1)((b,state')::enum)infune?(n=(1lslExpr.sizeofe)-1)?(except=[])state->letsize=Expr.sizeofeinletexpr=Solver.bindUid.zeroestate.constraintsinList.iter(fun(addr,value)->Solver.set_memory~addr(Z.of_int(Char.codevalue)))!(state.alocs);letd=Overapprox.evalstateeinmatchD.project~sizedwith|Pointz->letbv=Bv.createzsizeinifList.membvexceptthen[]else[(bv,state)]|Top|Seq_->letinit=letbv=Model.evalstate.modeleinifList.membvexceptthen[]else(QS.Preprocess.incr_const();Solver.neqexpr(Bitvector.value_ofbv);letcond=Expr.equale(Expr.constantbv)inletstate={statewithconstraints=cond::state.constraints}inignore(Overapprox.evalstatecond);Overapprox.refinestatecondD.one;[(bv,state)])inList.iter(funbv->Solver.neqexpr(Bitvector.value_ofbv))except;iterstateeexprsize(n-1)initletcheck_sat=letreccheck_sat_truestate=matchSolver.check_sat()with|Unknown->raiseUnknown|Unsat->Unsat|Sat->letmemory,alocs=extract_memorystateinifalocs==!(state.alocs)=falsethen(force_lazy_initalocsstate;state.alocs:=alocs;check_sat_truestate)elseletvars,values=extract_vars()inSat{statewithmodel=(vars,values,memory,extract_arrays(),Kernel_options.Machine.word_size());}infunstate->Solver.putUid.zerostate.constraints;List.iter(fun(addr,value)->Solver.set_memory~addr(Z.of_int(Char.codevalue)))!(state.alocs);check_sat_truestateletclose()=Solver.close()endletassumecondstate=ifExpr.is_equalcondExpr.onethen(QS.Preprocess.incr_true();Somestate)elseifExpr.is_equalcondExpr.zerothen(QS.Preprocess.incr_false();None)elseletd=Overapprox.evalstatecondinifD.included~size:1dD.zerothen(QS.Preprocess.incr_false();None)elseifD.included~size:1dD.onethen(QS.Preprocess.incr_true();Some{statewithconstraints=cond::state.constraints})elseletstate={statewithconstraints=cond::state.constraints}inifBitvector.zero=Model.evalstate.modelcondthen(QS.Solver.start_timer();letopenEngine(F())inletr=matchcheck_satstatewith|exceptionUnknown->QS.Solver.incr_err();raiseUnknown|Unsat->QS.Solver.incr_unsat();None|Satstate->QS.Solver.incr_sat();Overapprox.refinestatecondD.one;Somestateinclose();QS.Solver.stop_timer();r)else(QS.Preprocess.incr_true();Overapprox.refinestatecondD.one;Somestate)lettestcondstate=ifExpr.is_equalcondExpr.onethen(QS.Preprocess.incr_true();Truestate)elseifExpr.is_equalcondExpr.zerothen(QS.Preprocess.incr_false();Falsestate)elseletd=Overapprox.evalstatecondinifD.included~size:1dD.zerothen(QS.Preprocess.incr_false();Falsestate)elseifD.included~size:1dD.onethen(QS.Preprocess.incr_true();Truestate)elselett={statewithconstraints=cond::state.constraints}inletf={statewithconstraints=Expr.lognotcond::state.constraints}inlete=Model.evalstate.modelcondinlets=ifBv.is_zeroethen(Overapprox.refinefcondD.zero;t)else(Overapprox.refinetcondD.one;f)inQS.Solver.start_timer();letopenEngine(F())inletr=matchcheck_satswith|exceptionUnknown->QS.Solver.incr_err();raiseUnknown|Unsat->QS.Solver.incr_unsat();ifBv.is_zeroethenFalsefelseTruet|Satstate->QS.Solver.incr_sat();ifBv.is_zeroethen(Overapprox.refinestatecondD.one;Both{t=state;f})else(Overapprox.refinestatecondD.zero;Both{t;f=state})inclose();QS.Solver.stop_timer();rletenumerate=letwith_solvere?n?exceptstate=QS.Solver.start_timer();letopenEngine(F())inletr=enumeratee?n?exceptstateinclose();QS.Solver.stop_timer();rinfune?n?(except=[])state->match(e,n)with|Expr.Cstbv,_whenList.membvexcept=false->QS.Preprocess.incr_const();[(bv,state)]|Expr.Cst_,_->QS.Preprocess.incr_const();[]|_,Some1->letbv=Model.evalstate.modeleinifList.membvexceptthenwith_solvere?n~exceptstateelse(QS.Preprocess.incr_const();letcond=Expr.equale(Expr.constantbv)in[(bv,{statewithconstraints=cond::state.constraints(* TODO domains ?? *);});])|_,_->with_solvere?n~exceptstateletmerge~parenttt'=ift==t'thentelseift.ilocs==t'.ilocsthenmatch(t.constraints,t'.constraints)with|c::constraints,c'::constraints'whenconstraints==constraints'&&Expr.is_equalc(Expr.lognotc')->letdomains=parent.domainsandanchors=K.uniont.anchorst'.anchorsanddeps=BvMap.merge(fun_oo'->match(o,o')with|None,None->assertfalse|None,Some_->o'|Some_,None->o|Somed,Somed'->Some(BvSet.uniondd'))t.depst'.depsandvsymbols=ift.vsymbols==t'.vsymbolsthent.vsymbolselseI.merge(fun_o0o1->match(o0,o1)with|Somee0,Somee1->ifExpr.is_equale0e1theno0elseSome(Expr.itece0e1)|(Some_|None),(Some_|None)->raise_notraceNon_mergeable)t.vsymbolst'.vsymbolsandvarrays=ift.varrays==t'.varraysthent.varrayselseS.merge(fun_o0o1->match(o0,o1)with|Somea0,Somea1->Some(MMU.mergeparentca0a1)|(Some_|None),(Some_|None)->raise_notraceNon_mergeable)t.varrayst'.varraysandvmemory=MMU.mergeparentct.vmemoryt'.vmemoryandilocs=t.ilocsandalocs=t.alocsandmodel=t.modelin{constraints;deps;domains;anchors;vsymbols;varrays;vmemory;ilocs;alocs;model;}|_->raise_notraceNon_mergeableelseraise_notraceNon_mergeablemoduleValue=structtypet=Expr.tletkind=Termletconstant=Expr.constantletvaridnamesize=Expr.var(name^Suid.to_stringid)sizenameletunary=Expr.unaryletbinary=Expr.binaryletite=Expr.iteendletassertionst=t.constraintsletget_value(e:Expr.t)_=matchewithCstbv->bv|_->raise_notraceNon_uniqueletget_a_value(e:Expr.t)t=Model.evalt.modeleletpp_smt(target:Expr.tTypes.target)ppft=letmoduleP=Smt2_solver.Printerinletctx=P.create~next_id:Uid.zero()in(* visit assertions *)List.iter(P.visit_blctx)t.constraints;(* visit terms *)letdefs=matchtargetwith|Somedefs->List.iter(fun(e,_)->P.visit_bvctxe)defs;defs|None->P.visit_axctxt.vmemory;List.rev(I.fold(funidexprdefs->matchDba.Var.from_ididwith|exceptionNot_found->defs|{name;_}->P.visit_bvctxexpr;(expr,name)::defs)t.vsymbols[])inFormat.pp_open_vboxppf0;(* print declarations *)P.pp_print_declsppfctx;(* print definitions *)P.pp_print_defsppfctx;List.iter(fun(bv,name)->Format.fprintfppf"@[<h>(define-fun %s () (_ BitVec %d)@ "name(Expr.sizeofbv);P.pp_print_bvctxppfbv;Format.fprintfppf")@]@ ")defs;iftarget=NonethenFormat.fprintfppf"@[<h>(define-fun memory () (Array (_ BitVec %d) (_ BitVec 8))@ %a)@]"(Kernel_options.Machine.word_size())(P.pp_print_axctx)t.vmemory;(* print assertions *)List.iter(funbl->Format.pp_open_hboxppf();Format.pp_print_stringppf"(assert ";P.pp_print_blctxppfbl;Format.pp_print_charppf')';Format.pp_close_boxppf();Format.pp_print_spaceppf())t.constraints;Format.pp_close_boxppf()letto_formulat=letmoduleC=Smt2_solver.Crossinletctx=C.create~next_id:Uid.zero()inList.iter(C.assert_blctx)t.constraints;C.define_axctx"memory"t.vmemory;I.iter(funidexpr->C.define_bvctx(Dba.Var.from_idid).nameexpr)t.vsymbols;C.to_formulactxletdowncast_=NoneendtypeOptions.Engine.t+=Vanillalet()=Options.Engine.register"vanilla"Vanilla(fun()->(moduleState(Domains.Interval)((valget_solver_factory()))))