123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* 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). *)(* *)(**************************************************************************)(** Find the statements that writes a given zone. This is a lightweight version
of module [Scope.Defs]. Instead of using PDGs (that may be very costly to
compute), we only use Inout. This also means that we can find effects
*after* the stmt the user has chosen. *)openCil_typesopenLocationstypet=|AssignofCil_types.stmt|CallDirectofCil_types.stmt|CallIndirectofCil_types.stmt|GlobalInitofCil_types.varinfo*Cil_types.initinfo|FormalInitofCil_types.varinfo*(Cil_types.kernel_function*Cil_types.stmtlist)listlet(<?>)clcmp=ifc<>0thencelseLazy.forcelcmpletcomparew1w2=letopenCil_datatypeinmatchw1,w2with|Assigns1,Assigns2|CallDirects1,CallDirects2|CallIndirects1,CallIndirects2->Stmt.compares1s2|GlobalInit(v1,i1),GlobalInit(v2,i2)->Varinfo.comparev1v2<?>lazy(Initinfo.comparei1i2)|FormalInit(v1,cs1),FormalInit(v2,cs2)->letcompare_callsites(kf1,stmts1)(kf2,stmts2)=Kf.comparekf1kf2<?>lazy(List.compareStmt.comparestmts1stmts2)inVarinfo.comparev1v2<?>lazy(List.comparecompare_callsitescs1cs2)|Assign_,_->1|_,Assign_->-1|CallDirect_,_->1|_,CallDirect_->-1|CallIndirect_,_->1|_,CallIndirect_->-1|GlobalInit_,_->1|_,GlobalInit_->-1(** Does the functions called at [stmt] modify directly or indirectly [zlval] *)leteffects_of_callstmtzlvaleffects=letaux_kf(direct,indirect)kf=letinout=!Db.Operational_inputs.get_internal_precise~stmtkfinletout=inout.Inout_type.over_outputsinifZone.intersectsoutzlvalthenifEva.Analysis.use_spec_instead_of_definitionkfthen(true,indirect)(* Direct effect: there is no body for this funtion. *)else(direct,true)(* Indirect effect *)else(direct,indirect)inletkfs=Eva.Results.calleestmtinList.fold_leftaux_kfeffectskfsclassfind_write_instszlval=object(self)inheritVisitor.frama_c_inplacevalmutableres:tlist=[]method!vinsti=letstmt=Option.getself#current_stmtinbeginletaux_calllvopt_kf_args_loc=(* Direct effect through the writing of [lvopt], or indirect inside
the call. *)letz=!Db.Outputs.statementstmtinifZone.intersectszzlvalthenletdirect=matchlvoptwith|None->false|Somelv->Eva.Results.(beforestmt|>eval_addresslv|>as_zone_result)|>Result.fold~ok:(Zone.intersectszlval)~error:(fun_->false)inletdirect,indirect=effects_of_callstmtzlval(direct,false)inifdirectthenres<-CallDirectstmt::res;ifindirectthenres<-CallIndirectstmt::res;inmatchiwith|Set_|Local_init(_,AssignInit_,_)->(* Effect only throuh the written l-value *)letz=!Db.Outputs.statementstmtinifZone.intersectszzlvalthenbeginres<-Assignstmt::resend|Call(lvopt,f,args,loc)->aux_calllvoptfargsloc|Local_init(v,ConsInit(f,args,k),l)->Cil.treat_constructor_as_funcaux_callvfargskl|_->()(* No effect *)end;Cil.SkipChildrenmethodresult=resendletinst_writesz=letvis=newfind_write_instszinletaux_kf_fundeckf=letall_out=!Db.Operational_inputs.get_internal_precisekfinletzout=all_out.Inout_type.over_outputsinifZone.intersectszoutzthenbeginletfundec=Kernel_function.get_definitionkfinignore(Visitor.visitFramacFunction(vis:>Visitor.frama_c_visitor)fundec;)endinletaux_kfkf=ifKernel_function.is_definitionkfthenaux_kf_fundeckfinGlobals.Functions.iteraux_kf;vis#resultletbase_initsbaseacc=matchBase.to_varinfobasewith|exceptionBase.Not_a_C_variable->acc|viwhenvi.vglob->letinitinfo=Globals.Vars.findviinGlobalInit(vi,initinfo)::acc|viwhenvi.vformal->letkf=Option.get(Kernel_function.find_defining_kfvi)inletcallsites=Eva.Results.callsiteskfinFormalInit(vi,callsites)::acc|_->acc(* Local init will be found by [inst_writes] *)letcomputez=inst_writesz@Zone.fold_basesbase_initsz[]