123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2023 *)(* CEA (Commissariat a l'energie atomique et aux energies *)(* 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_datatypeopenLayoutmoduleWp=Wp_parameters(* -------------------------------------------------------------------------- *)(* --- Access Maps --- *)(* -------------------------------------------------------------------------- *)moduleVmap=Varinfo.MapmoduleSmap=Datatype.String.MapmoduleRmap=Qed.IntmapmoduleRset=Qed.IntsetmoduleDmap=Qed.Listmap.Make(Offset)moduleDset=Qed.Listset.Make(Deref)moduleAcs=Qed.Listset.Make(Lvalue)moduleClass=Qed.Listset.Make(Datatype.String)typeregion={id:int;mutablegarbled:bool;rw:bool;pack:bool;flat:bool;mutablenames:Class.t;mutablealias:alias;mutabledelta:intDmap.t;mutablederef:Dset.t;mutableread:Acs.t;mutablewritten:Acs.t;mutableshifted:Acs.t;mutablecopiedTo:Rset.t;(* copies to *)mutablepointsTo:intoption;}typemap={cache:Offset.cache;queue:intQueue.t;mutablerid:int;mutablevars:intVmap.t;mutablereturn:int;(* -1 when undefined *)mutablestrings:(int*string)Rmap.t;(* eid -> rid *)mutableindex:intSmap.t;mutableregion:regionRmap.t;mutablealiasing:intRmap.t;mutablecluster:regionclusterRmap.t;mutableroots:rootRmap.t;mutablefroms:regionfromlistRmap.t;mutabledomain:Rset.t;(* reachable regions via clusters *)mutablechunk:regionchunkRmap.t;(* memory chunks *)}letcreate()={rid=0;return=(-1);cache=Offset.cache();vars=Vmap.empty;strings=Rmap.empty;index=Smap.empty;region=Rmap.empty;aliasing=Rmap.empty;queue=Queue.create();cluster=Rmap.empty;roots=Rmap.empty;froms=Rmap.empty;domain=Rset.empty;chunk=Rmap.empty;}letnoid=0letis_emptymap=(map.rid=0)letfreshmap=letid=map.ridinmap.rid<-succid;letregion={id;garbled=false;rw=RW.default();flat=Flat.default();pack=Pack.default();names=[];alias=NotUsed;delta=Dmap.empty;deref=Dset.empty;read=Acs.empty;written=Acs.empty;shifted=Acs.empty;copiedTo=Rset.empty;pointsTo=None;}inmap.region<-Rmap.addidregionmap.region;region(* -------------------------------------------------------------------------- *)(* --- Datatype --- *)(* -------------------------------------------------------------------------- *)moduleR=structtypet=regionletida=a.idletequalab=(a.id=b.id)letcompareab=Stdlib.comparea.idb.idletpp_ridfmtid=Format.fprintffmt"R%03d"idletprettyfmtr=pp_ridfmtr.idendmoduleMap=Qed.Idxmap.Make(R)moduleSet=Qed.Idxset.Make(R)(* -------------------------------------------------------------------------- *)(* --- Union Find --- *)(* -------------------------------------------------------------------------- *)letrecaliasingmapi=tryletj=aliasingmap(Rmap.findimap.aliasing)inifj<>ithenmap.aliasing<-Rmap.addijmap.aliasing;jwithNot_found->iletlinktomapik=ifi<>kthenbeginmap.aliasing<-Rmap.addikmap.aliasing;Queue.addimap.queue;endletregionmapr=tryRmap.find(aliasingmapr)map.regionwithNot_found->failwith"Wp.Region: Undefined Region"letjoin_classesmapij=letk=minijin(linktomapik;linktomapjk;k)letjoin_idmapij=leti=aliasingmapiinletj=aliasingmapjinifi=jthenielsejoin_classesmapijletjoin_regionmaprarb=leti=aliasingmapra.idinletj=aliasingmaprb.idinletk=join_classesmapijinifk=ithenraelseifk=jthenrbelse(* defensive *)regionmapk(* -------------------------------------------------------------------------- *)(* --- Aliasing --- *)(* -------------------------------------------------------------------------- *)letaliasmapab=letk=join_idmapa.idb.idinletr=regionmapkinr.alias<-Aliased;rletdo_aliasmapab=ignore(aliasmapab)letadd_aliasmap~into:ab=leti=aliasingmapa.idinletj=aliasingmapb.idinletwa=(regionmapi).aliasinletwb=(regionmapj).aliasinletk=join_classesmapijin(* Aliasing has changed *)(regionmapk).alias<-Alias.aliaswa(Alias.usewb)letget_mergedmapr=leti=aliasingmapr.idinifi<>r.idthenSome(regionmapi)elseNoneletget_aliasmapr=leti=aliasingmapr.idinifi<>r.idthenregionmapielserleteq_aliasmapab=(aliasingmapa.id=aliasingmapb.id)(* -------------------------------------------------------------------------- *)(* --- General Iterator --- *)(* -------------------------------------------------------------------------- *)letoncemarkr=ifRset.memr.id!markthenfalseelse(mark:=Rset.addr.id!mark;true)letitermapf=letdo_oncemarksfr=ifoncemarksrthenfrelse()inRmap.iter(do_once(refRset.empty)f)map.region(* -------------------------------------------------------------------------- *)(* --- Region Accessor --- *)(* -------------------------------------------------------------------------- *)letidreg=reg.idletis_garbledreg=reg.garbledlethas_pointedreg=reg.pointsTo<>Nonelethas_derefreg=not(Dset.is_emptyreg.deref)lethas_layoutreg=not(Dmap.is_emptyreg.delta)lethas_offsetregd=Dmap.memdreg.deltaletiter_offsetmapfreg=Dmap.iter(funofsr->fofs(regionmapr))reg.deltalethas_copiesreg=not(Rset.is_emptyreg.copiedTo)letiter_copiesmapfreg=Rset.iter(funr->f(regionmapr))reg.copiedToletadd_offsetmapregd=tryregionmap(Dmap.finddreg.delta)withNot_found->letrd=freshmapinreg.delta<-Dmap.adddrd.idreg.delta;rdletadd_pointedmapreg=matchreg.pointsTowith|Somek->regionmapk|None->letr=freshmapinreg.pointsTo<-Somer.id;rletget_addrofmapreg=letaddr=freshmapinaddr.pointsTo<-Somereg.id;addrletget_pointedmapreg=matchreg.pointsTowith|None->None|Somer->Some(regionmapr)letget_offsetmapregd=trySome(regionmap(Dmap.finddreg.delta))withNot_found->Noneletget_copiesmapreg=List.map(regionmap)(Rset.elementsreg.copiedTo)(* -------------------------------------------------------------------------- *)(* --- Access --- *)(* -------------------------------------------------------------------------- *)letacs_readrglvalue=rg.read<-Acs.addlvaluerg.readletacs_writerglvalue=rg.written<-Acs.addlvaluerg.writtenletacs_shiftrglvalue=rg.shifted<-Acs.addlvaluerg.shiftedletacs_derefrgderef=rg.deref<-Dset.addderefrg.derefletacs_copy~src~tgt=iftgt.id<>src.idthensrc.copiedTo<-Rset.addtgt.idsrc.copiedToletiter_readfrg=Acs.iterfrg.readletiter_writefrg=Acs.iterfrg.writtenletiter_shiftfrg=Acs.iterfrg.shiftedletiter_dereffrg=Dset.iterfrg.derefletis_readrg=not(Acs.is_emptyrg.read)letis_writtenrg=not(Acs.is_emptyrg.written)letis_shiftedrg=not(Acs.is_emptyrg.shifted)letis_aliasedrg=Alias.is_aliasedrg.alias(* -------------------------------------------------------------------------- *)(* --- Varinfo Index --- *)(* -------------------------------------------------------------------------- *)letrvarmapxr=letreg=regionmaprinifreg.id<>rthenmap.vars<-Vmap.addxreg.idmap.vars;regletof_nullmap=freshmap(* A fresh region each time: polymorphic *)letof_cvarmapx=tryrvarmapx(Vmap.findxmap.vars)withNot_found->letreg=freshmapinmap.vars<-Vmap.addxreg.idmap.vars;regletof_returnmap=ifmap.return<0thenletreg=freshmapinmap.return<-reg.id;regelseregionmapmap.returnlethas_returnmap=0<=map.returnletiter_varsmapf=Vmap.iter(funxr->fx(rvarmapxr))map.vars(* -------------------------------------------------------------------------- *)(* --- Field Info Index --- *)(* -------------------------------------------------------------------------- *)letfield_offsetmapfd=Offset.field_offsetmap.cachefd(* -------------------------------------------------------------------------- *)(* --- String Literal Index --- *)(* -------------------------------------------------------------------------- *)letof_cstringmap~eid~cst=tryregionmap(fst@@Rmap.findeidmap.strings)withNot_found->letreg=freshmapinmap.strings<-Rmap.addeid(reg.id,cst)map.strings;regletiter_stringsmapf=Rmap.iter(fun(rid,cst)->f(regionmaprid)cst)map.strings(* -------------------------------------------------------------------------- *)(* --- Region Index --- *)(* -------------------------------------------------------------------------- *)letrindexmapar=letreg=regionmaprinifreg.id<>rthenmap.index<-Smap.addareg.idmap.index;regletof_namemapa=tryrindexmapa(Smap.findamap.index)withNot_found->letreg=freshmapinreg.names<-[a];map.index<-Smap.addareg.idmap.index;regletof_classmap=function|None->freshmap|Somea->of_namemapalethas_namesreg=not(Class.is_emptyreg.names)letiter_namesmapf=Smap.iter(funar->fa(rindexmapar))map.index(* -------------------------------------------------------------------------- *)(* --- Fusion --- *)(* -------------------------------------------------------------------------- *)letmerge_pointedmapuv=matchu,vwith|None,w|w,None->w|Somei,Somej->Some(join_idmapij)letmerge_deltamap_dab=join_idmapabletmerge_regionmap~idab={id;garbled=a.garbled||b.garbled;rw=RW.mergea.rwb.rw;flat=Flat.mergea.flatb.flat;pack=Pack.mergea.packb.pack;alias=Alias.mergea.aliasb.alias;names=Class.uniona.namesb.names;read=Acs.uniona.readb.read;written=Acs.uniona.writtenb.written;shifted=Acs.uniona.shiftedb.shifted;copiedTo=Rset.uniona.copiedTob.copiedTo;pointsTo=merge_pointedmapa.pointsTob.pointsTo;delta=Dmap.union(merge_deltamap)a.deltab.delta;deref=Dset.uniona.derefb.deref;}letfusionmap=whilenot(Queue.is_emptymap.queue)doleti=Queue.popmap.queueinletj=aliasingmapiinifi<>jthenbeginifnot(Wp.Region_fixpoint.get())thenWp.debug"Region %a -> %a"R.pp_ridiR.pp_ridj;leta=tryRmap.findimap.regionwithNot_found->assertfalseinletb=tryRmap.findjmap.regionwithNot_found->assertfalseinassert(i=a.id);assert(j=b.id);letc=merge_regionmap~id:jabinmap.region<-Rmap.addjc(Rmap.removeimap.region);enddoneletfusionnedmap=not(Queue.is_emptymap.queue)letiter_fusionmapf=Queue.iter(funi->fi(regionmapi))map.queue(* -------------------------------------------------------------------------- *)(* --- Garbling --- *)(* -------------------------------------------------------------------------- *)letrecgarblifymapreg=ifnotreg.garbledthenbeginreg.garbled<-true;Dmap.iter(fun_deltar->garblifymap(regionmapr);ignore(join_idmapreg.idr);)reg.delta;reg.delta<-Dmap.empty;end(* -------------------------------------------------------------------------- *)(* --- Clustering --- *)(* -------------------------------------------------------------------------- *)letclustermapreg=tryRmap.findreg.idmap.clusterwithNot_found->Layout.EmptymoduleCluster=structopenLayoutletrecfrom_regionmapreg=tryRmap.findreg.idmap.clusterwithNot_found->ifreg.garbledthenGarbledelseifnot(Wp.Region_cluster.get())thenEmptyelsebeginmap.cluster<-Rmap.addreg.idEmptymap.cluster;letmu~rawrarb=ifrawthenbegingarblifymapra;garblifymaprb;end;join_regionmaprarbinletcluster=ifhas_layoutregthenCluster.reshape~eq:R.equal~flat:reg.flat~pack:reg.pack@@from_layoutmapmuregelsefrom_derefmapmureginifcluster=Garbledthengarblifymapreg;map.cluster<-Rmap.addreg.idclustermap.cluster;clusterendandfrom_derefmapmureg=letpointed=lazy(add_pointedmapreg)inList.fold_left(funchunkderef->Cluster.mergeR.prettymuchunk(Cluster.deref~pointedderef))Emptyreg.derefandfrom_layoutmapmureg=Dmap.fold(funoffsettgtacc->letlayout=shiftmapoffset(regionmaptgt)inCluster.mergeR.prettymu(Layoutlayout)acc)reg.deltaEmptyandshiftmapoffsettarget=letinline=Wp.Region_inline.get()||not(is_aliasedtarget)inletcluster=from_regionmaptargetinCluster.shiftmap.cacheR.prettyoffsettarget~inlineclusterletcomputemapreg=beginifhas_layoutreg&&has_derefregthenbeginDset.iter(funderef->lettarget=add_offsetmapreg(Index(sndderef,1))intarget.read<-Acs.unionreg.readtarget.read;target.written<-Acs.unionreg.writtentarget.written;acs_dereftargetderef)reg.deref;reg.deref<-Dset.empty;reg.read<-Acs.empty;reg.written<-Acs.empty;Queue.addreg.idmap.queue;end;ignore(from_regionmapreg);endend(* -------------------------------------------------------------------------- *)(* --- Froms Analysis --- *)(* -------------------------------------------------------------------------- *)letget_fromsmapreg=tryRmap.findreg.idmap.fromswithNot_found->[]letadd_frommap~from~target=letrs=get_fromsmaptargetinmap.froms<-Rmap.addtarget.id(from::rs)map.fromsmoduleFroms=structopenLayoutletrecforwardmapmarks~source~from~target=map.domain<-Rset.addsource.idmap.domain;add_frommap~from~target;ifoncemarkstargetthenadd_regionmapmarkstargetandadd_regionmapmarksreg=beginadd_points_tomapmarks~source:regreg.pointsTo;add_clustermapmarks~source:reg(clustermapreg);endandadd_points_tomapmarks~source=function|None->()|Somep->add_derefmapmarks~source~target:(regionmapp)andadd_derefmapmarks~source~target=letfrom=ifis_shiftedtargetthenFarraysourceelseFderefsourceinforwardmapmarks~source~from~targetandadd_clustermapmarks~source=function|Empty|Garbled|Chunk(Int_|Float_)->()|Chunk(Pointertarget)->add_derefmapmarks~source~target|Layout{layout}->List.iter(add_rangemapmarks~source)layoutandadd_rangemapmarks~source=function|{ofs;reg=target;dim=Dim(_,[])}->forwardmapmarks~source~from:(Ffield(source,ofs))~target|{reg=target}->forwardmapmarks~source~from:(Findexsource)~targetend(* -------------------------------------------------------------------------- *)(* --- Roots Analysis --- *)(* -------------------------------------------------------------------------- *)letget_rootsmapreg=tryRmap.findreg.idmap.rootswithNot_found->Rnonelethas_rootsmapreg=get_rootsmapreg<>RnonemoduleRoots=structletrecof_regionmapregion=tryRmap.findregion.idmap.rootswithNot_found->letfroms=get_fromsmapregioninletroots=List.fold_left(funrootsfrom->Root.mergeroots(Root.from~root:(of_regionmap)from))Rnonefromsinmap.roots<-Rmap.addregion.idrootsmap.roots;rootsletcomputemapreg=ignore(of_regionmapreg)end(* -------------------------------------------------------------------------- *)(* --- Forward & Backward Propagation --- *)(* -------------------------------------------------------------------------- *)letforwardmap=beginletmarks=refRset.emptyinmap.domain<-Rset.empty;Vmap.iter(funxr->letreg=regionmaprinletopenCil_typesinifx.vglob||x.vformalthenadd_frommap~from:(Fvarx)~target:(regionmapr);Froms.add_regionmapmarksreg;)map.vars;endletbackwardmap=beginRmap.iter(Roots.computemap)map.region;end(* -------------------------------------------------------------------------- *)(* --- Chunk Analysis --- *)(* -------------------------------------------------------------------------- *)letrecchunkmapregion=tryRmap.findregion.idmap.chunkwithNot_found->letroots=get_rootsmapregioninletchunk=matchclustermapregionwith|Empty|Garbled->Mraw(roots,get_pointedmapregion)|Chunkv->ifis_readregion||is_writtenregionthenMmem(roots,v)elsebeginmatchvwith|Pointerr->Mrefr|_->Mraw(roots,get_pointedmapregion)end|Layout{layout}->letchunks=Chunk.union_map(fun{reg}->chunksmapreg)layoutinMcomp(chunks,layout)inmap.chunk<-Rmap.addregion.idchunkmap.chunk;chunkandchunksmapregion=matchchunkmapregionwith|Mcomp(rs,_)->rs|_->Chunk.singletonregion.id(* -------------------------------------------------------------------------- *)(* --- Fixpoint --- *)(* -------------------------------------------------------------------------- *)letfixpointmap=beginletturn=ref0inletloop=reftrueinwhile!loopdoincrturn;Wp.feedback~ontty:`Transient"Region clustering (loop #%d)"!turn;fusionmap;map.cluster<-Rmap.empty;itermap(Cluster.computemap);loop:=fusionnedmap;done;Wp.feedback~ontty:`Transient"Region forward analysis";forwardmap;Wp.feedback~ontty:`Transient"Region backward analysis";backwardmap;Wp.feedback~ontty:`Transient"Region fixpoint reached";end(* -------------------------------------------------------------------------- *)