123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openCil_typesopenLocations(* 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))letread_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_self.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_self.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))~exactstate(* ----- Conversion from cvalue --------------------------------------------- *)(* All conversion functions below return an error message in case of failure. *)type'aconversion=('a,string)Result.tleterrorformat=Format.kasprintfResult.errorformatletextract_definitionnamekf=ifKernel_function.has_definitionkfthenResult.Okkfelseerror"Missing definition for function %s"nameletextract_funvalue=matchfst(Location_Bytes.find_lonely_keyvalue)with|Base.Var(vi,_)whenGlobals.Functions.memvi->extract_definitionvi.vname(Globals.Functions.getvi)|_|exceptionNot_found->error"Expected pointer to function, received %a"Cvalue.V.prettyvalueletextract_pointervalue=matchLocation_Bytes.find_lonely_keyvaluewith|Base.Var(v,_),i|Base.Allocated(v,_,_),i->begintryResult.Ok(v,Integer.to_int_exn(Ival.project_inti))withIval.Not_Singleton_Int|Z.Overflow->error"Not a correct pointer, incorrect offset: %a"Ival.prettyiend|_|exceptionNot_found->error"Not a correct pointer '%a' (should be variable+offset)"Cvalue.V.prettyvalueletto_inti=tryResult.Ok(Integer.to_int_exni)withZ.Overflow->error"Overflow on integer %a"Integer.prettyiletextract_intvalue=tryCvalue.V.project_ivalvalue|>Ival.project_int|>to_intwithCvalue.V.Not_based_on_null|Ival.Not_Singleton_Int->error"Non-singleton integer value: %a"Cvalue.V.prettyvalueletextract_int_possibly_zerovalue=matchCvalue.V.project_ivalvalue|>Ival.project_small_setwith|Some[v]->to_intv|>Result.map(funv->v,`Exact)|Some[v1;v2]whenInteger.is_zerov1->to_intv2|>Result.map(funv->v,`WithZero)|Some[v1;v2]whenInteger.is_zerov2->to_intv1|>Result.map(funv->v,`WithZero)|Some_|None|exceptionCvalue.V.Not_based_on_null->error"Non-integer or imprecise value: %a"Cvalue.V.prettyvalueletextract_int_list~cardinalvalue=tryletival=Cvalue.V.project_ivalvalueinifIval.is_intival&&Ival.cardinal_is_less_thanivalcardinalthenIval.to_int_seqival|>List.of_seq|>List.mapInteger.to_int_exn|>Result.okelseerror"Imprecise value: %a"Ival.prettyivalwith|Cvalue.V.Not_based_on_null->error"Non-integer value: %a"Cvalue.V.prettyvalue|Z.Overflow->error"Overflow integer value: %a"Cvalue.V.prettyvalueletextract_constant_stringvalue=matchLocation_Bytes.fold_i(funbil->(b,i)::l)value[]with|[Base.Var(vi,_),i]whenIval.is_zeroi&&Ast_info.is_string_literalvi->letl=Globals.Vars.get_string_literalviin(matchlwith|Strs->Result.oks|Wstr_->error"Expected a string, not a wide string")|_|exceptionAbstract_interp.Error_Top->error"When decoding string, incorrect value '%a'"Cvalue.V.prettyvalue(* *)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_self.warning"Joining parameters lists of different lengths";(l,true)|x::xs,y::ys->letv,recv=join_valuexyandlv,recl=join_paramsxsysinv::lv,recv||reclletint_to_valuei=Cvalue.V.inject_ival(Ival.of_inti)