123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openCil_typesopenCil_datatypemoduleDataflow=Dataflow2moduletypeTable=sigtypekeytypevaluevalfind:key->value(** @raise Not_found if the key is not in the table. *)endmoduletypeInternalTable=sigincludeTablevaladd:key->value->unitvaliter:(key->value->unit)->unitendmoduleMake_table(H:Hashtbl.S)(V:sigtypetvalsize:intend):InternalTablewithtypekey=H.keyandtypevalue=V.t=structtypekey=H.keytypevalue=V.tlettbl=H.createV.sizeletadd=H.replacetblletfind=H.findtblletiterf=H.iterftblend(* In Function_table, value None means the function has no definition *)moduleFunction_table=Make_table(Kernel_function.Hashtbl)(structtypet=Abstract_state.summaryoptionletsize=7end)letanalyse_function_ref=Extlib.mk_fun"analyse_function"letfunction_summarykf=tryFunction_table.findkfwithNot_found->letresult=!analyse_function_refkfinFunction_table.addkfresult;result(* In Stmt_table, value None means abstract state = Bottom *)moduleStmt_table=structincludeDataflow.StartData(structtypet=Abstract_state.toptionletsize=7end)typekey=stmttypevalue=dataend(* Abstract state after taking into account all global variable definitions *)letinitial_state=ref@@SomeAbstract_state.emptyletwarn_unsupported_explicit_pointerpp_objobjloc=Options.warning~source:(fstloc)~wkey:Options.Warn.unsupported_address"unsupported feature: explicit pointer address: %a; analysis may be unsound"pp_objobjletdo_assignment(lv:lval)exp_o(s:Abstract_state.t):Abstract_state.t=tryAbstract_state.assignmentslvexp_owithSimplified.Explicit_pointer_addressloc->warn_unsupported_explicit_pointer(Pretty_utils.pp_optPrinter.pp_exp)exp_oloc;sletdo_init(lv:lval)(init:init_or_stroption)state=letrecauxlvinitstate=matchinitwith|None->Option.map(do_assignmentlvNone)state|Some(SingleInite)->Option.map(do_assignmentlv(Somee))state|Some(CompoundInit(_,l))->List.fold_left(funstate(o,init)->aux(Cil.addOffsetLvalolv)(Someinit)state)statelinmatchinitwith|Some(CInitinit)->auxlv(Someinit)state|SomeStrInit_->(* TODO: consider potential aliases for literal with common suffixes. *)state|None->auxlvNonestateletpp_abstract_state_opt?(debug=false)fmtv=matchvwith|None->Unicode.pp_bottomfmt|Somea->Abstract_state.pretty~debugfmtaletanalyse_global_varvinitinfost=Options.feedback~level:3"@[analysing global variable definition:@ @[%a@]@ =@ @[%a@];@]"Printer.pp_varinfovPrinter.pp_initinfoinitinfo;letresult=do_init(Varv,NoOffset)initinfo.initstinOptions.feedback~level:3"@[May-aliases after global variable definition@;<2>@[%a@]@;<2>are@;<2>@[%a@]@]"Printer.pp_varinfov(pp_abstract_state_opt~debug:false)result;Options.debug~level:3"@[May-alias graph after global variable definition@;<2>@[%a@]@;<2>is@;<4>@[%a@]@]"Printer.pp_varinfov(pp_abstract_state_opt~debug:true)result;resultletdo_function_call(stmt:stmt)state(res:lvaloption)(f:lhost)(args:explist)loc=letis_malloc(s:string):bool=(s="malloc")||(s="calloc")(* todo : add all function names *)inmatchfwith|Varvwhenis_mallocv.vname->(* special case for malloc *)beginmatch(state,res)with|(None,_)->None|(Somea,None)->(Options.warning"Memory allocation not stored (ignored)";Somea)|(Somea,Somelv)->trySome(Abstract_state.assignment_x_allocate_yalv)withSimplified.Explicit_pointer_addressloc->warn_unsupported_explicit_pointerPrinter.pp_stmtstmtloc;Someaend|_->(* general case *)letsummaries=matchKernel_function.get_calledfwith|SomekfwhenKernel_function.is_mainkf->[]|Somekf->[function_summarykf]|None->(* dereference function pointer using the results of the points-to analysis *)letlvf=f,NoOffsetinbeginmatchStmt_table.findstmtwith|Somestate->lettargets=Abstract_state.find_varslvfstateinOptions.feedback~level:3"%a is an indirect function call to one of %a"Printer.pp_stmtstmtAbstract_state.VarSet.prettytargets;letkf_of_var{vname;_}=trySome(Globals.Functions.find_def_by_namevname)withNot_found->Noneinletkfs=Seq.filter_mapkf_of_var@@Abstract_state.VarSet.to_seqtargetsinList.of_seq@@Seq.mapfunction_summarykfs|_->Options.fatal"unsupported call to function pointer: %a"Lval.prettylvfendinletapply_summarystatesummary=match(state,summary)with|(None,_)->None|(Somea,Somesummary)->Some(Abstract_state.callaresargssummary)|(Somea,None)->Options.warning~wkey:Options.Warn.undefined_function~once:true~source:(fstloc)"function %a has no definition"Printer.pp_lhostf;SomeainList.fold_leftapply_summarystatesummariesletdo_cons_init(s:stmt)(v:varinfo)fargtlocstate=Cil.treat_constructor_as_func(do_function_callsstate)vfargtlocletanalyse_instr(s:stmt)(i:instr)(a:Abstract_state.toption):Abstract_state.toption=matchiwith|Set(lv,exp,_)->Option.map(do_assignmentlv(Someexp))a|Local_init(v,AssignIniti,_)->do_init(Varv,NoOffset)(Some(CIniti))a|Local_init(v,ConsInit(f,arg,t),loc)->do_cons_initsvfargtloca|Code_annot_->a|Skip_->a|Call(res,ef,es,loc)->do_function_callsaresefesloc|Asm(_,_,_,loc)->Options.warning~source:(fstloc)~wkey:Options.Warn.unsupported_asm"unsupported feature: assembler code; skipping";aletdo_instr(s:stmt)(i:instr)(a:Abstract_state.toption):Abstract_state.toption=Options.feedback~level:3"@[analysing instruction:@ %a@]"Printer.pp_stmts;letresult=analyse_instrsiainOptions.feedback~level:3"@[May-aliases after instruction@;<2>@[%a@]@;<2>are@;<2>@[%a@]@]"Printer.pp_stmts(pp_abstract_state_opt~debug:false)result;Options.debug~level:3"@[May-alias graph after instruction@;<2>@[%a@]@;<2>is@;<4>@[%a@]@]"Printer.pp_stmts(pp_abstract_state_opt~debug:true)result;resultmoduleT=structletname="alias"letdebug=true(* TODO see options *)typet=Abstract_state.toptionmoduleStmtStartData=Stmt_tableletcopyx=x(* we only have persistent data *)letprettyfmta=matchawith|None->Format.fprintffmt"<No abstract state>"|Somea->Abstract_state.prettyfmtaletcomputeFirstPredecessor_a=aletcombinePredecessors_stmt~oldstate=matchold,statewith|_,None->assertfalse|None,Some_->Somestate(* [old] already included in [state] *)|Someold,Somenew_->ifAbstract_state.is_includednew_oldthenNoneelseSome(Some(Abstract_state.unionoldnew_))letdoInstr=do_instrletdoGuard__a=Dataflow.GUsea,Dataflow.GUsealetdoStmt__=Dataflow.SDefaultletdoEdge__a=aendmoduleF=Dataflow.Forwards(T)letdo_stmt(a:Abstract_state.t)(s:stmt):Abstract_state.t=matchs.skindwith|Instri->beginmatchdo_instrsi(Somea)with|None->Options.fatal"problem here"|Somea->aend|_->aletanalyse_function(kf:kernel_function)=letfinal_state=ifnot@@Kernel_function.has_definitionkfthenNoneelselet()=Options.feedback~level:2"analysing function: %a"Kernel_function.prettykfinletfirst_stmt=tryKernel_function.find_first_stmtkfwithKernel_function.No_Statement->assertfalseinT.StmtStartData.addfirst_stmt!initial_state;F.compute[first_stmt];letreturn_stmt=Kernel_function.find_returnkfintryStmt_table.findreturn_stmtwithNot_found->letsource,_=Kernel_function.get_locationkfinOptions.warning~source~wkey:Options.Warn.no_return_stmt"function %a does not return; analysis may be unsound"Kernel_function.prettykf;!initial_stateinletlevel=ifKernel_function.is_mainkfthen1else2infinal_state|>Option.iter(funs->Options.feedback~level"@[May-aliases at the end of function %a:@ @[%a@]"Kernel_function.prettykf(Abstract_state.pretty~debug:false)s;Options.debug~level"May-alias graph at the end of function %a:@;<4>@[%a@]"Kernel_function.prettykf(Abstract_state.pretty~debug:true)s;);letresult=matchfinal_statewith(* final state is None if kf has no definition *)|None->None|Somefs->letsummary=Abstract_state.make_summaryfskfinOptions.debug~level:2"Summary of function %a:@ @[%a@]"Kernel_function.prettykf(Abstract_state.pretty_summary~debug:false)summary;SomesummaryinifKernel_function.is_mainkfthenbeginmatchOptions.Dot_output.get(),final_statewith|"",_->()|_,None->()|fname,Somefinal_state->Abstract_state.print_dotfnamefinal_stateend;resultlet()=analyse_function_ref:=analyse_functionletmake_summary(state:Abstract_state.t)(kf:kernel_function)=matchfunction_summarykfwith|Somes->(state,s)|None->Options.fatal"not implemented"letcomputed_flag=reffalseletis_computed()=!computed_flagletprint_stmt_table_eltfmtkv:unit=letprint_key=Stmt.prettyinletprint_valuefmtv=matchvwith|None->Format.fprintffmt"<Bot>"|Somea->Abstract_state.pretty~debug:(Options.DebugTable.get())fmtainFormat.fprintffmt"Before statement %a :@[<hov 2> %a@]@."print_keykprint_valuevletprint_function_table_eltfmtkfs:unit=letfunction_name=Kernel_function.get_namekfinmatchswith|None->Options.debug"function %s -> None"function_name|Somes->Format.fprintffmt"Summary of function %s:@;<5 2>@[%a@]@."function_name(Abstract_state.pretty_summary~debug:(Options.DebugTable.get()))sletcompute()=Ast.compute();initial_state:=Globals.Vars.fold_in_file_orderanalyse_global_var(SomeAbstract_state.empty);Globals.Functions.iter(funkf->ignore@@function_summarykf);computed_flag:=true;ifOptions.ShowStmtTable.get()thenStmt_table.iter(print_stmt_table_eltFormat.std_formatter);ifOptions.ShowFunctionTable.get()thenFunction_table.iter(print_function_table_eltFormat.std_formatter);Options.debug~level:2"node counter: %d"!Abstract_state.node_counterletclear()=computed_flag:=false;initial_state:=SomeAbstract_state.empty;Stmt_table.clear()letget_state_before_stmtstmt=ifis_computed()thentryStmt_table.findstmtwithNot_found->NoneelseNoneletget_summarykf=ifis_computed()thentryFunction_table.findkfwithNot_found->NoneelseNone