123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2017-2019 The MOPSA Project. *)(* *)(* This program is free software: 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, either version 3 of the License, or *)(* (at your option) any later version. *)(* *)(* This program 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. *)(* *)(* You should have received a copy of the GNU Lesser General Public License *)(* along with this program. If not, see <http://www.gnu.org/licenses/>. *)(* *)(****************************************************************************)(** Inter-procedural iterator by inlining, caching the last analysis
results for each flow *)openMopsaopenSig.Abstraction.StatelessopenAstopenCallstackopenContextopenCommonopenMapExtletname="universal.iterators.interproc.sequential_cache"letopt_universal_modular_interproc_cache_size:intref=ref3let()=register_domain_optionname{key="-mod-interproc-size";category="Interproc";doc=" size of the cache in the modular interprocedural analysis";spec=Set_int(opt_universal_modular_interproc_cache_size,ArgExt.empty);default=string_of_int!opt_universal_modular_interproc_cache_size;};moduleDomain=structincludeGenStatelessDomainId(structletname=nameend)letdependencies=[]letchecks=[]letdebugfmt=Debug.debug~channel:namefmtmoduleFctx=GenContextKey(structtype'at=('aflow*('a,expr)cases)listStringMap.tletprintpfmtctx=Format.fprintffmt"Function cache context (py): %a@\n"(StringMap.fprintMapExt.printer_default(funfmts->Format.fprintffmt"%s"s)(funfmtlist->Format.pp_print_list(funfmt(in_flow,cases)->Format.fprintffmt"in_flow = %a@\ncases = %a@\n"(format(Flow.printp))in_flowEval.printcases)fmtlist))ctxend)letfind_signaturemanfunnamein_flow=tryletcache=find_ctxFctx.key(Flow.get_ctxin_flow)inletflows=StringMap.findfunnamecacheinSome(List.find(fun(flow_in,_)->Flow.subsetman.latticein_flowflow_in)flows)withNot_found->Noneletstore_signaturefunnamein_flowcasesold_ctx=letold_local_ctx=tryContext.find_ctxFctx.keyold_ctxwithNot_found->StringMap.emptyinletold_sig=tryStringMap.findfunnameold_local_ctxwithNot_found->[]inletnew_sig=ifList.lengthold_sig<!opt_universal_modular_interproc_cache_sizethen(in_flow,cases)::old_sigelse(in_flow,cases)::(List.rev@@List.tl@@List.revold_sig)inletnew_ctx=StringMap.addfunnamenew_sigold_local_ctxinadd_ctxFctx.keynew_ctxold_ctxletinitprogmanflow=Flow.map_ctx(add_ctxFctx.keyStringMap.empty)flow|>Post.return|>Option.someletsplit_cur_from_othersmanflow=letbot=Flow.bottom(Flow.get_ctxflow)(Flow.get_reportflow)inletflow_cur=Flow.setT_cur(Flow.getT_curman.latticeflow)man.latticebotinletflow_other=Flow.removeT_curflowinflow_cur,flow_otherletevalexpmanflow=letrange=erangeexpinmatchekindexpwith|E_call({ekind=E_function(User_definedfunc)},args)->ifman.lattice.is_bottom(Flow.getT_curman.latticeflow)thenCases.emptyflow|>OptionExt.returnelseletin_flow=flowinletin_flow_cur,in_flow_other=split_cur_from_othersmanin_flowinletparams,locals,body,in_flow_cur=init_fun_paramsfuncargsrangemanin_flow_curinletin_flow_cur=post_to_flowmanin_flow_curinbeginmatchfind_signaturemanfunc.fun_uniq_namein_flow_curwith|None->letret=matchfunc.fun_return_typewith|None->None|Some_->matchfunc.fun_return_varwith|Somev->Somev|None->Some(mk_returnexp)in(* mk_range_attr_var range (Format.asprintf "ret_var_%s" func.fun_uniq_name) T_any in *)letres=inlinefuncparamslocalsbodyretrangemanin_flow_curinCases.set_ctx(store_signaturefunc.fun_uniq_namein_flow_curres(Cases.get_ctxres))res>>$funrflow->Eval.singletonr(Flow.joinman.latticein_flow_otherflow)|Some(_,cases)->debug"reusing %s at range %a"func.fun_orig_namepp_rangefunc.fun_range;cases>>$funrflow->Eval.singletonr(Flow.joinman.latticein_flow_otherflow)end|>OptionExt.return|_->Noneletexec___=Noneletask___=Noneletprint_expr____=()endlet()=register_stateless_domain(moduleDomain)