123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167(**************************************************************************)(* *)(* This file is part of Frama-C. *)(* *)(* Copyright (C) 2007-2024 *)(* 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). *)(* *)(**************************************************************************)(** DataState is associated with a program point
and provide the dependencies for the data,
ie. it stores for each location the nodes of the pdg where its value
was last defined.
*)letdkey=Pdg_parameters.register_category"state"moduleP=Pdg_parametersopenPdg_typesopenPdgTypesexceptionCannot_foldletmakeloc_infounder_outputs={loc_info=loc_info;under_outputs=under_outputs}letempty=makeLocInfo.emptyLocations.Zone.bottom(* Convention: bottom is used for statements that are not reachable,
and for calls that never terminate. In this case, the second field
must be ignored *)letbottom=makeLocInfo.bottomLocations.Zone.bottomletprettyfmtstate=Format.fprintffmt"state = %a@.with under_outputs = %a@."LocInfo.prettystate.loc_infoLocations.Zone.prettystate.under_outputsletadd_loc_nodestate~exactlocnode=P.debug~dkey~level:2"add_loc_node (%s) : node %a -> %a@."(ifexactthen"exact"else"merge")PdgTypes.Node.prettynodeLocations.Zone.prettyloc;ifLocInfo.is_bottomstate.loc_infothen(* Do not add anything to a bottom state (which comes from an unreachable
statement *)stateelseletnew_info=NodeSetLattice.inject_singletonnodeinletnew_loc_info=LocInfo.add_binding~exactstate.loc_infolocnew_infoinletnew_outputs=(* Zone.link in the under-approx version of Zone.join *)ifexactthenLocations.Zone.linkstate.under_outputslocelsestate.under_outputsinP.debug~dkey~level:2"add_loc_node -> %a"prettystate;makenew_loc_infonew_outputs(** this one is very similar to [add_loc_node] except that
* we want to accumulate the nodes (exact = false) but nonetheless
* define under_outputs like (exact = true) *)letadd_init_state_inputstatelocnode=matchlocwith|Locations.Zone.Top(_p,_o)->(* don't add top because it loses everything*)state|_->letnew_info=NodeSetLattice.inject_singletonnodeinletnew_loc_info=LocInfo.add_binding~exact:falsestate.loc_infolocnew_infoinletnew_outputs=Locations.Zone.linkstate.under_outputslocinmakenew_loc_infonew_outputslettest_and_merge~oldnew_=ifLocInfo.is_includednew_.loc_infoold.loc_info&&Locations.Zone.is_includedold.under_outputsnew_.under_outputsthen(false,old)else(* Catch Bottom states, as under_outputs get a special value *)ifLocInfo.is_bottomold.loc_infothentrue,new_elseifLocInfo.is_bottomnew_.loc_infothentrue,oldelseletnew_loc_info=LocInfo.joinold.loc_infonew_.loc_infoinletnew_outputs=Locations.Zone.meetold.under_outputsnew_.under_outputsinletnew_state={loc_info=new_loc_info;under_outputs=new_outputs}intrue,new_state(** returns pairs of (n, z_opt) where n is a node that computes a part of [loc]
* and z is the intersection between [loc] and the zone computed by the node.
* @raise Cannot_fold if the state is top (TODO : something better ?)
* *)letget_loc_nodes_and_partstateloc=letprocessznodesacc=ifLocations.Zone.intersectszlocthenletz=ifLocations.Zone.equalloczthenSomeloc(* Be careful not ot put None here, because if we have n_1 : (s1 =
s2) and then n_2 : (s1.b = 3) the state looks like :
s1.a -> n_1; s1.b -> n_2 ; s1.c -> n_1. And if we
look for s1.a in that state, we get n_1 but this node
represent more that s1.a even if it is so in the
state... *)elseSome(Locations.Zone.narrowzloc)inletaddnacc=P.debug~dkey~level:2"get_loc_nodes -> %a@."PdgTypes.Node.pretty_with_part(n,z);(n,z)::accinNodeSetLattice.foldaddnodesaccelseaccinmatchstate.loc_infowith|LocInfo.Top->raiseCannot_fold|LocInfo.Bottom->[]|LocInfo.Mapm->LocInfo.foldprocessm[](** @raise Cannot_fold (see [get_loc_nodes_and_part]) *)letget_loc_nodesstateloc=P.debug~dkey~level:2"get_loc_nodes %a@. in %a@."Locations.Zone.prettylocprettystate;ifLocations.Zone.equallocLocations.Zone.bottomthen[],None(* nothing to do *)elseletnodes=get_loc_nodes_and_partstatelocinletundef_zone=Locations.Zone.difflocstate.under_outputsinP.debug~dkey~level:2"get_loc_nodes -> undef = %a@."Locations.Zone.prettyundef_zone;letundef_zone=if(Locations.Zone.equalundef_zoneLocations.Zone.bottom)thenNoneelseSomeundef_zoneinnodes,undef_zoneopenCil_datatypetypestates=PdgTypes.data_stateStmt.Hashtbl.t(* Slightly ugly, but should not be a problem unless the sid counter wraps *)letstmt_init=List.hdStmt.reprsletstmt_last={stmt_initwithCil_types.sid=stmt_init.Cil_types.sid-1}letstore_init_statestatesstate=Stmt.Hashtbl.addstatesstmt_initstateletstore_last_statestatesstate=Stmt.Hashtbl.addstatesstmt_laststateletget_init_statestates=Stmt.Hashtbl.findstatesstmt_initletget_last_statestates=Stmt.Hashtbl.findstatesstmt_lastletget_stmt_statestatesstmt=Stmt.Hashtbl.findstatesstmt