123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203(**************************************************************************)(* *)(* 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). *)(* *)(**************************************************************************)openCil_typesopenCil_datatypemoduleOptions=Reduc_optionsexceptionAlarm_reachedletdkey=Options.register_category"collect"letdebug=Options.debug~dkeytype'aalarm_component=Emitter.t->kernel_function->stmt->rank:int->Alarms.alarm->code_annotation->'a->'atypeannoth=AnnotAll|AnnotInouttypeenv={rel_annoth:annoth;rel_stmts:Stmt.Set.t;rel_vars:LvalStructEq.Set.tStmt.Map.t;}letempty_envannoth={rel_annoth=annoth;rel_stmts=Stmt.Set.empty;rel_vars=Stmt.Map.empty;}letenv_with_stmtenvstmt={envwithrel_stmts=Stmt.Set.addstmtenv.rel_stmts}letenv_with_stmt_varsenvstmtlvs=letvars=tryStmt.Map.findstmtenv.rel_varswithNot_found->LvalStructEq.Set.emptyinletnew_vars=LvalStructEq.Set.(unionvars(of_listlvs))in{envwithrel_vars=Stmt.Map.addstmtnew_varsenv.rel_vars}(* ************************************************************************ *)(** Alarms to relevant locations *)(* ************************************************************************ *)classstmts_vis(alarm_stmt:stmt)(env:envref)=object(_)inheritCil.nopCilVisitormethod!vstmtstmt=env:=env_with_stmt!envstmt;ifStmt.equalstmtalarm_stmtthenbeginraiseAlarm_reachedend;Cil.DoChildrenendletreccollect_offtyp=matchtypwith|TInt_|TFloat_->[NoOffset]|TComp({cfields=Someflds},_)->List.fold_leftcollect_fields[]flds|TArray(arrtyp,e_opt,_)->debug"Array of length %a"(Pretty_utils.pp_optPrinter.pp_exp)e_opt;begintrycollect_arrayarrtyp[](Cil.lenOfArray64e_opt)withCil.LenOfArray_->[]end|TVoid_|TFun_|TPtr_|TEnum_|TNamed_|TBuiltin_va_list_|TComp({cfields=None},_)->[]andcollect_fieldsaccfld=letoffs=collect_offfld.ftypeinList.map(funoff->Field(fld,off))offs@accandcollect_arraytypacc=function|xwhenInteger.is_zerox->acc|x->letoffs=collect_offtypinletexp=Cil.kinteger64~loc:Location.unknownxinletacc'=acc@List.map(funoff->Index(exp,off))offsincollect_arraytypacc'(Integer.addxInteger.minus_one)letcollect_varinfoaccx=letoffs=collect_offx.vtypeinList.map(funoff->(Varx,off))offs@accclassinout_vis(alarm_stmt:stmt)(kf:Kernel_function.t)(env:envref)=object(self)inheritstmts_visalarm_stmtenvassupervalmutablevars=[]method!vfunc_=vars<-Kernel_function.((get_localskf)@(get_formalskf));Cil.DoChildrenmethodprivateis_first_stmtstmt=tryStmt.equalstmt(Kernel_function.find_first_stmtkf)withKernel_function.No_Statement->assertfalsemethod!vstmtstmt=letout=!Db.Outputs.statementstmtinletfilter_outvi=letopenLocationsinletzone=enumerate_bits(loc_of_varinfovi)inZone.intersectsoutzoneinleteffect=ifself#is_first_stmtstmtthenvarselseList.filterfilter_outvarsinletvars=List.fold_leftcollect_varinfo[]effectinenv:=env_with_stmt_vars!envstmtvars;super#vstmtstmtendletget_relevant_stmtskfstmtenv=letdo_visitref_env=match!ref_env.rel_annothwith|AnnotAll->Cil.visitCilFunction(newstmts_visstmtref_env)|AnnotInout->Cil.visitCilFunction(newinout_visstmtkfref_env:>Cil.cilVisitor)inletrenv=refenvintryletfundec=Kernel_function.get_definitionkfinignore(do_visitrenvfundec);!renvwithAlarm_reached->!renvletget_relevant_emitkfstmt~rank:__a_annotenv=get_relevant_stmtskfstmtenvletshould_annotate_stmtenvstmt=Stmt.Set.memstmtenv.rel_stmts(* ************************************************************************ *)(** Relevant locations to relevant variables *)(* ************************************************************************ *)classrelevant_stmt_vars_visitor(vars:LvalStructEq.Set.tref)=object(_)inheritCil.nopCilVisitormethod!vstmtstmt=matchstmt.skindwith|Goto_|UnspecifiedSequence_->Cil.SkipChildren|_->Cil.DoChildrenmethod!vblock_=Cil.SkipChildrenmethod!vexpre=beginmatche.enodewith|Lvallv|AddrOflv|StartOflv->vars:=LvalStructEq.Set.addlv!vars|_->()end;Cil.DoChildrenendletget_relevant_all_vars_stmtkfstmt=letdo_visitref_vars=Cil.visitCilStmt(newrelevant_stmt_vars_visitorref_vars)inletref_vars=refLvalStructEq.Set.emptyinignore(do_visitref_varsstmt);letlocals=Kernel_function.get_localskfinletformals=Kernel_function.get_formalskfinletvars=List.mapCil.var(locals@formals)invars@LvalStructEq.Set.elements!ref_varsletget_relevant_inout_vars_stmtenvstmt=tryletvars=Stmt.Map.findstmtenv.rel_varsinLvalStructEq.Set.elementsvarswithNot_found->assertfalseletget_relevant_vars_stmtenvkfstmt=matchenv.rel_annothwith|AnnotAll->get_relevant_all_vars_stmtkfstmt|AnnotInout->get_relevant_inout_vars_stmtenvstmt