123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315(****************************************************************************)(* *)(* This file is part of MOPSA, a Modular Open Platform for Static Analysis. *)(* *)(* Copyright (C) 2018-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/>. *)(* *)(****************************************************************************)(** General intraprocedural iterator on Control Flow Graphs. *)openMopsaopenSig.Abstraction.StatelessopenUniversal.AstopenAstletname="cfg.iterators.intraproc"(*==========================================================================*)(** {2 Command line options} *)(*==========================================================================*)letopt_decreasing_iter:intref=ref1(** Number of decreasing iterations after widening stabilisation. *)let()=register_domain_optionname{key="-decreasing-iter";category="Loops";doc=" number of decreasing iterations after stabilization";spec=Set_int(opt_decreasing_iter,ArgExt.empty);default="1";}(*==========================================================================*)(** {2 Iterator} *)(*==========================================================================*)moduleDomain=structincludeGenStatelessDomainId(structletname=nameend)letchecks=[]letinitprogmanflow=None(* flow iterator for CFG *)letcfg_iteratorcfgmanflow=(* update the node abstract value as the join of incoming
edge posts and entries;
if weak=true, join with the previous value (for widened nodes)
*)letupdate_nodeweakflownode=(* post edge flows *)letvs=List.map(fun(port,edge)->Flow.get(T_cfg_edge_post(CFG.edge_idedge,port))man.latticeflow)(CFG.node_innode)in(* entry flow *)letvs=matchCFG.node_entry_portcfg.cfg_graphnodewith|None->vs|Someport->(Flow.get(T_cfg_entryport)man.latticeflow)::vsin(* old, if weak *)letnid=CFG.node_idnodeinletold=Flow.get(T_cfg_nodenid)man.latticeflowinletvs=ifweakthenold::vselsevsin(* join *)letctx=Flow.get_ctxflowinletv=List.fold_left(man.lattice.joinctx)man.lattice.bottomvsindebug"update node value %a: abs = @[%a@]@."pp_node_as_idnode(formatman.lattice.print)v;Flow.set(T_cfg_nodenid)vman.latticeflowin(* apply a transfer function, update the edge post *)letapply_edgeedgeflow=letstmt=CFG.edge_dataedgeindebug"applying edge %a: @[%a@]"pp_edge_as_idedgepp_stmtstmt;letsrc,dst=CFG.edge_srcedge,CFG.edge_dstedgein(* shift source node value into the expected port flow *)letflow=List.fold_left(funflow(port,node)->letv=Flow.get(T_cfg_node(CFG.node_idnode))man.latticeflowindebug"input node %a -> port %a, abs = @[%a@]"pp_node_as_idnodepp_tokenport(formatman.lattice.print)v;Flow.addportvman.latticeflow)flowsrcin(* apply edge transfer function *)man.execstmtflow>>%funflow->(* dispatch flow values into nodes *)letflow=List.fold_left(funflow(port,_)->letv=Flow.getportman.latticeflowindebug"edge post %a %a: abs = @[%a@]"pp_edge_as_idedgepp_tokenport(formatman.lattice.print)v;Flow.set(T_cfg_edge_post(CFG.edge_idedge,port))vman.latticeflow)flowdstin(* clean-up flows used by transfer function *)letflow=List.fold_left(funflow(port,_)->Flow.removeportflow)flow(src@dst)inPost.returnflowin(* recompute the node value and call apply_edge for all edges out
of this node
*)letpropagate_nodeweaknodeflow=(* update node value *)letflow=update_nodeweakflownodein(* reompute all edges from this node *)List.fold_left(funpost(_,e)->post>>%apply_edgee)(Post.returnflow)(CFG.node_outnode)in(* get the widening node id for a component *)letget_widening_nodelst=matchlstwith|(GraphSig.Simplenode)::_->CFG.node_idnode|_->Exceptions.panic"node expected at the head of a component"in(* analyze a component until its head is stable, with widening *)letrecfix_componentcountlstflow=letwid=get_widening_nodelstinletold=Flow.get(T_cfg_nodewid)man.latticeflowindebug"analyzing component @[%a@], widen=%a, count=%i, abs=@[%a@]"(Graph.pp_nested_list_listpp_node_as_id)lstpp_node_idwidcount(formatman.lattice.print)old;(* analyze the component *)analyze_componenttruelstflow>>%funflow->letv=Flow.get(T_cfg_nodewid)man.latticeflowin(* check stability *)ifman.lattice.subset(Flow.get_ctxflow)voldthen(debug"component head stable %a"pp_node_idwid;refine_component0lstflow)else(* apply widening *)letwidened=ifcount<!Universal.Iterators.Loops.opt_loop_widening_delaythenvelseman.lattice.widen(Flow.get_ctxflow)oldvindebug"component head not stable %a"pp_node_idwid;letflow=Flow.set(T_cfg_nodewid)widenedman.latticeflowinfix_component(count+1)lstflow(* decreasing iterations *)andrefine_componentcountlstflow=letwid=get_widening_nodelstinifcount>=!opt_decreasing_iterthen((* finished *)debug"component analysis finished @[%a@], head=%a, abs=@[%a@]"(Graph.pp_nested_list_listpp_node_as_id)lstpp_node_idwid(formatman.lattice.print)(Flow.get(T_cfg_nodewid)man.latticeflow);Post.returnflow)else((* iter *)debug"decreasing iteration at head %a, count=%i"pp_node_idwidcount;analyze_componentfalselstflow>>%refine_component(count+1)lst)(* analyze a list of components *)andanalyze_componentweaklstflow:'apost=matchlstwith|(GraphSig.Simplenode)::rest->flow|>propagate_nodeweaknode>>%analyze_componentfalserest|(GraphSig.Composedl)::rest->flow|>fix_component0l>>%analyze_componentfalserest|[]->Post.returnflowin(* shift the current flow into the entry *)letflow_inflow=(* set cfg_entry information *)letflow=List.fold_left(funflow(port,node)->debug"set entry node %a, port %a"pp_node_as_idnodepp_tokenport;letv=Flow.getportman.latticeflowinFlow.set(T_cfg_entryport)vman.latticeflow)flow(CFG.entriescfg.cfg_graph)in(* remove cur flow *)Flow.removeT_curflowin(* gather the flows from the exit nodes *)letflow_outflow=List.fold_left(funflow(port,node)->debug"get exit node %a, port %a"pp_node_as_idnodepp_tokenport;letv=Flow.get(T_cfg_node(CFG.node_idnode))man.latticeflowinFlow.addportvman.latticeflow)flow(CFG.exitscfg.cfg_graph)in(* remove all node-related flows (keeping cur, etc.) *)letcleanupflow=(* clean node info *)letflow=CFG.fold_nodes(funid_flow->Flow.remove(T_cfg_nodeid)flow)cfg.cfg_graphflowin(* clean edge post info *)letflow=CFG.fold_edges(funidedgeflow->List.fold_left(funflow(port,_)->Flow.remove(T_cfg_edge_post(id,port))flow)flow(CFG.edge_dstedge))cfg.cfg_graphflowin(* clean entry info *)List.fold_left(funflow(port,_)->Flow.remove(T_cfg_entryport)flow)flow(CFG.entriescfg.cfg_graph)in(* all together now *)letflow=flow_inflowinanalyze_componentfalsecfg.cfg_orderflow>>%funflow->letflow=flow|>flow_out|>cleanupinPost.returnflow(* atomic test function *)lettest_iteratormancondflow=letrange=erangecondindebug"CFG test [%a] at %a"pp_exprcondpp_rangerange;man.evalcondflow>>$funcondflow->man.exec(mk_assumecondrange)flow>>%funtflow->man.exec(mk_assume(mk_notcondrange)range)flow>>%funfflow->lettflow=Flow.setT_true(Flow.getT_curman.latticetflow)man.latticetflowandfflow=Flow.setT_false(Flow.getT_curman.latticefflow)man.latticefflowinFlow.joinman.latticetflowfflow|>Post.returnletexecstmtmanflow=matchskindstmtwith|S_cfgcfg->Some(cfg_iteratorcfgmanflow)|S_testexpr->Some(test_iteratormanexprflow)|S_skip->Some(Post.returnflow)|_->(* S_expression, S_block and S_print are handled by universal's intraproc *)Noneletevalexpmanflow=Noneletaskquerymanflow=Noneletprint_exprmanflowprinterexp=()endlet()=register_stateless_domain(moduleDomain)