123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-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 licenses/LGPLv2.1). *)(* *)(**************************************************************************)openCil_typesopenCilopenLocations(* Must be used inlined, as Machine.theMachine is mutable
let pointer_size_bytes = Machine.sizeof_ptr ()
let int_size_bytes = Machine.sizeof_int ()
*)letsize_char_in_bits=8moduleTypes=structtypestate=Cvalue.Model.ttypevalue=Cvalue.V.ttypezone=Zone.ttypeslice=Cvalue.V_Offsetmap.ttypefunctions_states=stateCil_datatype.Stmt.Hashtbl.ttypemap_functions_states=stateCil_datatype.Stmt.Map.ttypestate_accesser=|Global|Localoffunctions_statesletmap_functions_states_to_get_statem=funs->tryCil_datatype.Stmt.Map.findsmwithNot_found->Cvalue.Model.bottomletfunctions_states_to_requesthstmt=letstate=tryCil_datatype.Stmt.Hashtbl.findhstmtwithNot_found->Cvalue.Model.bottominResults.in_cvalue_statestateletiter_requests=function|Global->funstmtf->letrequests=Results.(beforestmt|>by_callstack|>List.mapsnd)inList.iter(funrequest->frequest)requests|Localhs->funstmtf->f(functions_states_to_requesthsstmt)letmerge_map_non_map_functions_statesmaph=Cil_datatype.Stmt.Hashtbl.fold(funstmtstatem->letprevious=tryCil_datatype.Stmt.Map.findstmtmwithNot_found->Cvalue.Model.bottominletjoin=Cvalue.Model.joinpreviousstateinifjoin!=previousthenCil_datatype.Stmt.Map.addstmtjoinmelsem)hmapletmerge_map_functions_states=Cil_datatype.Stmt.Map.merge(Extlib.merge_opt(fun_->Cvalue.Model.join))(* -------------------------------------------------------------------------- *)(* --- Ids --- *)(* -------------------------------------------------------------------------- *)typepointer=Cil_types.varinfo*intmodulePointer=structincludeDatatype.Pair_with_collections(Cil_datatype.Varinfo)(Datatype.Int)letprettyfmt((v,o):pointer)=ifo=0thenFormat.fprintffmt"&%a"Printer.pp_varinfovelseFormat.fprintffmt"&%a+%d"Printer.pp_varinfovoendendlettyp_array_char=Cil_const.(mk_tarrayucharTypeNone)letpretty_slicefmts=Cvalue.V_Offsetmap.pretty_generic~typ:typ_array_char()fmtsletlocation_with_size_auxpsbytes=Locations.loc_bytes_to_loc_bitsp,Abstract_interp.Int.of_int(size_char_in_bits*sbytes)letlocation_with_sizepsbytes=letlocb,size=location_with_size_auxpsbytesinLocations.make_loclocb(Int_Base.injectsize)letlocation_of_pointer(p:Types.pointer)=Location_Bytes.inject(Base.of_varinfo(fstp))(Ival.of_int(sndp))letlval_from_pointer(v,offs):lval=letloc=v.vdeclinletexp_var=mkAddrOrStartOf~loc(varv)inletexp_offs=Cil.new_exp~loc(Const(CInt64(Integer.of_intoffs,IInt,None)))inletexp'=new_exp~loc(BinOp(PlusPI,exp_var,exp_offs,Cil_const.intPtrType))inletlval=mkMem~addr:exp'~off:NoOffsetinlvalletread_int_pointerpstate=letp=location_of_pointerpinletp=location_with_sizep(Machine.sizeof_int())inCvalue.Model.findstatep(* TODO: restore warnings *)letread_slice~p~sbytesstate=letloc_bits,size=location_with_size_auxpsbytesinmatchCvalue.Model.copy_offsetmaploc_bitssizestatewith|`Bottom->assert(Cvalue.Model.equalstateCvalue.Model.bottom);Mt_options.fatal"Reading inside bottom state"|`Valueoffs->offsletwrite_int_pointerpistate=letsbytes=Machine.sizeof_int()andvalue=Location_Bytes.injectBase.null(Ival.of_inti)inletpointer=location_of_pointerpinletp=location_with_sizepointersbytesinMt_options.debug~level:3"# Write %a at %a, size %d bytes"Cvalue.V.prettyvalueLocations.prettypsbytes;Cvalue.Model.add_binding~exact:truestatepvalueletreplace_value_at_int_pointerp~before~afterstate=letsbytes=Machine.sizeof_int()inletvalue_after=Location_Bytes.injectBase.null(Ival.of_intafter)inletvalue_before=Location_Bytes.injectBase.null(Ival.of_intbefore)inletpointer=location_of_pointerpinletp=location_with_sizepointersbytesinletcur=Cvalue.Model.find~conflate_bottom:truestatepinifLocation_Bytes.equalcurvalue_beforethenCvalue.Model.add_binding~exact:truestatepvalue_afterelseifLocation_Bytes.is_includedvalue_beforecurthenletv=Cvalue.V.(join(diff_if_onecurvalue_before)value_after)inCvalue.Model.add_binding~exact:truestatepvelsestateletwrite_slice~p~sbytes~slice~exactstate=letpointer=Locations.loc_bytes_to_loc_bits(location_of_pointerp)inCvalue.Model.paste_offsetmap~from:slice~dst_loc:pointer~size:(Abstract_interp.Int.of_int(sbytes*size_char_in_bits))~exactstateletextract_funvalue=tryletb,_=Location_Bytes.find_lonely_keyvaluein(matchbwith|Base.Var(v,_)->(tryletf=Globals.Functions.getvin(matchf.fundecwith|Definition(_,_)->`Successf|Declaration(_,f,_,_)->`Failure(funfmt->Format.fprintffmt"Missing@ definition@ for function@ '%s'."f.vname))withNot_found->`Failure(funfmt->Format.fprintffmt"Expected@ pointer to@ function,@ received@ \
non-function@ value %a."Base.prettyb))|_->raiseNot_found)withNot_found->(* find_loneley_key + above *)`Failure(funfmt->Format.fprintffmt"Expected@ pointer@ to function,@ received %a."Cvalue.V.prettyvalue)letextract_pointervalue=tryletb,i=Location_Bytes.find_lonely_keyvaluein(matchbwith|Base.Var(v,_)|Base.Allocated(v,_,_)->(try`Success(v,Abstract_interp.Int.to_int_exn(Ival.project_inti))withIval.Not_Singleton_Int->`Failure(funfmt->Format.fprintffmt"Not@ a@ correct@ \
pointer@, incorrect@ offset: %a"Ival.prettyi))|_->raiseNot_found)withNot_found->(* find_loneley_key + above *)`Failure(funfmt->Format.fprintffmt"Not@ a@ correct@ \
pointer '%a'@ (should be@ variable+offset)"Cvalue.V.prettyvalue)letextract_intvalue=tryletb,i=Location_Bytes.find_lonely_keyvaluein(matchbwith|Base.Null->(try`Success(Abstract_interp.Int.to_int_exn(Ival.project_inti))withIval.Not_Singleton_Int->`Failure(funfmt->Format.fprintffmt"Non-integer value: %a"Ival.prettyi))|_->raiseNot_found)withNot_found->(* find_loneley_key + above *)`Failure(funfmt->Format.fprintffmt"Non-integer value: %a"Cvalue.V.prettyvalue)letextract_int_possibly_zerovalue=tryletb,i=Location_Bytes.find_lonely_keyvaluein(matchbwith|Base.Null->letfail=`Failure(funfmt->Format.fprintffmt"Non-integer value: %a"Ival.prettyi)in(tryignore(Ival.cardinal_less_thani3);(matchIval.fold_int(funil->i::l)i[]with|[v]->`Success(Abstract_interp.Int.to_int_exnv,`Exact)|[v1;v2]->(* Sorted in reverse direction *)letv1=Abstract_interp.Int.to_int_exnv1inletv2=Abstract_interp.Int.to_int_exnv2inifv2=0then`Success(v1,`WithZero)elsefail|[]|_::_::_::_->fail)withAbstract_interp.Error_Top|Abstract_interp.Not_less_than->fail)|_->raiseNot_found)withNot_found->(* find_loneley_key + above *)`Failure(funfmt->Format.fprintffmt"Non-integer value: %a"Cvalue.V.prettyvalue)letextract_non_wide_stringcstr=matchcstrwith|Base.CSStrings->`Successs|Base.CSWstrings->`Failure(funfmt->Format.fprintffmt"Wide string not supported (string@ '%s')"(Escape.escape_wstrings))letextract_constant_stringvalue=trymatchLocation_Bytes.fold_i(funbil->(b,i)::l)value[]with|[Base.String(_,e),i]whenIval.is_zeroi->extract_non_wide_stringe|_->`Failure(funfmt->Format.fprintffmt"When decoding string, incorrect value@ '%a'"Cvalue.V.prettyvalue)withe->`Failure(funfmt->Format.fprintffmt"Not a correct string '%a'@. \
Conversion raised %s"Cvalue.V.prettyvalue(Printexc.to_stringe))(* *)letclear_non_globals=Cvalue.Model.filter_base(funv->not(Base.is_any_formal_or_localv))(* *)letjoin_states1s2=letr=Cvalue.Model.joins2s1inr,Cvalue.Model.equalrs1=falseletjoin_valuev1v2=letr=Cvalue.V.joinv1v2inr,Cvalue.V.equalrv1=falseletrecjoin_paramsl1l2=matchl1,l2with|[],[]->([],false)|[],l|l,[]->Mt_options.warning"Joining parameters lists of different lengths";(l,true)|x::xs,y::ys->letv,recv=join_valuexyandlv,recl=join_paramsxsysinv::lv,recv||reclletjoin_zonez1z2=letr=Zone.joinz1z2inr,Zone.equalrz1=false(* *)letis_frama_c_varv=String.starts_with~prefix:"__FRAMAC_MTHREAD"v.vnameletis_frama_c_base=function|Base.Var(v,_)|Base.Allocated(v,_,_)->is_frama_c_varv|_->falseletremove_frama_c_var_from_zone=Zone.filter_base(funb->not(is_frama_c_baseb))letremove_frama_c_var_from_mem=Cvalue.Model.filter_base(funb->not(is_frama_c_baseb))letint_to_valuei=Cvalue.V.inject_ival(Ival.of_inti)