123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178(**************************************************************************)(* *)(* 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_typesopenVisitor(* To avoid a performance issue, do not fold implicit zero-initializers of large
arrays. For arrays of scalar elements, the outputs of an initializer is
exactly the zone covered by the array. For arrays containing structs with
padding bits, this is an over-approximation, so we prefer folding the
initializer if the array is not too big (the 100 cells limit is arbitrary).
We still need to fold the explicit initializers to collect the inputs. *)letfold_implicit_initializertyp=not(Cil.isArrayTypetyp&&(Cil.isArithmeticOrPointerType(Cil.typeOf_array_elemtyp)||Ast_info.array_sizetyp>(Integer.of_int100)))letspecialize_state_on_call?stmtkf=matchstmtwith|None->Eva.Results.(at_start_ofkf|>get_cvalue_model)|Somestmt->letfilter=funcs->matchEva.Callstack.top_callsitecswith|Kstmts->Cil_datatype.Stmt.equalsstmt|Kglobal->falseinEva.Results.(at_start_ofkf|>filter_callstackfilter|>get_cvalue_model)classvirtual['a]cumulative_visitor=objectinheritframa_c_inplaceasselfmethodspecialize_state_on_callkf=specialize_state_on_call?stmt:self#current_stmtkfmethodvirtualcompute_kf:kernel_function->'aendclasstypevirtual['a]cumulative_class=objectinherit['a]cumulative_visitormethodbottom:'amethodresult:'amethodjoin:'a->unitmethodcompute_funspec:kernel_function->'amethodclean_kf_result:kernel_function->'a->'aendmoduleMake(X:sigvalanalysis_name:stringtypetmoduleT:Datatype.Swithtypet=tclassvirtualdo_it:[t]cumulative_classend)=structmoduleMemo=Kernel_function.Make_Table(X.T)(structletname="Inout.Cumulative_analysis.Memo("^X.analysis_name^")"letdependencies=[Eva.Analysis.self]letsize=97end)classdo_it_cachedcall_stack=object(self)inheritX.do_it(* The cycle variable holds the list of functions that are
involved in a cycle. As long as it is not empty, we known that
the results we are computing are not complete, and we do not memorize
them *)valmutablecycle=Kernel_function.Hptset.emptymethodprivateadd_cycles=cycle<-Kernel_function.Hptset.unionscyclemethodcycle=cycle(* Computation using the body of a kernel function. The result is
automatically cached by the function if possible *)methodprivatecompute_kf_with_defkf=letf=Kernel_function.get_definitionkfinifList.exists(Kernel_function.equalkf)call_stackthen(self#add_cycle(Kernel_function.Hptset.singletonkf);self#bottom)elseletcomputer=newdo_it_cached(kf::call_stack)inignore(visitFramacFunction(computer:>frama_c_visitor)f);(* Results on all the statements of the function *)letv=computer#resultinletv=computer#clean_kf_resultkfvin(* recursive calls detected during analysis of the statements*)letcycle_aux=Kernel_function.Hptset.removekfcomputer#cycleinself#add_cyclecycle_aux;ifKernel_function.Hptset.is_emptycyclethen((* No recursive calls, our results are correct *)Inout_parameters.debug"Caching %s result for %a"X.analysis_nameKernel_function.prettykf;Memo.addkfv;)elseInout_parameters.debug"Not caching %s result for %a because of cycle"X.analysis_nameKernel_function.prettykf;v(* Computation and caching for a kernel function, using its spec *)methodprivatecompute_kf_with_spec_generickf=tryMemo.findkfwithNot_found->letr_glob=self#compute_funspeckfinletr_glob=self#clean_kf_resultkfr_globinMemo.addkfr_glob;r_globmethodcompute_kfkf=ifEva.Analysis.use_spec_instead_of_definitionkfthen(* If only a declaration is available, or we are instructed to use
the spec, do so. If a current stmt is available (most of the times),
do not cache the results. Maybe [compute_funspec] will be able
to deliver a more precise result on this given statement *)matchself#current_stmtwith|None->self#compute_kf_with_spec_generickf|Some_stmt->self#compute_funspeckfelsetryMemo.findkfwithNot_found->self#compute_kf_with_defkfendletstatementstmt=letcomputer=newdo_it_cached[]inignore(visitFramacStmt(computer:>frama_c_visitor)stmt);assert(Kernel_function.Hptset.is_emptycomputer#cycle);computer#resultletexprstmte=letcomputer=newdo_it_cached[]incomputer#push_stmtstmt;ignore(visitFramacExpr(computer:>frama_c_visitor)e);assert(Kernel_function.Hptset.is_emptycomputer#cycle);computer#resultletkernel_functionkf=letcomputer=newdo_it_cached[]incomputer#join(computer#compute_kfkf);assert(Kernel_function.Hptset.is_emptycomputer#cycle);computer#resultend(*
Local Variables:
compile-command: "make -C ../../.."
End:
*)