12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169(**************************************************************************)(* *)(* This file is part of WP plug-in of Frama-C. *)(* *)(* Copyright (C) 2007-2024 *)(* 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_|IPModule_|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|TCast(false,Ctype_,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_|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_|IPDecrease_|IPPropertyInstance_|IPReachable_|IPAxiomatic_|IPModule_|IPOther_|IPTypeInvariant_|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_propinletnames=ifis_smoke_testpidthen"smoke"::nameselsenamesinmatchProperty.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)(* -------------------------------------------------------------------------- *)