123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302(**************************************************************************)(* *)(* SPDX-License-Identifier LGPL-2.1 *)(* Copyright (C) *)(* CEA (Commissariat à l'énergie atomique et aux énergies alternatives) *)(* *)(**************************************************************************)openCilopenCil_typesopenLogic_constletconst_oft=Ast_types.add_attributes[("const",[])]tletsize_t()=Globals.Types.find_typeLogic_typing.Typedef"size_t"letprepare_definitionnamefun_type=letvi=Cil.makeGlobalVar~referenced:truenamefun_typeinvi.vdefined<-true;letfd=Cil.emptyFunctionFromVIviinCil.setFormalsDeclvifun_type;fd.sformals<-Cil.getFormalsDeclvi;fdletcall_functionlvalviargs=letloc=Cil_datatype.Location.unknowninlet_,typs,_,_=Cil.splitFunctionTypeVIviinlettyps=Cil.argsToListtypsinletgen_argexp(_,typ,_)=ifCil_datatype.Typ.equalvi.vtypetypthenexpelseCil.mkCast~newt:typexpinletargs=List.map2gen_argargstypsinCall(lval,(Varvi),args,loc)letrecstring_of_typ_auxt=matcht.tnodewith|TVoid->"void"|TIntIBool->"bool"|TIntIChar->"char"|TIntISChar->"schar"|TIntIUChar->"uchar"|TIntIInt->"int"|TIntIUInt->"uint"|TIntIShort->"short"|TIntIUShort->"ushort"|TIntILong->"long"|TIntIULong->"ulong"|TIntILongLong->"llong"|TIntIULongLong->"ullong"|TFloatFFloat->"float"|TFloatFDouble->"double"|TFloatFLongDouble->"ldouble"|TPtrt->"ptr_"^string_of_typt|TEnumei->"e_"^ei.ename|TCompciwhenci.cstruct->"st_"^ci.cname|TCompci->"un_"^ci.cname|TArray(t,Somee)->"arr"^(string_of_expe)^"_"^string_of_typt|_->Options.fatal"unsupported type %a"Cil_printer.pp_typtandstring_of_typt=string_of_typ_aux(Ast_types.unrollt)andstring_of_expe=Format.asprintf"%a"Cil_printer.pp_expeletsize_var?(name_ext="")tvalue={l_var_info=Cil_const.make_logic_var_local("__fc_"^name_ext^"len")t;l_type=Somet;l_tparams=[];l_labels=[];l_profile=[];l_body=LBtermvalue;}(** Features related to terms *)letcvar_to_tvarvi=tvar(cvar_to_lvarvi)lettminus?loct1t2=letminus,typ=matcht1.term_type,t2.term_typewith|Ctype(t1),Ctype(t2)whenAst_types.is_ptrt1&&Ast_types.is_ptrt2->MinusPP,Linteger|Ctype(t),_whenAst_types.is_ptrt->MinusPI,Ctype(t)|t,_->MinusA,tinterm?loc(TBinOp(minus,t1,t2))typlettplus?loct1t2=letplus=matcht1.term_typewith|Ctype(t)whenAst_types.is_ptrt->PlusPI|_->PlusAinterm?loc(TBinOp(plus,t1,t2))t1.term_typelettdivide?loct1t2=term?loc(TBinOp(Div,t1,t2))t1.term_typeletttype_of_pointedt=matchAst_types.unroll_logictwith|Ctype{tnode=TPtrt|TArray(t,_)}->Ctypet|_->Options.fatal"ttype_of_pointed on a non pointer type"lettbuffer_range?locptrlen=letlast=tminus?loclen(tinteger?loc1)inletrange=trange?loc(Some(tinteger?loc0),Somelast)intplus?locptrrangeletrectunref_range?locptrlen=lettyp=ttype_of_pointedptr.term_typeinletrange=tbuffer_range?locptrleninlettlval=(TMemrange),TNoOffsetinlettlval,typ=tunref_range_unfold?loctlvaltypinterm(TLvaltlval)typandtunref_range_unfold?loclvaltyp=matchtypwith|Ctype{tnode=TArray(typ,Somee)}->letlen=Logic_utils.expr_to_term~coerce:trueeinletlast=tminus?loclen(tinteger?loc1)inletrange=trange?loc(Some(tinteger?loc0),Somelast)inletlval=addTermOffsetLval(TIndex(range,TNoOffset))lvalintunref_range_unfoldlval(Ctypetyp)|_->lval,typlettaccess?locptroffset=letget_lval=function|TLval(lval)->lval|_->Options.fatal"unexpected non-lvalue on call to taccess"inmatchAst_types.unroll_logicptr.term_typewith|Ctype{tnode=TPtr_}->letaddress=tplus?locptroffsetinletlval=TLval(TMem(address),TNoOffset)interm?loclval(ttype_of_pointedptr.term_type)|Ctype{tnode=TArray_}->letlval=get_lvalptr.term_nodeinletlval=addTermOffsetLval(TIndex(offset,TNoOffset))lvalinterm?loc(TLvallval)(ttype_of_pointedptr.term_type)|_->Options.fatal"taccess on a non pointer type"letsizeofpointed=function|Ctype{tnode=(TPtrt|TArray(t,_))}->Cil.bytesSizeOft|_->Options.fatal"size_of_pointed on a non pointer type"letsizeof=function|Ctypet->Cil.bytesSizeOft|_->Options.fatal"sizeof on a non C type"lettunref_range_bytes_len?locptrbytes_len=letsizeof=sizeofpointedptr.term_typeinifsizeof=1thentunref_range?locptrbytes_lenelseletsizeof=tinteger?locsizeofinletlen=tdivide?locbytes_lensizeofintunref_range?locptrlen(** Features related to predicates *)letplet_len_div_size?loc?name_exttbytes_lenpred=letsizeof=sizeofpointedtinifsizeof=1thenpredbytes_lenelseletlen=tdivide?locbytes_len(tinteger?locsizeof)inletlen_var=size_var?name_extLintegerleninplet?loclen_var(pred(tvarlen_var.l_var_info))letpgeneric_valid_buffer?locvaliditylblptrlen=letbuffer=tbuffer_range?locptrleninvalidity?loc(lbl,buffer)letpgeneric_valid_len_bytes?locvaliditylblptrbytes_len=plet_len_div_size?locptr.term_typebytes_len(pgeneric_valid_buffer?locvaliditylblptr)letpobject_pointer?loclabelptr=Logic_const.pobject_pointer?loc(label,ptr)letpvalid_len_bytes?loc=pgeneric_valid_len_bytes?locpvalidletpvalid_read_len_bytes?loc=pgeneric_valid_len_bytes?locpvalid_readletpcorrect_len_bytes?loctbytes_len=letsizeof=tinteger?loc(sizeofpointedt)inletmodulo=term?loc(TBinOp(Mod,bytes_len,sizeof))Lintegerinprel?loc(Req,modulo,tinteger?loc0)letpbounds_incl_excl?loclowvalueup=letgeq_0=prel?loc(Rle,low,value)inletlt_len=prel?loc(Rlt,value,up)inpand?loc(geq_0,lt_len)letrecpunfold_all_elems_eq?loct1t2len=assert(Cil_datatype.Logic_type.equalt1.term_typet2.term_type);pall_elems_eq?loc0t1t2lenandpall_elems_eq?locdeptht1t2len=letind=Cil_const.make_logic_var_quant("j"^(string_of_intdepth))Lintegerinlettind=tvarindinletbounds=pbounds_incl_excl?loc(tinteger0)tindleninlett1_acc=taccess?loct1tindinlett2_acc=taccess?loct2tindinleteq=peq_unfold?loc(depth+1)t1_acct2_accinpforall?loc([ind],(pimplies?loc(bounds,eq)))andpeq_unfold?locdeptht1t2=matchAst_types.unroll_logict1.term_typewith|Ctype{tnode=TArray(_,Somelen)}->letlen=Logic_utils.expr_to_term~coerce:trueleninpall_elems_eq?locdeptht1t2len|_->prel?loc(Req,t1,t2)letrecpunfold_all_elems_pred?loct1lenpred=pall_elems_pred?loc0t1lenpredandpall_elems_pred?locdeptht1lenpred=letind=Cil_const.make_logic_var_quant("j"^(string_of_intdepth))Lintegerinlettind=tvarindinletbounds=pbounds_incl_excl?loc(tinteger0)tindleninlett1_acc=taccess?loct1tindinleteq=punfold_pred?locdeptht1_accpredinpforall?loc([ind],(pimplies?loc(bounds,eq)))andpunfold_pred?loc?(dyn_len=None)deptht1pred=matchAst_types.unroll_logict1.term_typewith|Ctype{tnode=TArray(_,opt_len)}->letlen=matchopt_len,dyn_lenwith|Somelen,None->Logic_utils.expr_to_term~coerce:truelen|_,Somelen->len|None,None->Options.fatal"Unfolding array: cannot find a length"inpall_elems_pred?loc(depth+1)t1lenpred|Ctype{tnode=TCompci}->pall_fields_pred?locdeptht1cipred|_->pred?loct1andpall_fields_pred?loc?(flex_mem_len=None)deptht1cipred=leteqdyn_lenfi=letlval=matcht1.term_nodewithTLval(lv)->lv|_->assertfalseinletnlval=addTermOffsetLval(TField(fi,TNoOffset))lvalinletterm=term?loc(TLvalnlval)(Ctypefi.ftype)inpunfold_pred?loc~dyn_lendepthtermpredinletreceqs_fields=function|[]->[]|[x]->[eqflex_mem_lenx]|x::l->letx'=eqNonexinx'::(eqs_fieldsl)inpands(eqs_fields(Option.getci.cfields))letpunfold_flexible_struct_pred?locthe_structbytes_lenpred=letstruct_len=tinteger?loc(sizeofthe_struct.term_type)inletci=matchthe_struct.term_typewith|Ctype({tnode=TCompci}ast)whenCil.has_flexible_array_membert->ci|_->Options.fatal"Unfolding flexible on a non flexible structure"inletflex_type=Ctype(Extlib.last(Option.getci.cfields)).ftypeinletflex_len=tminusbytes_lenstruct_leninletpall_fields_predlen=pall_fields_pred?loc~flex_mem_len:(Somelen)0the_structcipredinplet_len_div_size?loc~name_ext:"flex"flex_typeflex_lenpall_fields_predletpseparated_memories?locp1len1p2len2=letb1=tbuffer_range?locp1len1inletb2=tbuffer_range?locp2len2inpseparated?loc[b1;b2]letmake_behavior?(name=Cil.default_behavior_name)?(assumes=[])?(requires=[])?(ensures=[])?(assigns=WritesAny)?(alloc=FreeAllocAny)?(extension=[])()={b_name=name;b_requires=requires;b_assumes=assumes;b_post_cond=ensures;b_assigns=assigns;b_allocation=alloc;b_extended=extension}letdefault_comp_disjbhvs=letb_names=List.filter(funb->not(String.equalCil.default_behavior_nameb))(List.fold_left(funlb->b.b_name::l)[]bhvs)inmatchb_nameswith|[]->[],[]|_->[b_names],[b_names]letmake_funspecbhvs?(termination=None)?(complete_disjoint=(default_comp_disjbhvs))()=letcomplete,disjoint=complete_disjointin{spec_behavior=bhvs;spec_variant=None;spec_terminates=termination;spec_complete_behaviors=complete;spec_disjoint_behaviors=disjoint}