123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330(**************************************************************************)(* *)(* 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_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)letfunction_compute_ref=Extlib.mk_fun"function_compute"(* In Stmt_table, value None means abstract state = Bottom *)moduleStmt_table=structincludeDataflow.StartData(structtypet=Abstract_state.toptionletsize=7end)typekey=stmttypevalue=dataendletwarn_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:exp)(a:Abstract_state.t):Abstract_state.t=tryAbstract_state.assignmentalvexpwithSimplified.Explicit_pointer_addressloc->warn_unsupported_explicit_pointerPrinter.pp_expexploc;aletrecdo_init(lv:lval)(init:init)state=matchinitwith|SingleInite->Option.map(do_assignmentlve)state|CompoundInit(_,l)->List.fold_left(funstate(o,init)->do_init(Cil.addOffsetLvalolv)initstate)statelletdoFunctionf=!function_compute_reffletdo_function_call(stmt:stmt)state(res:lvaloption)(ef:exp)(args:explist)loc=letis_malloc(s:string):bool=(s="malloc")||(s="calloc")(* todo : add all function names *)inmatchefwith|{enode=Lval(Varv,_);_}whenis_mallocv.vname->begin(* special case for malloc *)match(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|_->begin(* general case *)letsummary=matchKernel_function.get_calledefwith|SomekfwhenKernel_function.is_mainkf->None|Somekf->begintryFunction_table.findkfwithNot_found->doFunctionkfend|None->Options.warning~wkey:Options.Warn.unsupported_function~source:(fstloc)"unsupported feature: call to function pointer: %a"Exp.prettyef;Noneinmatch(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"Exp.prettyef;Someaendletdo_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=matchiwithSet(lv,exp,_)->Option.map(do_assignmentlvexp)a|Local_init(v,AssignIniti,_)->do_init(Varv,NoOffset)ia|Local_init(v,ConsInit(f,arg,t),loc)->do_cons_initsvfargtloca|Code_annot_->a|Skip_->a|Call(res,ef,es,loc)->(* !function_compute_ref ef *)do_function_callsaresefesloc|Asm(_,_,_,loc)->Options.warning~source:(fstloc)~wkey:Options.Warn.unsupported_asm"unsupported feature: assembler code; skipping";aletpp_abstract_state_opt?(debug=false)fmtv=matchvwith|None->Format.fprintffmt"⊥"|Somea->Abstract_state.pretty~debugfmtaletdo_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 persistant data *)letprettyfmta=matchawithNone->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.skindwithInstri->beginmatchdo_instrsi(Somea)withNone->Options.fatal"problem here"|Somea->aend|_->aletanalyse_function(kf:kernel_function)=Options.feedback~level:2"analysing function: %a"Kernel_function.prettykf;ifKernel_function.has_definitionkfthenbeginletfirst_stmt=tryKernel_function.find_first_stmtkfwithKernel_function.No_Statement->assertfalseinT.StmtStartData.addfirst_stmt(SomeAbstract_state.empty);F.compute[first_stmt];letreturn_stmt=Kernel_function.find_returnkfintryStmt_table.findreturn_stmtwithNot_found->beginletsource,_=Kernel_function.get_locationkfinOptions.warning~source~wkey:Options.Warn.no_return_stmt"function %a does not return; analysis may be unsound"Kernel_function.prettykf;SomeAbstract_state.emptyendendelseNoneletdoFunction(kf:kernel_function)=letfinal_state=analyse_functionkfinletlevel=ifKernel_function.is_mainkfthen1else2inOptions.feedback~level"@[May-aliases at the end of function %a:@ @[%a@]"Kernel_function.prettykf(pp_abstract_state_opt~debug:false)final_state;Options.debug~level"May-alias graph at the end of function %a:@;<4>@[%a@]"Kernel_function.prettykf(pp_abstract_state_opt~debug:true)final_state;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;Function_table.addkfresult;resultlet()=function_compute_ref:=doFunctionletmake_summary(state:Abstract_state.t)(kf:kernel_function)=trybeginmatchFunction_table.findkfwithSomes->(state,s)|None->Options.fatal"not implemented"endwithNot_found->beginmatchdoFunctionkfwithSomes->(state,s)|None->Options.fatal"not implemented"endletcomputed_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();Globals.Functions.iter(funkf->ignore@@doFunctionkf);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)letclear()=computed_flag:=false;Stmt_table.clear()letget_state_before_stmt_kfstmt=ifis_computed()thentryStmt_table.findstmtwithNot_found->NoneelseNoneletget_summarykf=ifis_computed()thentryFunction_table.findkfwithNot_found->NoneelseNone