123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167(**************************************************************************)(* *)(* 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_datatype(*----------------------------------------------------------------------------*)(* Property identification *)(*----------------------------------------------------------------------------*)(** Beside the property identification, it can be found in different contexts
* depending on which part of the computation is involved.
* For instance, properties on loops are split in 2 parts : establishment and
* preservation.
*)typeprop_kind=|PKTactic(** tactical sub-goal *)|PKCheck(** internal check *)|PKProp(** normal property *)|PKEstablished(** computation related to a loop property before the loop. *)|PKPreserved(** computation related to a loop property inside the loop. *)|PKPropLoop(** loop property used as hypothesis inside a loop. *)|PKVarDecr(** computation related to the decreasing of a variant in a loop *)|PKVarPos(** computation related to a loop variant being positive *)|PKVarRel(** computation related to a generalized loop variant *)|PKAFctOut(** computation related to the function assigns on normal termination *)|PKAFctExit(** computation related to the function assigns on exit termination *)|PKTerminates(** computation related to the termination *)|PKDecreases(** computation related to the decreases clause *)|PKSmoke(** expected to fail *)|PKPreofkernel_function*stmt*Property.t(** precondition for function
at stmt, property of the require. Many information that should come
from the p_prop part of the prop_id, but in the PKPre case,
it seems that it is hidden in a IPBlob property ! *)typeprop_id={p_kind:prop_kind;p_prop:Property.t;p_doomed:Property.tlist;(* false-if-reachable props when fired *)p_unreachable:Property.other_loc;(* false-if-reachable location *)p_part:(int*int)option;}letunknown=Property.OLGlobCil_datatype.Location.unknownlettactical~gid=letip="Wp.Tactical."^gidin{p_kind=PKTactic;p_prop=Property.(ip_otheripunknown);p_doomed=[];p_unreachable=unknown;p_part=None}(* -------------------------------------------------------------------------- *)(* --- Category --- *)(* -------------------------------------------------------------------------- *)letparts_of_idp=p.p_partletproperty_of_idp=p.p_propletdoomed_if_validp=p.p_doomedletunreachable_if_validp=p.p_unreachableletmk_partpid(k,n)={pidwithp_part=Some(k,n)}letsource_of_idp=fst(Property.locationp.p_prop)exceptionFoundofintletnum_of_bhv_frombhv(out,_)=matchbhv.b_assignswithWritesAny->Wp_parameters.fatal"no \\from in this behavior ???"|Writesl->letaddn(o,f)=matchfwithFromAny->n|From_->ifLogic_utils.is_same_identified_termoutothenraise(Foundn)elsen+1intrylet_=List.fold_leftadd1linWp_parameters.fatal"didn't found this \\from"withFoundn->n(*----------------------------------------------------------------------------*)(* Constructors *)(*----------------------------------------------------------------------------*)letmk_propkindprop={p_kind=kind;p_prop=prop;p_unreachable=unknown;p_doomed=[];p_part=None}letmk_checkprop=mk_propPKCheckpropletmk_propertyprop=mk_propPKProppropletmk_annot_idkfstmtca=Property.ip_of_code_annot_singlekfstmtcaletmk_annot_idskfstmtca=Property.ip_of_code_annotkfstmtcaletmk_code_annot_idskfsca=List.map(mk_propPKProp)(mk_annot_idskfsca)letmk_assert_idkfsca=mk_propPKProp(mk_annot_idkfsca)letmk_loop_inv_idkfs~establishedca=letkind=ifestablishedthenPKEstablishedelsePKPreservedinmk_propkind(mk_annot_idkfsca)letmk_loop_invkfsca=mk_loop_inv_idkfs~established:trueca,mk_loop_inv_idkfs~established:falsecaletmk_inv_hyp_idkfsca=mk_propPKPropLoop(mk_annot_idkfsca)letmk_var_decr_idkfsca=mk_propPKVarDecr(mk_annot_idkfsca)letmk_var_pos_idkfsca=mk_propPKVarPos(mk_annot_idkfsca)letmk_var_idkfsca=mk_propPKVarRel(mk_annot_idkfsca)letmk_loop_from_idkfscafrom=letid=Property.ip_of_fromkf(Kstmts)(Property.Id_loopca)frominmk_propPKPropLoop(Option.getid)letmk_bhv_from_idkfkiabhvfrom=leta=Datatype.String.Set.of_listainletid=Property.ip_of_fromkfki(Property.Id_contract(a,bhv))frominmk_propPKProp(Option.getid)letget_kind_for_tktkindhas_exit=matchtkindwith|Normal->ifhas_exitthenPKAFctOutelsePKProp|Exits->PKAFctExit|_->assertfalseletmk_fct_from_idkfkf_has_exitbhvtkindfrom=letcontract_info=Property.Id_contract(Datatype.String.Set.empty,bhv)inletid=Property.ip_of_fromkfKglobalcontract_infofrominletkind=get_kind_for_tktkindkf_has_exitinmk_propkind(Option.getid)letmk_disj_bhv_id(kf,ki,active,disj)=mk_propPKProp(Property.ip_of_disjointkfki~activedisj)letmk_compl_bhv_id(kf,ki,active,comp)=mk_propPKProp(Property.ip_of_completekfki~activecomp)letmk_decrease_idkfsx=mk_propPKDecreases(Property.ip_of_decreaseskfsx)letmk_lemma_idl=mk_propPKProp(LogicUsage.ip_lemmal)letmk_stmt_assigns_idkfsactiveba=letactive=Datatype.String.Set.of_listactiveinletb=Property.Id_contract(active,b)inletp=Property.ip_of_assignskf(Kstmts)b(Writesa)inOption.map(mk_propPKProp)pletmk_loop_assigns_idkfscaa=letca=Property.Id_loopcainletp=Property.ip_of_assignskf(Kstmts)ca(Writesa)inOption.map(mk_propPKPropLoop)pletmk_fct_assigns_idkfkf_has_exitbtkinda=letb=Property.Id_contract(Datatype.String.Set.empty,b)inletkind=get_kind_for_tktkindkf_has_exitinletp=Property.ip_of_assignskfKglobalb(Writesa)inOption.map(mk_propkind)pletmk_pre_idkfkibp=mk_propPKProp(Property.ip_of_requireskfkibp)letmk_post_idkfkibp=mk_propPKProp(Property.ip_of_ensureskfkibp)letmk_terminates_idkfkinstrp=mk_propPKTerminates(Property.ip_of_terminateskfkinstrp)letmk_stmt_post_idkfsbp=mk_propPKProp(Property.ip_of_ensureskf(Kstmts)bp)letmk_fct_post_idkfbp=mk_propPKProp(Property.ip_of_ensureskfKglobalbp)letmk_call_pre_idcalled_kfs_callcalled_precalled_pre_p=letkind=PKPre(called_kf,s_call,called_pre)inmk_propkindcalled_pre_pletmk_smokekf~id?(doomed=[])?unreachable()=letoloc=matchunreachablewith|None->Property.OLContractkf|Somestmt->Property.OLStmt(kf,stmt)in{p_kind=PKSmoke;p_prop=Property.ip_other("wp_smoke_"^id)oloc;p_doomed=doomed;p_unreachable=oloc;p_part=None;}(*----------------------------------------------------------------------------*)letkind_order=function|PKProp->0|PKPre_->1|PKEstablished->2|PKPreserved->3|PKVarPos->4|PKVarDecr->5|PKVarRel->6|PKPropLoop->7|PKAFctOut->8|PKAFctExit->9|PKCheck->10|PKTactic->11|PKSmoke->12|PKTerminates->13|PKDecreases->14letcompare_kindk1k2=matchk1,k2withPKPre(kf1,ki1,p1),PKPre(kf2,ki2,p2)->letcmp=Kernel_function.comparekf1kf2inifcmp<>0thencmpelseletcmp=Stmt.compareki1ki2inifcmp<>0thencmpelseProperty.comparep1p2|_,_->Stdlib.compare(kind_orderk1)(kind_orderk2)letcompare_prop_idpid1pid2=(* This order of comparison groups together prop_pids with same properties *)letp1=property_of_idpid1inletp2=property_of_idpid2inletcmp=Description.full_comparep1p2inifcmp<>0thencmpelseletcmp=compare_kindpid2.p_kindpid1.p_kindinifcmp<>0thencmpelseStdlib.comparepid1.p_partpid2.p_partmodulePropIdRaw=Datatype.Make_with_collections(structtypet=prop_idincludeDatatype.Undefinedletname="WpAnnot.prop_id"letreprs=List.mapmk_propertyProperty.reprslethashpid=Property.hashpid.p_propletcompare=compare_prop_idletequalpid1pid2=compare_prop_idpid1pid2=0letcopy=Datatype.undefinedletrehash=Datatype.identityletpretty=Datatype.undefinedletmem_project=Datatype.never_any_projectend)(* -------------------------------------------------------------------------- *)(* --- Lagacy Naming --- *)(* -------------------------------------------------------------------------- *)moduleNameUniquify(D:Datatype.S_with_collections)(S:sigvalname:stringvalbasename:D.t->stringend):sigvalunique_basename:D.t->stringend=structmoduleNamesTbl=State_builder.Hashtbl(Datatype.String.Hashtbl)(Datatype.Int)(structletname=S.name^"Names"letdependencies=[]letsize=97end)moduleIndexTbl=State_builder.Hashtbl(D.Hashtbl)(Datatype.String)(structletname=S.name^"Index"letdependencies=[Ast.self;NamesTbl.self;Globals.Functions.self;Annotations.code_annot_state;Annotations.funspec_state;Annotations.global_state]letsize=97end)(** returns the name that should be returned by the function [get_prop_name_id]
if the given property has [name] as basename. That name is reserved so that
[get_prop_name_id prop] can never return an identical name. *)letreserve_name_idpid=letbasename=S.basenamepidintryletspeed_up_start=NamesTbl.findbasenamein(* this basename is already reserved *)letn,unique_name=Extlib.make_unique_nameNamesTbl.mem~sep:"_"~start:speed_up_startbasenameinNamesTbl.replacebasename(succn);(* to speed up Extlib.make_unique_name for next time *)unique_namewithNot_found->(* first time that basename is reserved *)NamesTbl.addbasename2;basename(** returns a unique name identifying the property.
This name is built from the basename of the property. *)letunique_basenamepid=tryIndexTbl.findpidwithNot_found->(* first time we are asking for a name for that [ip] *)letunique_name=reserve_name_idpidinIndexTbl.addpidunique_name;unique_nameend(* -------------------------------------------------------------------------- *)(* --- Naming Properties --- *)(* -------------------------------------------------------------------------- *)moduleNames:sigvalget_prop_id_name:prop_id->stringend=struct(** Uniquify the first part of the prop_id *)moduleUniquify1=NameUniquify(Property)(structletname="Wp.WpPropId.Names."letbasenameip=lettruncate=max20(Wp_parameters.TruncPropIdFileName.get())inProperty.Names.get_prop_basename~truncateipend)letget_ipip=Uniquify1.unique_basenameip(** Uniquify call-site for precondition check. So
that precondition of the same call-site are grouped *)moduleCallSite=Datatype.Triple_with_collections(Kernel_function)(Kernel_function)(Stmt)(structletmodule_name="Wp.WpPropId.CallSite"end)moduleUniquify_Stmt=NameUniquify(CallSite)(structletname="Wp.WpPropId.Names3."letbasename(caller_kf,callee_kf,_stmt)=(Kernel_function.get_namecaller_kf)^"_call_"^(Kernel_function.get_namecallee_kf)end)letget_prop_id_basep=matchp.p_kind,p.p_propwith|PKEstablished,p->get_ipp^"_established"|PKPreserved,p->get_ipp^"_preserved"|PKVarDecr,p->get_ipp^"_decrease"|PKVarPos,p->get_ipp^"_positive"|PKVarRel,p->get_ipp^"_relation"|PKAFctOut,p->get_ipp^"_normal"|PKAFctExit,p->get_ipp^"_exit"|PKPre(callee_kf,stmt,pre),_->letcaller_kf=Kernel_function.find_englobing_kfstmtinletcall_string=Uniquify_Stmt.unique_basename(caller_kf,callee_kf,stmt)in(* remove name of callee kernel function given by get_ip *)letip_string=get_ippreinletip_string=Option.value~default:ip_string(Extlib.string_del_prefix((Kernel_function.get_namecallee_kf)^"_")ip_string)incall_string^"_"^ip_string|_,p->get_ippletget_prop_id_basenamep=letbasename=get_prop_id_basepinmatchp.p_partwith|None->basename|Some(k,n)->ifn<10thenPrintf.sprintf"%s_part%d"basename(succk)elseifn<100thenPrintf.sprintf"%s_part%02d"basename(succk)elseifn<1000thenPrintf.sprintf"%s_part%03d"basename(succk)elsePrintf.sprintf"%s_part%06d"basename(succk)moduleUniquify2=NameUniquify(PropIdRaw)(structletname="Wp.WpPropId.Names2."letbasename=get_prop_id_basenameend)letget_prop_id_namep=Uniquify2.unique_basenamepend(* -------------------------------------------------------------------------- *)(* --- Naming Accessors --- *)(* -------------------------------------------------------------------------- *)letget_propid=Names.get_prop_id_name(** Name related to a property PO *)letpp_propidfmtpid=Format.pp_print_stringfmt(get_propidpid)letpp_namesfmtl=letl=Datatype.String.Set.elementslinmatchlwith|[]->()|_->Format.fprintffmt"_%a"(Wp_error.pp_string_list~empty:""~sep:"_")lletident_namesnames=List.filter(function""->true|_asn->'\"'<>(String.getn0))namesletuser_pred_namesp=letp_names=ident_namesp.tp_statement.pred_nameinifp.tp_kind=Checkthen"@check"::p_nameselsep_namesletcode_annot_namesca=matchca.annot_contentwith|AAssert(_,pred)->"@assert"::user_pred_namespred|AInvariant(_,_,pred)->"@invariant"::user_pred_namespred|AVariant(term,_)->"@variant"::(ident_namesterm.term_name)|AExtended(_,_,{ext_name})->[Printf.sprintf"@%s"ext_name]|_->[](* TODO : add some more names ? *)(** This is used to give the name of the property that the user can give
* to select it from the command line (-wp-prop option) *)letuser_prop_namesp=letopenPropertyinmatchpwith|IPPredicate{ip_kind;ip_pred}->Format.asprintf"@@%a"Property.pretty_predicate_kindip_kind::user_pred_namesip_pred.ip_content|IPExtended{ie_ext={ext_name}}->[Printf.sprintf"@%s"ext_name]|IPCodeAnnot{ica_ca}->code_annot_namesica_ca|IPComplete{ic_bhvs}->letkind_name="@complete_behaviors"inletname=Format.asprintf"complete_behaviors%a"pp_namesic_bhvsinkind_name::[name]|IPDisjoint{ic_bhvs}->letkind_name="@disjoint_behaviors"inletname=Format.asprintf"disjoint_behaviors%a"pp_namesic_bhvsinkind_name::[name]|IPAssigns{ias_froms}->List.fold_left(funacc(t,_)->(ident_namest.it_content.term_name)@acc)["@assigns"]ias_froms|IPDecrease{id_ca=Someca}->"@decreases"::code_annot_namesca|IPDecrease_->["@decreases"]|IPLemma{il_name=a;il_pred=l}->letnames="@lemma"::a::user_pred_nameslinbeginmatchLogicUsage.section_of_lemmaawith|LogicUsage.Toplevel_->names|LogicUsage.Axiomaticax->ax.LogicUsage.ax_name::namesend(* TODO *)|IPFrom_|IPAllocation_|IPAxiomatic_|IPBehavior_|IPReachable_|IPPropertyInstance_|IPTypeInvariant_|IPGlobalInvariant_|IPOther_->[]letuser_bhv_namesp=letopenPropertyinletfors=matchpwith|Property.IPCodeAnnot{ica_ca}->letfors=matchica_ca.annot_contentwith|Cil_types.AAssert(fors,_)|Cil_types.AStmtSpec(fors,_)|Cil_types.AInvariant(fors,_,_)|Cil_types.AAssigns(fors,_)|Cil_types.AAllocation(fors,_)|Cil_types.AExtended(fors,_,_)->fors|_->[]infors|_->[]inOption.fold~none:fors~some:(funb->b.b_name::fors)(get_behaviorp)letstring_of_termination_kind=functionNormal->"ensures"|Exits->"exits"|Breaks->"breaks"|Continues->"continues"|Returns->"returns"letlabel_of_kind=function|PKTactic->"Tactic"|PKSmoke->"Smoke-test"|PKCheck->"Check"|PKProp->"Property"|PKPropLoop->"Invariant"(* should be assert false ??? *)|PKEstablished->"Establishment"|PKPreserved->"Preservation"|PKVarDecr->"Decreasing"|PKVarPos->"Positive"|PKVarRel->"Relation"|PKAFctOut->"Function assigns"|PKAFctExit->"Exit assigns"|PKTerminates->"Terminates"|PKDecreases->"Decreases"|PKPre(kf,_,_)->Printf.sprintf"Precondition for '%s'"(Kernel_function.get_namekf)letlabel_of_prop_idp=matchp.p_partwith|None->label_of_kindp.p_kind|Some(k,n)->Printf.sprintf"%s (%d/%d)"(label_of_kindp.p_kind)(succk)nmodulePretty=structopenFormatletpp_partfmtp=matchp.p_partwith|None->()|Some(k,n)->fprintffmt" (%d/%d)"(succk)nletpp_subpropfmtp=matchp.p_kindwith|PKProp|PKTactic|PKCheck|PKPropLoop|PKSmoke|PKTerminates|PKDecreases->()|PKEstablished->pp_print_stringfmt" (established)"|PKPreserved->pp_print_stringfmt" (preserved)"|PKVarDecr->pp_print_stringfmt" (decrease)"|PKVarPos->pp_print_stringfmt" (positive)"|PKVarRel->pp_print_stringfmt" (relation)"|PKAFctOut->pp_print_stringfmt" (return)"|PKAFctExit->pp_print_stringfmt" (exit)"|PKPre(kf,_,_)->fprintffmt" (call '%s')"(Kernel_function.get_namekf)letpp_propfmtp=Description.pp_localized~kf:`Never~ki:false~kloc:falsefmtp.p_propletpp_localfmtp=beginpp_propfmtp;pp_subpropfmtp;pp_partfmtp;endendletpretty_local=Pretty.pp_local(* -------------------------------------------------------------------------- *)(* --- Datatype --- *)(* -------------------------------------------------------------------------- *)modulePropId=structincludePropIdRawletpretty=pp_propidend(* -------------------------------------------------------------------------- *)(* --- Hints --- *)(* -------------------------------------------------------------------------- *)typehints={mutablerequired:stringlist;mutablehints:stringlist;}letadd_hinthsx=ifnot(List.memxhs.hints)thenhs.hints<-x::hs.hintsletadd_requiredhsx=ifnot(List.memxhs.required)thenhs.required<-x::hs.requiredletstmt_hintshss=List.iter(funlabel->matchlabelwith|Label(a,_,src)->ifsrcthenadd_hinthsa|Default_->add_hinths"default"|Case(e,_)->matchCtypes.get_int64ewith|Somek->add_hinths("case-"^Int64.to_stringk)|None->())s.labelsletkinstr_hintshs=function|Kstmts->stmt_hintshss|Kglobal->()letpropid_hintshsp=letopenPropertyinmatchp.p_kind,p.p_propwith|PKCheck,_->()|PKSmoke,_->add_requiredhs"smoke-test"|PKProp,IPAssigns{ias_kinstr=Kstmt_}->add_requiredhs"stmt-assigns"|PKProp,IPAssigns{ias_kinstr=Kglobal}->add_requiredhs"fct-assigns"|PKPropLoop,Property.IPAssigns_->add_requiredhs"loop-assigns"|PKPropLoop,_->add_requiredhs"invariant"|PKProp,_->add_requiredhs"property"|PKTactic,_->add_requiredhs"tactic"|PKEstablished,_->add_requiredhs"established"|PKPreserved,_->add_requiredhs"preserved"|PKVarDecr,_->add_requiredhs"decrease"|PKVarPos,_->add_requiredhs"positive"|PKVarRel,_->add_requiredhs"relation"|PKAFctOut,_->add_requiredhs"return"|PKAFctExit,_->add_requiredhs"exit"|PKTerminates,_->add_requiredhs"terminates"|PKDecreases,_->add_requiredhs"decreases"|PKPre(kf,st,_),_->add_requiredhs("precond-"^Kernel_function.get_namekf);stmt_hintshsstletrecterm_hintshst=matcht.term_nodewith|TLval(lv,_)->lval_hintshslv|TAddrOf(lv,_)->lval_hintshslv|TCastE(_,t)->term_hintshst|TBinOp((PlusPI|MinusPI),a,_)->term_hintshsa|Tlet(_,t)->term_hintshst|_->()andlval_hintshs=function|TVar{lv_origin=Some{vorig_name=x}}|TVar{lv_name=x}->add_hinthsx|TResult_->add_hinths"result"|TMemt->add_hinths"*";term_hintshstletassigns_hintshsfroms=List.iter(fun({it_content=t},_)->term_hintshst)fromsletannot_hintshs=function|AAssert(bs,ipred)|AInvariant(bs,_,ipred)->List.iter(add_hinths)(ident_namesipred.tp_statement.pred_name);List.iter(add_hinths)bs|AAssigns(bs,Writesfroms)->List.iter(add_hinths)bs;assigns_hintshsfroms|AAllocation_|AAssigns(_,WritesAny)|AStmtSpec_|AVariant_|APragma_|AExtended_->()letproperty_hintshs=letopenPropertyinfunction|IPLemma{il_name;il_pred}->List.iter(add_requiredhs)(il_name::il_pred.tp_statement.pred_name)|IPBehavior_->()|IPComplete{ic_bhvs}|IPDisjoint{ic_bhvs}->Datatype.String.Set.iter(add_requiredhs)ic_bhvs|IPPredicate{ip_pred}->List.iter(add_hinths)ip_pred.ip_content.tp_statement.pred_name|IPExtended{ie_ext={ext_name}}->List.iter(add_hinths)[ext_name]|IPCodeAnnot{ica_ca}->annot_hintshsica_ca.annot_content|IPAssigns{ias_froms}->assigns_hintshsias_froms|IPAllocation_(* TODO *)|IPFrom_|Property.IPDecrease_|Property.IPPropertyInstance_|IPReachable_|Property.IPAxiomatic_|Property.IPOther_|IPTypeInvariant_|Property.IPGlobalInvariant_->()letprop_id_keysp=beginleths={hints=[];required=[]}inletoptaddf=functionNone->()|Somex->addhs(fx)inpropid_hintshsp;property_hintshsp.p_prop;optadd_requiredKernel_function.get_name(Property.get_kfp.p_prop);optadd_required(funb->ifCil.is_default_behaviorbthen"default"elseb.b_name)(Property.get_behaviorp.p_prop);optadd_hint(fun(k,_)->Printf.sprintf"part-%d"k)p.p_part;kinstr_hintshs(Property.get_kinstrp.p_prop);List.sortString.comparehs.required,List.sortString.comparehs.hintsend(*----------------------------------------------------------------------------*)(* Pretty-Print *)(*----------------------------------------------------------------------------*)letpp_goal_kindfmt=function|PKTactic|PKSmoke|PKCheck|PKProp|PKPropLoop|PKAFctOut|PKAFctExit|PKTerminates|PKDecreases|PKPre_->()|PKEstablished->Format.pp_print_stringfmt"Establishment of "|PKPreserved->Format.pp_print_stringfmt"Preservation of "|PKVarDecr->Format.pp_print_stringfmt"Decreasing of "|PKVarPos->Format.pp_print_stringfmt"Positivity of "|PKVarRel->Format.pp_print_stringfmt"Follows relation "letpp_goal_partfmt=function|None->()|Some(k,n)->Format.fprintffmt" (%d/%d)"(succk)nletprettyfmtpid=beginpp_goal_kindfmtpid.p_kind;Description.pp_propertyfmtpid.p_prop;pp_goal_partfmtpid.p_part;endletpretty_contextkffmtpid=beginpp_goal_kindfmtpid.p_kind;Description.pp_localized~kf~ki:true~kloc:truefmtpid.p_prop;pp_goal_partfmtpid.p_part;end(*----------------------------------------------------------------------------*)(* Comparison *)(*----------------------------------------------------------------------------*)letis_checkp=p.p_kind=PKCheckletis_tacticp=p.p_kind=PKTacticletis_smoke_testp=p.p_kind=PKSmokeletis_assignsp=matchproperty_of_idpwith|Property.IPAssigns_->true|_->falseletis_requires=letopenPropertyinfunction|IPPredicate{ip_kind=PKRequires_}->true|_->falseletis_loop_preservationp=matchp.p_kindwith|PKPreserved->beginmatchProperty.get_kinstrp.p_propwith|Kglobal->Wp_parameters.fatal"Loop Preservation ? (%a)"Property.prettyp.p_prop|Kstmtst->Somestend|_->Noneletuser_prop_pidpid=letp_prop=matchpid.p_kindwith|PKPre(_,_,p_prop)->p_prop|_->property_of_idpidinletnames=user_prop_namesp_propinmatchProperty.get_kfp_propwith|None->names|Somekf->Kernel_function.get_namekf::namesletselect_defaultpid=letnames=user_prop_pidpidinnot(List.mem"no_wp"names)letare_selected_namesaskednames=ifList.mem"no_wp"namesthenfalseelseletis_minuss=trys.[0]='-'with_->falseinletis_pluss=trys.[0]='+'with_->falseinletremove_firsts=String.subs1((String.lengths)-1)inletevalaccasked=letis_minus,a=matchaccwith|None->ifis_minusaskedthentrue,trueelsefalse,false|Somea->(is_minusasked),ainleteval()=letasked=ifis_minus||(is_plusasked)thenremove_firstaskedelseaskedinList.memaskednamesinSome(ifis_minusthena&&(not(eval()))elsea||(eval()))inmatchList.fold_leftevalNoneaskedwith|Somefalse->false|_->trueletselect_by_nameasked_namespid=letnames=user_prop_pidpidinare_selected_namesasked_namesnamesletselect_for_behaviorsbhvspid=letfors=Property.get_for_behaviors@@property_of_idpidinList.exists(funb->List.membfors)bhvsletselect_call_pres_callasked_prepid=matchpid.p_kindwith|PKPre(_,p_stmt,p_prop)->Stmt.equals_callp_stmt&&(matchasked_prewith|None->true|Someasked_pre->Property.equalp_propasked_pre)|_->false(*----------------------------------------------------------------------------*)(* About assigns identification *)(*----------------------------------------------------------------------------*)typea_kind=LoopAssigns|StmtAssignstypeassigns_desc={a_label:Clabels.c_label;a_stmt:Cil_types.stmtoption;a_kind:a_kind;a_assigns:Cil_types.assigns;}letmk_asm_assigns_descs={a_label=Clabels.stmts;a_stmt=Somes;a_kind=StmtAssigns;a_assigns=WritesAny;}letmk_loop_assigns_descsassigns={a_label=Clabels.stmts;a_stmt=Somes;a_kind=LoopAssigns;a_assigns=Writesassigns}letmk_stmt_assigns_descsassigns={a_label=Clabels.stmts;a_stmt=Somes;a_kind=StmtAssigns;a_assigns=Writesassigns;}letmk_stmt_assigns_any_descs={a_label=Clabels.stmts;a_stmt=Somes;a_kind=StmtAssigns;a_assigns=WritesAny;}letmk_init_assigns={a_label=Clabels.init;a_stmt=None;a_kind=StmtAssigns;a_assigns=WritesAny;}(*
(** kf assigns for normal path when there is an exit path *)
let mk_fout_assigns_desc assigns = {
a_label = Logic_const.pre_label ;
(* a_fun = Assigns_FctOut ; *)
a_kind = StmtAssigns ;
a_assigns = Writes assigns ;
}
(** kf assigns for exit path *)
let mk_exit_assigns_desc assigns = {
a_label = Logic_const.pre_label ;
(* a_fun = Assigns_FctExit ; *)
a_kind = StmtAssigns ;
a_assigns = Writes assigns ;
}
*)letmk_kf_assigns_descassigns={a_label=Clabels.pre;a_stmt=None;a_kind=StmtAssigns;a_assigns=Writesassigns;}letis_call_assigns=function|{a_stmt=Some{skind=Instr(Call_|Local_init(_,ConsInit_,_))}}->true|_->falseletpp_assigns_descfmta=Wp_error.pp_assignsfmta.a_assigns(*----------------------------------------------------------------------------*)(**
* 2 kinds of annotations can be found : predicates and assigns.
* because assigns properties can only be translated into predicates
* by the memory model.
* - Assigns properties are composed of the assigns list from Cil,
* and a label to know where to stop.
* - Predicates are just the predicate type from Cil.
*)(*----------------------------------------------------------------------------*)typepred_info=prop_id*Cil_types.predicatetypevariant_info=prop_id*Cil_types.variantletmk_pred_infoidp=(id,p)letpred_info_id(id,_)=idletpp_pred_of_pred_infofmt(_id,p)=Printer.pp_predicatefmtpletpp_pred_infofmt(id,p)=Format.fprintffmt"(@[%a:@ %a@])"pp_propididPrinter.pp_predicateptypeassigns_info=prop_id*assigns_descletassigns_info_id(id,_)=idtypeassigns_full_info=AssignsLocationsofassigns_info|AssignsAnyofassigns_desc|NoAssignsInfoletempty_assigns_info=NoAssignsInfoletmk_assigns_infoida=AssignsLocations(id,a)letmk_stmt_any_assigns_infos=leta={a_label=Clabels.stmts;a_stmt=Somes;a_kind=StmtAssigns;a_assigns=WritesAny;}inAssignsAnyaletmk_kf_any_assigns_info()=leta={a_label=Clabels.pre;a_stmt=None;a_kind=StmtAssigns;a_assigns=WritesAny;}inAssignsAnyaletmk_loop_any_assigns_infos=leta={a_label=Clabels.stmts;a_stmt=Somes;a_kind=LoopAssigns;a_assigns=WritesAny;}inAssignsAnya(* let pp_assigns_id (id, _a) = pp_propid id *)letpp_assign_infokfmta=matchawith|NoAssignsInfo->()|AssignsAnya->letpkind=matcha.a_kindwith|StmtAssigns->""|LoopAssigns->"loop"inFormat.fprintffmt"%s(@@%a): %s assigns everything@."kClabels.prettya.a_labelpkind|AssignsLocations(_,a)->Format.fprintffmt"%s(@@%a): %a@."kClabels.prettya.a_labelpp_assigns_descaletmerge_assign_infoa1a2=matcha1,a2with|NoAssignsInfo,a|a,NoAssignsInfo->a|(AssignsLocations_|AssignsAny_),(AssignsLocations_|AssignsAny_)->Wp_parameters.fatal"Several assigns ?"(* -------------------------------------------------------------------------- *)(* --- Axioms --- *)(* -------------------------------------------------------------------------- *)typeaxiom_info=prop_id*LogicUsage.logic_lemmaletmk_axiom_infolemma=letid=mk_lemma_idlemmain(id,lemma)letpp_axiom_infofmt(id,thm)=Format.fprintffmt"(@[%a:@ %a@])"pp_propididPrinter.pp_predicatethm.LogicUsage.lem_predicate.tp_statement(* -------------------------------------------------------------------------- *)(* --- Prop Splitter --- *)(* -------------------------------------------------------------------------- *)(* prop-id splitter *)letsplit_bagjobpidgoals=letn=Bag.lengthgoalsinifn<=1thenBag.iter(jobpid)goalselseletk=ref0inBag.iter(fung->letpid_k=mk_partpid(!k,n)inincrk;jobpid_kg)goalsletsplit_mapfpidgs=letn=List.lengthgsinifn<=1thenList.map(fpid)gselseletk=ref0inList.map(fung->letpid_k=mk_partpid(!k,n)inincrk;fpid_kg)gs(*----------------------------------------------------------------------------*)(** About proofs *)(*----------------------------------------------------------------------------*)letsubproofsid=matchid.p_kindwith|PKCheck->0|PKProp|PKSmoke|PKTactic|PKPre_|PKPropLoop|PKTerminates|PKDecreases|PKVarRel->1|PKEstablished|PKPreserved|PKVarDecr|PKVarPos|PKAFctExit|PKAFctOut->2letsubproof_idxid=matchid.p_kindwith|PKCheck->(-1)(* 0/0 *)|PKProp|PKTactic|PKPre_|PKSmoke|PKPropLoop|PKTerminates|PKDecreases|PKVarRel->0(* 1/1 *)|PKPreserved->0(* 1/2 *)|PKEstablished->1(* 2/2 *)|PKVarDecr->0(* 1/2 *)|PKVarPos->1(* 2/2 *)|PKAFctOut->0(* 1/2 *)|PKAFctExit->1(* 2/2 *)(** find the outer loop in which the stmt is. *)letget_loop_stmtkfstmt=(* because we don't have the cfg here, we can only use Cil information,
* and then we can only recognize syntactic loops... TODO: use the cfg ? *)letrecis_in_blkb=List.existsis_in_stmtb.bstmtsandis_in_stmts=ifs.sid=stmt.sidthentrueelsematchs.skindwith|If(_,b1,b2,_)->is_in_blkb1||is_in_blkb2|Switch(_,b,_,_)|Blockb->is_in_blkb|UnspecifiedSequenceseq->letb=Cil.block_from_unspecified_sequenceseqinis_in_blkb|Loop(_,b,_,_,_)->is_in_blkb|_->falseandfind_loop_in_blkblk=find_loop_in_stmtsblk.bstmtsandfind_loop_in_stmtsl=matchlwith|[]->None|s::tl->(matchfind_loop_in_stmtswithSomel->Somel|None->find_loop_in_stmtstl)andfind_loop_in_stmts=matchs.skindwith|(Loop_)->ifis_in_stmtsthenSomeselseNone|If(_,b1,b2,_)->(matchfind_loop_in_blkb1withSomel->Somel|None->find_loop_in_blkb2)|Switch(_,b,_,_)|Blockb->find_loop_in_blkb|UnspecifiedSequenceseq->letb=Cil.block_from_unspecified_sequenceseqinfind_loop_in_blkb|_->Noneinletf=Kernel_function.get_definitionkfinfind_loop_in_blkf.sbody(** Quite don't understand what is going on here... what is it supposed to do ?
* [2011-07-07-Anne] *)letget_inductionp=letget_stmt=letopenPropertyinfunction|IPDecrease{id_kf;id_kinstr=Kstmtstmt}->Some(id_kf,stmt)|IPCodeAnnot{ica_kf;ica_stmt}->Some(ica_kf,ica_stmt)|IPAssigns{ias_kf;ias_kinstr=Kstmtstmt}->Some(ias_kf,stmt)|_->Noneinmatchp.p_kindwith|PKCheck|PKSmoke|PKAFctOut|PKAFctExit|PKPre_|PKTactic|PKTerminates|PKDecreases->None|PKProp->letloop_stmt_opt=matchget_stmt(property_of_idp)with|None->None|Some(kf,s)->get_loop_stmtkfsinloop_stmt_opt|PKPropLoop->letopenPropertyinletloop_stmt_opt=matchproperty_of_idpwith|IPCodeAnnot{ica_kf;ica_stmt;ica_ca={annot_content=AInvariant(_,loop,_)}}->ifloopthen(*loop invariant *)Someica_stmtelse(* invariant inside loop *)get_loop_stmtica_kfica_stmt|IPAssigns{ias_kinstr=Kstmtstmt;ias_bhv=Id_loop_}->(* loop assigns *)Somestmt|_->None(* assert false ??? *)inloop_stmt_opt|PKEstablished|PKVarDecr|PKVarPos|PKVarRel|PKPreserved->(matchget_stmt(property_of_idp)with|None->None|Some(_,s)->Somes)(* -------------------------------------------------------------------------- *)(* --- Filter according to status --- *)(* -------------------------------------------------------------------------- *)letfilter_statuspid=Wp_parameters.StatusAll.get()||beginletmoduleC=Property_status.ConsolidationinmatchC.get(property_of_idpid)with|C.Never_tried->true|C.Considered_valid|C.Inconsistent_->false|C.Valid_|C.Valid_under_hyp_|C.Invalid_but_dead_|C.Valid_but_dead_|C.Unknown_but_dead_->Wp_parameters.StatusTrue.get()|C.Unknown_->Wp_parameters.StatusMaybe.get()|C.Invalid_|C.Invalid_under_hyp_->Wp_parameters.StatusFalse.get()end(*----------------------------------------------------------------------------*)(* Proofs Management *)(*----------------------------------------------------------------------------*)typeproof={target:Property.t;proved:proofpartarray;mutableinvalid:bool;mutabledependencies:Property.Set.t;}andproofpart=|Noproof|Complete|PartsofBitvector.tlettargetp=p.targetletdependenciesp=Property.Set.elements(Property.Set.removep.targetp.dependencies)letcreate_proofip=letn=subproofsipin{target=property_of_idip;proved=Array.makenNoproof;dependencies=Property.Set.empty;invalid=false;}letadd_proofpfiphs=beginifnot(Property.equal(property_of_idip)pf.target)thenWp_parameters.fatal"Partial proof inconsistency";List.iter(funiph->ifnot(is_requiresiph)thenpf.dependencies<-Property.Set.addiphpf.dependencies)hs;letk=subproof_idxipinmatchparts_of_idipwith|None->pf.proved.(k)<-Complete|Some(p,n)->matchpf.proved.(k)with|Complete->()|Noproof->letbv=Bitvector.createninBitvector.set_rangebv0(p-1);Bitvector.set_rangebv(p+1)(n-1);pf.proved.(k)<-Partsbv|Partsbv->Bitvector.clearbvp;ifBitvector.is_emptybvthenpf.proved.(k)<-Completeendletadd_invalid_proofpf=pf.invalid<-trueletis_composedpf=Array.lengthpf.proved>1letis_provedpf=Array.for_all(functionComplete->true|_->false)pf.provedletis_invalidpf=pf.invalid&¬(is_provedpf)(* -------------------------------------------------------------------------- *)