Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file meta_bindings.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231(**************************************************************************)(* *)(* This file is part of the Frama-C's MetACSL plug-in. *)(* *)(* Copyright (C) 2018-2024 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* 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 LICENSE) *)(* *)(**************************************************************************)openMeta_optionsopenMeta_utilsopenLogic_ptreeopenLogic_typingopenCil_types(* Gathered bindings *)lettypes=Str_Hashtbl.create5letsetnamebase=base^"_set"letsizenamebase=base^"_size"letcapnamebase=base^"_capacity"(* Replace \bound(name) by name_set[name_i] where name_i is a newly created
* quantified logic variable, which is remembered in the 'quantifiers' table to
* close the predicate at the end (see after_parse)
*)letparse_boundtclocquantifiersbn=matchbn.lexpr_nodewith|PLvarbname->letcontent_type=beginmatchStr_Hashtbl.find_opttypesbnamewith|Somex->x|None->tc.errorloc"The name '%s' is used but not bound anywhere"bnameendinlettabvar=tc.find_var(setnamebname)inletquantvar=beginmatchStr_Hashtbl.find_optquantifiersbnamewith|Somex->x|None->letres=Cil_const.make_logic_var_quant(bname^"_i")LintegerinStr_Hashtbl.addquantifiersbnameres;resendinlettlv=(TVartabvar,TIndex(Logic_const.tvarquantvar,TNoOffset))inLogic_const.term(TLvaltlv)content_type|_->tc.errorloc"Expecting a simple variable name for \\bound"(* Replace a \bind(val, name) by the pair associating the actual C variable
to the name. Used afterwards at the end of the translation process.
*)letparse_bindtcloccvar_namegvar_name=letcvar=tc.find_varcvar_nameinletbdg_type=beginmatchcvar.lv_typewith|Ctype_aslt->lt|_->tc.errorloc"Only C variables can be bound to names"endinbeginmatchStr_Hashtbl.find_opttypesgvar_namewith|None->Str_Hashtbl.addtypesgvar_namebdg_type|Someold_type->ifnot@@Logic_utils.is_same_typebdg_typeold_typethentc.errorloc"The name %s was previously bound with variables of type %a \
but now you are trying to bind it with a variable of type %a"gvar_namePrinter.pp_logic_typeold_typePrinter.pp_logic_typebdg_typeend;letcvar_term=Logic_const.tvarcvarinletname_term=Logic_const.term(TConst(LStrgvar_name))(CtypeCil_const.charPtrType)inExt_terms[cvar_term;name_term](* Called by the delayed parser for each predicate
* quanthash is a hash table with a pair for each \bound(val, name) associating
* 'name' with the quantified logic_variable used to replace bound.
* The predicate is closed with universal quantification on each of these
* variables, with a proper interval 0 <= quant < name_size
*)letafter_parsetcpredquanthash=letopenLogic_constinletquantifiers=Str_Hashtbl.fold(fun_->List.cons)quanthash[]inletconditions=Str_Hashtbl.fold(funnamevarconds->letmainterm=tvarvarinletsizeterm=tc.find_var(sizenamename)|>tvarinletsupzero=prel(Rle,tinteger0,mainterm)inletinfmax=prel(Rlt,mainterm,sizeterm)insupzero::infmax::conds)quanthash[]inletwith_cond=pimplies(pandsconditions,pred)inpforall(quantifiers,with_cond)letext_flags=refNone(* to_add maps sids to statements that must be inserted before the
* corresponding statements *)letto_add=Stmt_Hashtbl.create5(* Toggles the inline visitor *)letvisit_inline=reffalse(* Add ghost code needed for bindings, i.e. declarations of name_set/size and
* their modification when encountering \binds *)letadd_ghost_codeflags=ext_flags:=Someflags;visit_inline:=true;letf=Ast.get()inletunkloc=Cil_datatype.Location.unknownin(* Declare _set and _size global variables *)letmake_globalnametyp=letbase_type=Logic_utils.logicCTypetypin(* The _set is either a fixed array or a pointer *)letctype=matchflags.static_bindingswith|Somen->TArray(base_type,Some(Cil.integer~loc:unklocn),[])|None->TPtr(base_type,[])inletvar=Cil.makeGlobalVar(setnamename)ctypeinletsvar=Cil.makeGlobalVar(sizenamename)Cil_const.uintTypeinvar.vghost<-true;svar.vghost<-true;letsinit={init=Some(Cil.makeZeroInit~loc:unklocCil_const.uintType)}inGlobals.Vars.add_declvar;Globals.Vars.addsvarsinit;letpre=[GVarDecl(var,unkloc);GVar(svar,sinit,unkloc)]inmatchflags.static_bindingswith|Some_->pre|None->(* For dynamic arrays, add a capacity variable *)letcvar=Cil.makeGlobalVar(capnamename)Cil_const.uintTypeincvar.vghost<-true;Globals.Vars.addcvarsinit;GVar(cvar,sinit,unkloc)::preinletglobs=Str_Hashtbl.fold(funabc->(make_globalab)@c)types[]inf.globals<-globs@f.globals;(* Visit the file, resetting to_add when encoutering a function (since sids
* are unique only within a function) and inserting values of to_add in
* correct blocks
*)letchanged_funcs=refFundec_Set.emptyinletmark_changedf=changed_funcs:=Fundec_Set.addf!changed_funcsinletvis=object(self)inheritVisitor.frama_c_inplacemethod!vblock_=Cil.DoChildrenPost(funblock->letrecaux=function|[]->[]|s::t->letaux_stmt=find_hash_listStmt_Hashtbl.find_optto_addsinifaux_stmt<>[]thenmark_changed(Option.getself#current_func);aux_stmt@[s]@(auxt)inblock.bstmts<-auxblock.bstmts;block)method!vfunc_=Stmt_Hashtbl.clearto_add;Cil.DoChildrenendinVisitor.visitFramacFilevisf;ifnot(Fundec_Set.is_empty!changed_funcs)thenbeginletreinit_cfgf=Cfg.clearCFGinfo~clear_id:falsef;Cfg.cfgFunfinFundec_Set.iterreinit_cfg!changed_funcs;Ast.mark_as_changed()endletsearch_global_varname=Globals.Vars.find_from_astinfonameGlobal(* Replace \binds by code adequately modifying _set and _size *)letmake_static_modif_codenamelvar=letunkloc=Cil_datatype.Location.unknowninlettabvar=search_global_var(setnamename)inletsizevar=search_global_var(sizenamename)inList.rev[(lettabcell=(Vartabvar,Index(Cil.evarsizevar,NoOffset))inletvalue=Option.getlvar.lv_origin|>Cil.evarinCil.mkStmtOneInstr~ghost:true(Set(tabcell,value,unkloc)));(letincrexp=Cil.increm(Cil.evarsizevar)1inCil.mkStmtOneInstr~ghost:true(Set(Cil.varsizevar,increxp,unkloc)))](* Dynamic version *)letmake_dynamic_modif_codenamelvar=letunkloc=Cil_datatype.Location.unknowninlettabvar=search_global_var(setnamename)inletsizevar=search_global_var(sizenamename)inletcapvar=search_global_var(capnamename)inList.rev[(letcond=Cil.mkBinOp~loc:unklocGt(Cil.evarsizevar)(Cil.evarcapvar)inletnewsize=Cil.mkBinOp~loc:unklocMult(Cil.integer~loc:unkloc2)(Cil.increm(Cil.evarsizevar)1)inletrealloc=Globals.Functions.find_by_name"realloc"|>Kernel_function.get_vi|>Cil.evarinletarg=Cil.(new_exp~loc:unkloc(CastE(Cil_const.voidPtrType,evartabvar)))inletincinstr=Call(None,realloc,[arg;newsize],unkloc)inletinc=Cil.mkStmtOneInstr~ghost:trueincinstrinCil.mkStmt~ghost:true(If(cond,Cil.mkBlock[inc],Cil.mkBlock[],unkloc)));(letaddr=Cil.mkBinOp~loc:unklocPlusPI(Cil.evartabvar)(Cil.evarsizevar)inlettabcell=Cil.mkMem~addr~off:NoOffsetinletvalue=Option.getlvar.lv_origin|>Cil.evarinCil.mkStmtOneInstr~ghost:true(Set(tabcell,value,unkloc)));(letincrexp=Cil.increm(Cil.evarsizevar)1inCil.mkStmtOneInstr~ghost:true(Set(Cil.varsizevar,increxp,unkloc)))]letgf()=match!ext_flagswith|None->Meta_options.Self.fatal"uninitialized bindings"|Some{static_bindings=None}->make_dynamic_modif_code|Some{static_bindings=Some_}->make_static_modif_code(* When encountering an ID, create the correct ghost stmt and fill to_add *)letprocess_imetavis=if!visit_inlinethenfunction|Ext_terms[{term_node=TLval(TVarlvar,TNoOffset)};{term_node=TConst(LStrname)}]->lets=Option.getvis#current_stmtinletgf=gf()inList.iter(fun(v:stmt)->add_to_hash_listStmt_Hashtbl.(find_opt,replace)to_addsv)(gfnamelvar);Cil.SkipChildren|_->Cil.SkipChildrenelsefun_->Cil.SkipChildren