123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126openLibraryDescmoduleAccess=LibraryDesc.Access(* avoid spurious dependency cycle due to ocamldep overapprox ambiguity between Access and LibraryDesc.Access *)(** First-class patterns for arguments matching.
@see <https://github.com/ocaml-ppx/ppxlib/blob/main/src/ast_pattern.ml> for inspiration from ppxlib. *)modulePattern=struct(** @param a Type of value to match.
@param k Type of continuation function.
@param r Return type of match. *)type('a,'k,'r)t='a->'k->'rexceptionExpectedofstringletfails=raise(Expecteds)let__:_t=funxk->kxletdrop:_t=fun_k->kletnil:_t=funxk->matchxwith|[]->k|_->fail"Library function is called with more arguments than expected."let(^::)(p1:_t)(p2:_t):_t=funxk->matchxwith|x1::x2->letk=p1x1kinletk=p2x2kink|[]->fail"^::"endtypeaccess=|AccessofLibraryDesc.Access.t|Ifof(unit->bool)*accessletreceval_access=function|Accessacc->Someacc|If(p,access)->ifp()theneval_accessaccesselseNonetype('k,'l,'r)arg_desc={accesses:accesslist;match_arg:(Cil.exp,'k,'r)Pattern.t;match_var_args:(Cil.explist,'l,'r)Pattern.t;}type('k,'r)args_desc=|[]:('r,'r)args_desc|VarArgs:(_,'l,'r)arg_desc->('l,'r)args_desc|(::):('k,_,'m)arg_desc*('m,'r)args_desc->('k,'r)args_descletrecmatch_args:typekr.(k,r)args_desc->(Cil.explist,k,r)Pattern.t=function|[]->Pattern.nil|VarArgs{match_var_args;_}->match_var_args|{match_arg;_}::args->Pattern.(match_arg^::match_argsargs)letrecaccs:typekr.(k,r)args_desc->Accesses.t=funargs_descargs->matchargs_desc,argswith|[],[]->[]|VarArgsarg_desc,args->List.filter_map(funaccess->matcheval_accessaccesswith|Someacc->Some(acc,args)|None->None)arg_desc.accesses|arg_desc::args_desc,arg::args->letaccs''=accsargs_descargsinList.fold_left(fun(accs'':(Access.t*Cil.explist)list)(access:access)->matcheval_accessaccesswith|Someacc->beginmatchList.assoc_optaccaccs''with|Someargs->(acc,arg::args)::List.remove_assocaccaccs''|None->(acc,[arg])::accs''end|None->accs'')accs''arg_desc.accesses|_,_->invalid_arg"accs"letspecial?(attrs:attrlist=[])args_descspecial_cont={special=Fun.flip(match_argsargs_desc)special_cont;accs=accsargs_desc;attrs;}letspecial'?(attrs:attrlist=[])args_descspecial_cont={special=(funargs->Fun.flip(match_argsargs_desc)(special_cont())args);(* eta-expanded such that special_cont is re-executed on each call instead of once during LibraryFunctions construction *)accs=accsargs_desc;attrs;}letunknown?attrsargs_desc=special?attrsargs_descUnknownletempty____desc={match_arg=Pattern.(__);match_var_args=Pattern.(__);accesses=[];}let__(_name:string)accesses={empty____descwithaccesses;}let__'accesses={empty____descwithaccesses;}letempty_drop_desc={match_arg=Pattern.drop;match_var_args=Pattern.drop;accesses=[];}letdrop(_name:string)accesses={empty_drop_descwithaccesses;}letdrop'accesses={empty_drop_descwithaccesses;}letr=Access{kind=Read;deep=false;}letr_deep=Access{kind=Read;deep=true;}letw=Access{kind=Write;deep=false;}letw_deep=Access{kind=Write;deep=true;}letf=Access{kind=Free;deep=false;}letf_deep=Access{kind=Free;deep=true;}lets=Access{kind=Spawn;deep=false;}lets_deep=Access{kind=Spawn;deep=true;}letc=Access{kind=Spawn;deep=false;}(* TODO: Sound, but very imprecise hack for calls to function pointers given as arguments. *)letc_deep=Access{kind=Spawn;deep=true;}letif_paccess=If(p,access)