123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246(****************************************************************************)(* *)(* 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/>. *)(* *)(****************************************************************************)(** Extends the simple Universal language with Control Flow Graphs. *)openMopsaopenUniversal.Ast(*==========================================================================*)(** {2 Graph types} *)(*==========================================================================*)moduleLoc=structtypet=Location.pos(* maybe add a unique tag? *)letcompare=Location.compare_poslethash=Hashtbl.hashletequall1l2=Location.compare_posl1l2=0letprint=Location.pp_positionendmoduleTagLoc=structtypet={loc:Loc.t;tag:string;(* optional tag (may be "") *)id:int;(* unique among t with the same log ans tag *)}letcompare(t1:t)(t2:t):int=Compare.tripleLoc.comparecomparecompare(t1.loc,t1.id,t1.tag)(t2.loc,t2.id,t2.tag)lethash:t->int=Hashtbl.hashletequal(t1:t)(t2:t):bool=comparet1t2=0letprintfmt(t:t)=matcht.tag,t.idwith|"",0->Loc.printfmtt.loc|"",_->Format.fprintffmt"%a(%i)"Loc.printt.loct.id|_,0->Format.fprintffmt"%a(%s)"Loc.printt.loct.tag|_->Format.fprintffmt"%a(%s:%i)"Loc.printt.loct.tagt.idendmoduleRange=structtypet=rangeletcompare=compare_rangelethash=Hashtbl.hashletequall1l2=comparel1l2=0letprint=pp_rangeendmodulePort=structtypet=tokenletcompare=compare_tokenlethash=Hashtbl.hashletequall1l2=comparel1l2=0letprint=pp_tokenendmoduleLocSet=SetExt.Make(Loc)moduleLocMap=MapExt.Make(Loc)moduleLocHash=Hashtbl.Make(Loc)moduleTagLocSet=SetExt.Make(TagLoc)moduleTagLocMap=MapExt.Make(TagLoc)moduleTagLocHash=Hashtbl.Make(TagLoc)moduleRangeSet=SetExt.Make(Range)moduleRangeMap=MapExt.Make(Range)moduleRangeHash=Hashtbl.Make(Range)(** Build CFG module. *)moduleCFG_Param=structmoduleNodeId=TagLoc(** Identify nodes by source location. *)moduleEdgeId=Range(** Identify edges by source range. *)modulePort=Port(** Edge outputs are distinguished by flow tokens. *)endmoduleCFG=Graph.Make(CFG_Param)(** Edges are labelled with a statement.
Nodes have no information in the graph structure.
Abstract invariant information will be kept in maps separately
from the CFG.
This way, CFG can be kept immutable.
*)typegraph=(unit,stmt)CFG.graphtypenode=(unit,stmt)CFG.nodetypeedge=(unit,stmt)CFG.edgetypenode_id=TagLoc.ttypeedge_id=Range.ttypeport=tokentypecfg={cfg_graph:graph;mutablecfg_order:nodeGraphSig.nested_listlist;}(*==========================================================================*)(** {2 Graph utilities} *)(*==========================================================================*)letmk_node_id?(id=0)?(tag="")(loc:Loc.t):node_id=TagLoc.{id;tag;loc;}letfresh_node_id=LocHash.create16letmk_fresh_node_id?(tag="")(loc:Loc.t):node_id=letid=tryLocHash.findfresh_node_idlocwithNot_found->0inLocHash.replacefresh_node_idloc(id+1);mk_node_id~id~tagloc(** Fresh node with some source location information.
NOTE: Do not mix mk_fresh_node_id and mk_node_id as it can break
uniqueness.
*)letloc_anonymous:Loc.t=Location.mk_pos"<anonymous>"(-1)(-1)letmk_anonymous_node_id?(tag="")():node_id=mk_fresh_node_id~tagloc_anonymous(** Fresh node without any source location information. *)letcopy_node_id(n:node_id):node_id=mk_fresh_node_id~tag:n.TagLoc.tagn.TagLoc.locletnode_loc(t:node_id):Loc.t=t.TagLoc.locletpp_node_id=TagLoc.printletpp_node_as_idfmtnode=pp_node_idfmt(CFG.node_idnode)letcompare_node_id=TagLoc.compareletmk_edge_id?(tag="")(range:range):edge_id=iftag=""thenrangeelsetag_rangerange"%s"tagletfresh_edge_id=RangeHash.create16(* we use our own fresh range generator to keep an origin_range information *)letmk_fresh_edge_id?(tag="")(range:range):edge_id=letid=tryRangeHash.findfresh_edge_idrangewithNot_found->0inRangeHash.replacefresh_edge_idrange(id+1);lettag=ifid=0thentagelseiftag=""thenstring_of_intidelsetag^":"^(string_of_intid)inmk_edge_id~tagrange(** Fresh range with possible some source range information.
NOTE: Do not mix mk_fresh_edge_id and mk_edge_id as it can break
uniqueness.
*)letmk_anonymous_edge_id?(tag="")():edge_id=mk_edge_id~tag(mk_fresh_range())(** Fresh range without any source range information. *)letedge_range(t:edge_id):range=tletpp_edge_id=Range.printletpp_edge_as_idfmtedge=pp_edge_idfmt(CFG.edge_idedge)letcompare_edge_id=Range.compare(*==========================================================================*)(** {2 Flows} *)(*==========================================================================*)(** Associate a flow to each CFG node.
We can store abstract information for the whole graph in a
single abstract state, using node flows.
We also associate a flow to cache the post-image of each CFG edge.
*)typetoken+=|T_cfg_nodeofnode_id|T_cfg_edge_postofedge_id*port|T_cfg_entryofport(** Flow for true and false branch of tests. *)typetoken+=|T_true|T_false(*==========================================================================*)(** {2 Statements} *)(*==========================================================================*)typestmt_kind+=|S_cfgofcfg|S_testofexpr(** test nodes, with a true and a false branch *)|S_skip(** empty node *)letmk_skiprange=mk_stmtS_skiprangeletmk_testerange=mk_stmt(S_teste)rangeletmk_cfgcfgrange=mk_stmt(S_cfgcfg)range