123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* 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 LICENSE). *)(* *)(**************************************************************************)(* Note: the idea here is that we put the wraps and wrapu lazily. Only
when some operations require a pre-wrap, like division and
comparison (all the signed operations). addition, subtraction,
maybe multiply do not.
*)(* TODO: A version where we add wraps and wrapu operations
manually. And somewhere (in the term domain?) remove those for
which we prove that no wrapping occurs. *)typesize=intmoduleMake(I:Sig.BASE_WITH_INTEGER):Sig.BASE_WITH_INTEGERwithtypebinary=I.integerandtypeboolean=I.booleanandtypeinteger=I.integerandmoduleContext=I.ContextandmoduleInteger_Query=I.Integer_Query(* and module Query.Binary_Lattice = I.Query.Integer_Lattice *)=structletname()="Lift_integer_domain_to_binary_domain("^(I.name())^")";;letunique_id()=Sig.Fresh_id.fresh@@name();;(* open Term_types *)moduleTypes=structtypeinteger=I.integertypebinary=I.integertypeboolean=I.booleantypeenum=I.enumendincludeTypesmoduleContext=I.Context(*open Context*)(* include Operator.Builtin.Make(Types)(Context) *)letmu_context_open=I.mu_context_openlettyped_nondet2=I.typed_nondet2letnondet_same_context=I.nondet_same_contextletroot_context=I.root_contextletcontext_pretty=I.context_prettyletserialize_integer=I.serialize_integerletserialize_boolean=I.serialize_booleanletserialize_enum=I.serialize_enumletserialize_binary~widens~size=I.serialize_integer~widens(* let serialize_binary ~widens ~size ctxa a ctxb b acc = *)(* let Result(included,acc,d) = I.serialize_integer ~widens ctxa a ctxb b acc in *)(* Result(included,acc,fun ctx tup -> let res,tup = d ctx tup in res,tup) *)(* ;; *)lettyped_fixpoint_step=I.typed_fixpoint_stepletwidened_fixpoint_step=I.widened_fixpoint_stepletassume=I.assumemoduleBoolean_Forward=I.Boolean_ForwardmoduleInteger_Forward=I.Integer_ForwardmoduleEnum_Forward=I.Enum_Forward(* Note: if we have nowrap signs, we want to put an alarm instead of wrapping. *)letwraps~sizectxx=assertfalse;;letwrapu~sizectxx=assertfalse;;(* TODO: this model assumes that no overflow occurs (this should be
checked separately), and that bitvectors are not re-interpreted
(e.g. memcopying a signed int to an int). Thus we should add
checks (i.e. ACSL terms) that the input of signed operands
(e.g. division) is within the correct range.
To see where to put wrapping operations, see e.g. Jacques-Henri
Jourdan PhD thesis. *)moduleBinary_Forward=structmoduleIF=Integer_Forwardletpred2f=fun~sizectxab->fctxab;;letop2f=fun~sizectxab->(* Codex_log.feedback "size %d size1 %d size2 %d" size size1 size2; *)fctxab;;letop2_flagsf=fun~size~flagsctxab->(* Codex_log.feedback "size %d size1 %d size2 %d" size size1 size2; *)fctxab;;letop2_all_flagsf=fun~size~nsw~nuw~nuswctxab->(* Codex_log.feedback "size %d size1 %d size2 %d" size size1 size2; *)fctxab;;(* XXX: Commencer par ici. les comparaisons doivent introduire des modulos, ca depend de la taille. *)(* Pour beq, on a le choix. Regardons les intervalles des arguments, et faisons au mieux pour savoir comment wrapper. Notons que si les intervalles sont complètement disjoints, on peut parfois faire juste une soustraction. *)(* On peut aussi faire un case split: soit on est égal et on est sur l'intervalle signé, soit on est égal et on est sur l'intervalle non-signé. Pas forcément le plus arrangeant. *)letbeq=pred2IF.ieqletbiule=pred2IF.ileletbisle=pred2IF.ileletbiadd=op2_flagsIF.iaddletbisub=op2_flagsIF.isubletbimul=op2_flagsIF.imulletbxor=op2IF.ixorletband=op2IF.iandletbor=op2IF.ior(* TODO: maybe we need to wrap here. e.g. bsext is a noop only if
the old value is wrapped, and likewise for buext. But, if
oldsize == size, we don't need to wrap. *)letbsext~size~oldsizectxx=if(size==oldsize)thenxelsex(* assert false *)letbuext~size~oldsizectxx=if(size==oldsize)thenxelsex(* assert false *)letbofbool~size_=assertfalseletbchoose~sizecond_=assertfalseletbashr=op2IF.ishrletblshr=op2IF.ishrletbshl=op2_flagsIF.ishlletbisdiv=op2IF.idivletbiudiv=op2IF.idivopenUnitsletbconcat~(size1:In_bits.t)~(size2:In_bits.t)ctxab=letresult=IF.iaddctxb@@IF.itimes(Z.shift_leftZ.one(size2:>int))ctxainresultletbismod=op2IF.imodletbiumod~sizectxab=leta=wrapu~sizectxainletb=wrapu~sizectxbinop2IF.imod~sizectxabletbextract~(size:In_bits.t)~(index:In_bits.t)~(oldsize:In_bits.t)ctxb=(* Codex_log.feedback "lift_integer.bextract oldsize %d index %d size %d sizeb %d\n" oldsize index size sizeb; *)assertIn_bits.(index+size<=oldsize);(* assert(size < 64); *)(* Fast path *)ifsize==oldsizethen(assert(index==In_bits.zero);b)elseletdiv=(* We use shr instead of division because:
- This avoids having too large number (when extracting parts of a big array)
- We need euclidian division, not truncated div. *)ifindex==In_bits.zerothenbelseIF.ishrctxb(IF.iconst(Z.of_int(index:>int))ctx)in(* XXX: Should be euclidian modulo, not truncated one. *)letmodu=ifIn_bits.(size+index==oldsize)thendivelse(* XXX: iand renvoie aussi un resultat positif, donc ne convient pas.
* MAYBE: do a bextract on integers? *)(* IF.iand ctx div (IF.iconst (Z.pred @@ Z.shift_left Z.one size) ctx) *)IF.imodctxdiv(IF.iconst(Z.shift_leftZ.one(size:>int))ctx)inmodu;;letbiconst~sizekctx=(* Kernel.feedback "biconst size %d" size; *)(IF.iconstkctx)(* TODO: The address-specific transfer functions should all be
handled by the enclosing domain. And we should be able to
write assert false for them here.
TODO: We should have a world parameter for boolean unknowns
too, that we would use here.
*)letbuninit~size=assertfalse(* MAYBE: empty? *)letvalid~size:__acc_typ_ctx_v=assertfalse(* boolean_unknown? *)(* IF.ieq ctx (IF.iunknown () ctx) (IF.zero ctx) *)letvalid_ptr_arith~size:__=assertfalseletbshift~size~offset~max_=assertfalseletbindex~size_=assertfalseendletbinary_pretty~sizectxfmti=I.integer_prettyctxfmtiletbinary_is_empty~sizectxi=I.integer_is_emptyctxilet_binary_pretty~sizectxfmt(i,_size)=Format.fprintffmt"{size:%d;contents:%a}"_size(I.integer_prettyctx)i;;letinteger_is_empty=I.integer_is_emptyletinteger_pretty=I.integer_prettyletboolean_pretty=I.boolean_pretty(* let boolean_is_empty = I.boolean_is_empty *)letenum_pretty=I.enum_prettyletassume_binary~sizectxcond(x,sizex)=(* Codex_log.feedback "size %d sizex %d" size sizex; *)assert(size==sizex);assertfalse;;(* (I.assume_integer ctx cond x, size) *)moduleBinary=I.IntegermoduleInteger=I.IntegermoduleBoolean=I.BooleanmoduleEnum=I.EnummoduleQuery=structinclude(I.Query:(moduletypeofI.QuerywithmoduleBinary_Lattice:=I.Query.Binary_Lattice))moduleBinary_Lattice=Lattices.Bitvector_Of_Integer.Make(I.Integer_Query.Integer_Lattice)letbinary_fold_crop~sizebin~inf~supaccf=I.Integer_Query.Integer_Lattice.fold_cropbin~inf~supfacc(* The fact that we know something about the binary does not mean
that we know something about the integer. For instance, &a[0]
!= &b[0] does not imply that 0 != 0. When correct, it is still
possible to call directly I.Query.inject_boolean. *)letbinary~sizectxid=I.Integer_Query.queryctxidendmoduleInteger_Query=I.Integer_Queryletsatisfiablectxboolean=I.satisfiablectxbooleanletbinary_empty~size=I.integer_emptyletinteger_empty=I.integer_emptyletboolean_empty=I.boolean_emptyletenum_empty=I.enum_emptyletbinary_unknown~sizectx=I.integer_unknownctxletinteger_unknown=I.integer_unknownletboolean_unknown=I.boolean_unknownletenum_unknown=I.enum_unknownletunion=I.unionletbinary_unknown_typed~size:__=assertfalseletquery_boolean=I.query_booleanend