123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507(**************************************************************************)(* *)(* 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_typesopenCil_datatypeopenLogic_ptreemoduleWp=Wp_parameters(* -------------------------------------------------------------------------- *)(* --- L-Path --- *)(* -------------------------------------------------------------------------- *)typeregion_pattern=|FREE|PVAR|PREF|PMEM|PVECTOR|PMATRIXtypelrange=|R_indexofterm|R_rangeoftermoption*termoptiontypelpath={loc:location;lnode:lnode;ltype:typ;}andlnode=|L_varofvarinfo|L_regionofstring|L_addroflpath|L_staroftyp*lpath|L_shiftoflpath*typ*lrange|L_indexoflpath*typ*lrange|L_fieldoflpath*fieldinfolist|L_castoftyp*lpathtyperegion_spec={region_name:stringoption;region_pattern:region_pattern;region_lpath:lpathlist;}(*
let get_int e =
match Logic_utils.constFoldTermToInt e with
| None -> None
| Some a -> Some (Integer.to_int_exn a)
let get_int_option = function
| None -> None
| Some e -> get_int e
*)moduleLpath=structtypet=lpathletcompare_boundab=matcha,bwith|None,None->0|Somea,Someb->Term.compareab|None,Some_->(-1)|Some_,None->1letcompare_rangeab=matcha,bwith|R_indexa,R_indexb->Term.compareab|R_index_,_->(-1)|_,R_index_->1|R_range(a1,b1),R_range(a2,b2)->letcmp=compare_bounda1a2inifcmp<>0thencmpelsecompare_boundb1b2letreccompareab=matcha.lnode,b.lnodewith|L_varx,L_vary->Varinfo.comparexy|L_var_,_->(-1)|_,L_var_->1|L_regiona,L_regionb->String.compareab|L_region_,_->(-1)|_,L_region_->1|L_star(ta,a),L_star(tb,b)->letcmp=Typ.comparetatbinifcmp<>0thencmpelsecompareab|L_star_,_->(-1)|_,L_star_->1|L_addra,L_addrb->compareab|L_addr_,_->(-1)|_,L_addr_->1|L_shift(a,ta,i),L_shift(b,tb,j)->compare_indexataibtbj|L_shift_,_->(-1)|_,L_shift_->1|L_index(a,ta,i),L_index(b,tb,j)->compare_indexataibtbj|L_index_,_->(-1)|_,L_index_->1|L_field(a,fs),L_field(b,gs)->letcmp=compareabinifcmp<>0thencmpelseQed.Hcons.compare_listFieldinfo.comparefsgs|L_field_,_->(-1)|_,L_field_->1|L_cast(ta,a),L_cast(tb,b)->letcmp=Typ.comparetatbinifcmp<>0thencmpelsecompareabandcompare_indexataibtbj=letcmp=compareabinifcmp<>0thencmpelseletcmp=Typ.comparetatbinifcmp<>0thencmpelsecompare_rangeijletequalab=(compareab=0)letpp_boundppfmt=functionNone->()|Somea->ppfmtaletpp_rangeppfmt=function|R_indexa->ppfmta|R_range(a,b)->beginpp_boundppfmta;Format.fprintffmt"@,..";pp_boundppfmtb;endletfirst=function[]->assertfalse|f::_->fletreclast=function[]->assertfalse|[f]->f|_::fs->lastfsletis_lval=function|L_var_|L_region_|L_index_|L_field_->true|_->falseletrecpp_lpathppfmta=matcha.lnodewith|L_varx->Varinfo.prettyfmtx|L_regiona->Format.pp_print_stringfmta|L_field(p,[f])->pfieldpppffmt|L_field(p,fs)->Format.fprintffmt"@[<hov 2>(%t@,..%t)@]"(pfieldppp(firstfs))(pfieldppp(lastfs))|L_index(a,_,i)->Format.fprintffmt"@[<hov 2>%a@,[%a]@]"(pp_lvalpp)a(pp_rangepp)i|L_shift(a,_,i)->Format.fprintffmt"@[<hov 2>%a@,+(%a)@]"(pp_lpathpp)a(pp_rangepp)i|L_star(_,a)->Format.fprintffmt"*%a"(pp_lvalpp)a|L_addra->Format.fprintffmt"&%a"(pp_lvalpp)a|L_cast(t,a)->Format.fprintffmt"(%a)@,%a"Typ.prettyt(pp_lvalpp)aandpfieldppaffmt=Format.fprintffmt"@[<hov 2>%a%a@]"(panchorpp)aFieldinfo.prettyfandpanchorppfmta=matcha.lnodewith|L_star(_,p)->Format.fprintffmt"%a@,->"(pp_lvalpp)p|_->Format.fprintffmt"%a@,."(pp_lvalpp)aandpp_lvalppfmta=ifis_lvala.lnodethenpp_lpathppfmtaelseFormat.fprintffmt"(%a)"(pp_lpathpp)aletpretty=pp_lpathTerm.prettyend(* -------------------------------------------------------------------------- *)(* --- Region Spec Printer --- *)(* -------------------------------------------------------------------------- *)letpatterns=["PVAR",PVAR;"PREF",PREF;"PMEM",PMEM;"PVECTOR",PVECTOR;"PMATRIX",PMATRIX;]letp_namep=fst(List.find(fun(_,q)->q=p)patterns)letpp_pattern_specfmtp=tryFormat.fprintffmt"\\pattern{%s}"(p_namep);truewithNot_found->falseletpp_path_specppfmtcomalv=ifcomathenFormat.fprintffmt",@ ";Lpath.pp_lpathppfmtlv;trueletpp_region_specppfmtcomaspec=beginifcomathenFormat.fprintffmt",@ ";Format.fprintffmt"@[<hv 2>";Option.iter(Format.fprintffmt"%s:@ ")spec.region_name;letcoma=pp_pattern_specfmtspec.region_patterninletcoma=List.fold_left(pp_path_specppfmt)comaspec.region_lpathinFormat.fprintffmt"@]";comaend(* -------------------------------------------------------------------------- *)(* --- Typing Env --- *)(* -------------------------------------------------------------------------- *)typeenv={context:Logic_typing.typing_context;mutabledeclared:stringlist;mutablename:stringoption;mutablepattern:region_pattern;mutablepaths:lpathlist;mutablespecs:region_speclist;}leterrorenv~locmsg=env.context.Logic_typing.errorlocmsgletflushenv=letregion_name=env.nameinenv.name<-None;letregion_pattern=env.patterninenv.pattern<-FREE;letregion_lpath=List.revenv.pathsinenv.paths<-[];Option.iter(funa->env.declared<-a::env.declared)region_name;ifnot(region_name=None&®ion_lpath=[])thenletregion={region_name;region_pattern;region_lpath}inenv.specs<-region::env.specs(* -------------------------------------------------------------------------- *)(* --- Type Utils --- *)(* -------------------------------------------------------------------------- *)letisIndexTypet=matchLogic_utils.unroll_typetwith|Ctype(TInt_)|Linteger->true|_->falseletgetCompoundTypeenv~loctyp=matchCil.unrollTypetypwith|TComp(comp,_)->comp|_->errorenv~loc"Expected compound type for term"(* -------------------------------------------------------------------------- *)(* --- Path Typechecking --- *)(* -------------------------------------------------------------------------- *)letparse_varinfoenv~locx=trymatchenv.context.Logic_typing.find_varxwith|{lv_origin=Somev}->v|_->errorenv~loc"Variable '%s' is not a C-variable"xwithNot_found->errorenv~loc"Unknown variable (or region) '%s'"xletparse_fieldinfoenv~loccompf=tryList.find(funfd->fd.fname=f)(Option.value~default:[]comp.cfields)withNot_found->errorenv~loc"No field '%s' in compound type '%s'"fcomp.cnameletparse_lindexenve=letopenLogic_typinginletg=env.contextinlett=g.type_termgg.pre_stateeinifisIndexTypet.term_typethentelseerrorenv~loc:t.term_loc"Index term shall have a integer type"letparse_ltypeenv~loct=letopenLogic_typinginletg=env.contextinlett=g.logic_typeglocg.pre_statetinmatchLogic_utils.unroll_typetwith|Ctypetyp->typ|_->errorenv~loc"C-type expected for casting l-values"letparse_lboundenv=function|None->None|Somee->Some(parse_lindexenve)letparse_lrangeenve=matche.lexpr_nodewith|PLrange(a,b)->R_range(parse_lboundenva,parse_lboundenvb)|_->R_index(parse_lindexenve)letsugar~locnode={lexpr_loc=loc;lexpr_node=node}letrecfield_range~insidefafb=function|[]->[]|f::fs->letbound=Fieldinfo.equalffa||Fieldinfo.equalffbinifinsidethenf::(ifboundthen[]elsefield_range~insidefafbfs)elseifboundthenf::(field_range~inside:truefafbfs)elsefield_range~insidefafbfsletrectypeof_fields=function|[]->TVoid[]|[f]->f.ftype|f::fs->lett=typeof_fieldsfsinifTyp.equalf.ftypetthentelseTVoid[]letrecparse_lpathenve=letloc=e.lexpr_locinmatche.lexpr_nodewith|PLvarx->ifList.memxenv.declaredthen{loc;lnode=L_regionx;ltype=TVoid[]}elseletv=parse_varinfoenv~locxin{loc;lnode=L_varv;ltype=v.vtype}|PLunop(Ustar,p)->letlv=parse_lpathenvpinifCil.isPointerTypelv.ltypethenlette=Cil.typeOf_pointedlv.ltypein{loc;lnode=L_star(te,lv);ltype=te}elseerrorenv~loc"Pointer-type expected for operator '&'"|PLunop(Uamp,p)->letlv=parse_lpathenvpinletltype=TPtr(lv.ltype,[])in{loc;lnode=L_addrlv;ltype}|PLbinop(p,Badd,r)->let{ltype}aslv=parse_lpathenvpinletrg=parse_lrangeenvrinifCil.isPointerTypeltypethenlette=Cil.typeOf_pointedltypein{loc;lnode=L_shift(lv,te,rg);ltype=ltype}elseifCil.isArrayTypeltypethenlette=Cil.typeOf_array_elemltypein{loc;lnode=L_shift(lv,te,rg);ltype=TPtr(te,[])}elseerrorenv~loc"Pointer-type expected for operator '+'"|PLdot(p,f)->letlv=parse_lpathenvpinletcomp=getCompoundTypeenv~loc:lv.loclv.ltypeinletfd=parse_fieldinfoenv~loccompfin{loc;lnode=L_field(lv,[fd]);ltype=fd.ftype}|PLarrow(p,f)->letsp=sugar~loc(PLunop(Ustar,p))inletpf=sugar~loc(PLdot(sp,f))inparse_lpathenvpf|PLarrget(p,k)->let{ltype}aslv=parse_lpathenvpinletrg=parse_lrangeenvkinifCil.isPointerTypeltypethenletpointed=Cil.typeOf_pointedltypeinletls={loc;lnode=L_shift(lv,pointed,rg);ltype}in{loc;lnode=L_star(pointed,ls);ltype=pointed}elseifCil.isArrayTypeltypethenletelt=Cil.typeOf_array_elemltypein{loc;lnode=L_index(lv,elt,rg);ltype=elt}elseerrorenv~loc:lv.loc"Pointer or array type expected"|PLcast(t,a)->letlv=parse_lpathenvainletty=parse_ltypeenv~loctin{loc;lnode=L_cast(ty,lv);ltype=ty}|PLrange(Somea,Someb)->letpa,fa=parse_fpathenvainletpb,fb=parse_fpathenvbinletp=ifLpath.equalpapbthenpaelseerrorenv~loc"Range of fields from different l-values"inletcomp=ifCompinfo.equalfa.fcompfb.fcompthenfa.fcompelseerrorenv~loc"Range of fields from incompatible types"inletfields=field_range~inside:falsefafb(Option.value~default:[]comp.cfields)inletltype=typeof_fieldsfieldsin{loc;lnode=L_field(p,fields);ltype}|PLrange(Somea,None)->letp,fd=parse_fpathenvainletfields=field_range~inside:falsefdfd(Option.value~default:[]fd.fcomp.cfields)inletltype=typeof_fieldsfieldsin{loc;lnode=L_field(p,fields);ltype}|PLrange(None,Somea)->letp,fd=parse_fpathenvainletfields=field_range~inside:truefdfd(Option.value~default:[]fd.fcomp.cfields)inletltype=typeof_fieldsfieldsin{loc;lnode=L_field(p,fields);ltype}|_->errorenv~loc"Unexpected expression for region spec"andparse_fpathenvp=letlv=parse_lpathenvpinmatchlv.lnodewith|L_field(a,[f])->a,f|_->errorenv~loc:lv.loc"Missing field access in range"(* -------------------------------------------------------------------------- *)(* --- Spec Typechecking --- *)(* -------------------------------------------------------------------------- *)letkspec=ref0letregistry=Hashtbl.create0letparse_patternenv~locnamesparams=matchnameswith|[name]->letpattern=tryList.assocnamepatternswithNot_found->errorenv~loc"Unknown pattern '%s'"nameinifparams<>[]thenerrorenv~loc"Unexpected parameters for pattern '%s'"name;pattern|[]->errorenv~loc"Missing pattern name"|_->errorenv~loc"Duplicate pattern names"letrecparse_regionenvp=letloc=p.lexpr_locinmatchp.lexpr_nodewith|PLnamed(name,p)->flushenv;env.name<-Somename;parse_regionenvp|PLapp("\\pattern",names,params)->letpattern=parse_patternenv~locnamesparamsinifenv.pattern<>FREE&&env.pattern<>patternthenerrorenv~loc"Duplicate pattern definition in region"elseenv.pattern<-pattern|_->letpath=parse_lpathenvpinenv.paths<-path::env.pathslettypechecktyping_context_locps=letenv={name=None;declared=[];context=typing_context;pattern=FREE;paths=[];specs=[];}inList.iter(parse_regionenv)ps;letid=!kspecinincrkspec;letspecs=flushenv;env.specsinHashtbl.addregistryidspecs;Ext_idid(* -------------------------------------------------------------------------- *)(* --- Registry --- *)(* -------------------------------------------------------------------------- *)letof_extid=Hashtbl.findregistryletof_extrev=function|{ext_name="region";ext_kind=Ext_idk}->of_extidk|_->raiseNot_foundletof_extensione=List.rev(of_extreve)letof_behaviorbhv=List.fold_left(funacce->List.rev_append(tryof_extrevewithNot_found->[])acc)[]bhv.Cil_types.b_extendedletpp_extensionprinterfmt=function|Ext_idk->letspec=tryHashtbl.findregistrykwithNot_found->[]inignore(List.fold_left(pp_region_specprinter#termfmt)falsespec)|_->()letspecified=letre=Str.regexp_case_fold"region"infunmodel->tryignore(Str.search_forwardremodel0);truewithNot_found->falseletregistered=reffalseletregister()=ifnot!registered&&(Wp.Region.get()||Wp.Region_annot.get()||List.existsspecified(Wp.Model.get()))thenbeginregistered:=true;Acsl_extension.register_behavior"region"typecheck~printer:pp_extensionfalseendlet()=Cmdline.run_after_configuring_stageregister(* -------------------------------------------------------------------------- *)