123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602(*
*
* Copyright (c) 2001-2002,
* John Kodumal <jkodumal@eecs.berkeley.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. The names of the contributors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*)exceptionBad_returnexceptionBad_functionopenCilopenFeaturemoduleH=HashtblmoduleA=OlfexceptionUnknownLocation=A.UnknownLocationtypeaccess=A.lvalue*booltypeaccess_map=(lval,access)H.t(** a mapping from varinfo's back to fundecs *)moduleVarInfoKey=structtypet=varinfoletcomparev1v2=v1.vid-v2.videndmoduleF=Map.Make(VarInfoKey)(***********************************************************************)(* *)(* Global Variables *)(* *)(***********************************************************************)letmodel_strings=reffalseletprint_constraints=A.print_constraintsletdebug_constraints=A.debug_constraintsletdebug_aliases=A.debug_aliasesletsmart_aliases=A.smart_aliasesletdebug=A.debugletanalyze_mono=A.analyze_monoletno_flow=A.no_flowletno_sub=A.no_subletfun_ptrs_as_funs=reffalseletshow_progress=reffalseletdebug_may_aliases=reffalseletfound_undefined=reffalseletconservative_undefineds=reffalseletcurrent_fundec:fundecoptionref=refNoneletfun_access_map:(fundec,access_map)H.t=H.create64(* A mapping from varinfos to fundecs *)letfun_varinfo_map=refF.emptyletcurrent_ret:A.tauoptionref=refNoneletlvalue_hash:(varinfo,A.lvalue)H.t=H.create64letexpressions:(exp,A.tau)H.t=H.create64letlvalues:(lval,A.lvalue)H.t=H.create64letfresh_index:(unit->int)=letcount=ref0infun()->incrcount;!countletalloc_names=["malloc";"calloc";"realloc";"xmalloc";"__builtin_alloca";"alloca";"kmalloc"](* This function should be set by the client if it
* knows of functions returning a result that have
* no side effects. If the result is not used, then
* the call will be eliminated. *)letcallHasNoSideEffects:(exp->bool)ref=ref(fun_->false)letall_globals:varinfolistref=ref[]letall_functions:fundeclistref=ref[](***********************************************************************)(* *)(* Utility Functions *)(* *)(***********************************************************************)letis_undefined_fun=functionLval(lh,o)->ifisFunctionType(typeOfLval(lh,o))thenmatchlhwithVarv->v.vstorage=Extern|_->falseelsefalse|_->falseletis_alloc_fun=functionLval(lh,o)->ifisFunctionType(typeOfLval(lh,o))thenmatchlhwithVarv->List.memv.vnamealloc_names|_->falseelsefalse|_->falseletnext_alloc=functionLval(Varv,o)->letname=Printf.sprintf"%s@%d"v.vname(fresh_index())inA.address(A.make_lvaluefalsename(Somev))(* check *)|_->raiseBad_returnletis_effect_free_fun=functionLval(lh,o)whenisFunctionType(typeOfLval(lh,o))->beginmatchlhwithVarv->begintry("CHECK_"=String.subv.vname06||!callHasNoSideEffects(Lval(lh,o)))withInvalid_argument_->falseend|_->falseend|_->false(***********************************************************************)(* *)(* AST Traversal Functions *)(* *)(***********************************************************************)(* should do nothing, might need to worry about Index case *)(* let analyzeOffset (o : offset ) : A.tau = A.bottom () *)letanalyze_var_decl(v:varinfo):A.lvalue=tryH.findlvalue_hashvwithNot_found->letlv=A.make_lvaluefalsev.vname(Somev)inH.addlvalue_hashvlv;lvletisFunPtrType(t:typ):bool=matchtwithTPtr(t,_)->isFunctionTypet|_->falseletrecanalyze_lval(lv:lval):A.lvalue=letfind_access(l:A.lvalue)(is_var:bool):A.lvalue=match!current_fundecwithNone->l|Somef->letaccesses=H.findfun_access_mapfinifH.memaccesseslvthenlelsebeginH.addaccesseslv(l,is_var);lendinletresult=matchlvwithVarv,_->(* instantiate every syntactic occurrence of a function *)letalv=ifisFunctionType(typeOfLvallv)thenA.instantiate(analyze_var_declv)(fresh_index())elseanalyze_var_declvinfind_accessalvtrue|Meme,_->(* assert (not (isFunctionType(typeOf(e))) ); *)letalv=if!fun_ptrs_as_funs&&isFunPtrType(typeOfe)thenanalyze_expr_as_lvaleelseA.deref(analyze_expre)infind_accessalvfalseinH.replacelvalueslvresult;resultandanalyze_expr_as_lval(e:exp):A.lvalue=matchewithLvall->analyze_lvall|_->assertfalse(* todo -- other kinds of expressions? *)andanalyze_expr(e:exp):A.tau=letresult=matchewithConst(CStrs)->if!model_stringsthenA.address(A.make_lvaluefalses(Some(makeVarinfofalsescharConstPtrType)))elseA.bottom()|Constc->A.bottom()|Lvall->A.rvalue(analyze_lvall)|SizeOf_->A.bottom()|SizeOfStr_->A.bottom()|AlignOf_->A.bottom()|UnOp(op,e,t)->analyze_expre|BinOp(op,e,e',t)->A.join(analyze_expre)(analyze_expre')|Question(_,e,e',_)->A.join(analyze_expre)(analyze_expre')|CastE(t,e)->analyze_expre|AddrOfl->if!fun_ptrs_as_funs&&isFunctionType(typeOfLvall)thenA.rvalue(analyze_lvall)elseA.address(analyze_lvall)|AddrOfLabel_->failwith"not implemented yet"(* XXX *)|StartOfl->A.address(analyze_lvall)|AlignOfE_->A.bottom()|SizeOfE_->A.bottom()|Imag__->A.bottom()|Real__->A.bottom()inH.addexpressionseresult;result(* check *)letrecanalyze_init(i:init):A.tau=matchiwithSingleInite->analyze_expre|CompoundInit(t,oi)->A.join_inits(Util.list_map(function(_,i)->analyze_initi)oi)letanalyze_instr(i:instr):unit=matchiwithSet(lval,rhs,l)->A.assign(analyze_lvallval)(analyze_exprrhs)|Call(res,fexpr,actuals,l)->ifnot(isFunctionType(typeOffexpr))then()(* todo : is this a varargs? *)elseifis_alloc_funfexprthenbeginif!debugthenprint_string"Found allocation function...\n";matchreswithSomer->A.assign(analyze_lvalr)(next_allocfexpr)|None->()endelseifis_effect_free_funfexprthenList.iter(fune->ignore(analyze_expre))actualselse(* todo : check to see if the thing is an undefined function *)letfnres,site=ifis_undefined_funfexpr&&!conservative_undefinedsthenbeginfound_undefined:=true;A.apply_undefined(Util.list_mapanalyze_expractuals)endelseA.apply(analyze_exprfexpr)(Util.list_mapanalyze_expractuals)inbeginmatchreswithSomer->A.assign_retsite(analyze_lvalr)fnres|None->()end|Asm_->()|VarDecl_->()letrecanalyze_stmt(s:stmt):unit=matchs.skindwithInstril->List.iteranalyze_instril|Return(eo,l)->beginmatcheowithSomee->beginmatch!current_retwithSomeret->A.returnret(analyze_expre)|None->raiseBad_returnend|None->()end|Goto(s',l)->()(* analyze_stmt(!s') *)|ComputedGoto(e,l)->()|If(e,b,b',l)->(* ignore the expression e; expressions can't be side-effecting *)analyze_blockb;analyze_blockb'|Switch(e,b,sl,l)->analyze_blockb;List.iteranalyze_stmtsl|Loop(b,l,_,_)->analyze_blockb|Blockb->analyze_blockb|TryFinally(b,h,_)->analyze_blockb;analyze_blockh|TryExcept(b,(il,_),h,_)->analyze_blockb;List.iteranalyze_instril;analyze_blockh|Breakl->()|Continuel->()andanalyze_block(b:block):unit=List.iteranalyze_stmtb.bstmtsletanalyze_function(f:fundec):unit=letoldlv=analyze_var_declf.svarinletret=A.make_fresh(f.svar.vname^"_ret")inletformals=Util.list_mapanalyze_var_declf.sformalsinletnewf=A.make_functionf.svar.vnameformalsretinif!show_progressthenPrintf.printf"Analyzing function %s\n"f.svar.vname;fun_varinfo_map:=F.addf.svarf(!fun_varinfo_map);current_fundec:=Somef;H.addfun_access_mapf(H.create8);A.assignoldlvnewf;current_ret:=Someret;analyze_blockf.sbodyletanalyze_global(g:global):unit=matchgwithGVarDecl(v,l)->()(* ignore (analyze_var_decl(v)) -- no need *)|GVar(v,init,l)->all_globals:=v::!all_globals;beginmatchinit.initwithSomei->A.assign(analyze_var_declv)(analyze_initi)|None->ignore(analyze_var_declv)end|GFun(f,l)->all_functions:=f::!all_functions;analyze_functionf|_->()letanalyze_file(f:file):unit=iterGlobalsfanalyze_global(***********************************************************************)(* *)(* High-level Query Interface *)(* *)(***********************************************************************)(* Same as analyze_expr, but no constraints. *)letrectraverse_expr(e:exp):A.tau=H.findexpressionseandtraverse_expr_as_lval(e:exp):A.lvalue=matchewith|Lvall->traverse_lvall|_->assertfalse(* todo -- other kinds of expressions? *)andtraverse_lval(lv:lval):A.lvalue=H.findlvalueslvletmay_alias(e1:exp)(e2:exp):bool=lettau1,tau2=traverse_expre1,traverse_expre2inletresult=A.may_aliastau1tau2inif!debug_may_aliasesthenbeginletdoc1=d_exp()e1inletdoc2=d_exp()e2inlets1=Pretty.sprint~width:30doc1inlets2=Pretty.sprint~width:30doc2inPrintf.printf"%s and %s may alias? %s\n"s1s2(ifresultthen"yes"else"no")end;resultletresolve_lval(lv:lval):varinfolist=A.points_to(traverse_lvallv)letresolve_exp(e:exp):varinfolist=A.epoints_to(traverse_expre)letresolve_funptr(e:exp):fundeclist=letvarinfos=A.epoints_to(traverse_expre)inList.fold_left(funfdecs->funvinf->tryF.findvinf!fun_varinfo_map::fdecswithNot_found->fdecs)[]varinfosletcount_hash_eltsh=letresult=ref0inH.iter(fun_->fun_->incrresult)lvalue_hash;!resultletcompute_may_aliases(b:bool):unit=letreccompute_may_aliases_aux(exps:explist)=matchexpswith[]->()|h::t->ignore(Util.list_map(may_aliash)t);compute_may_aliases_auxtandexprs:explistref=ref[]inH.iter(fune->fun_->exprs:=e::!exprs)expressions;compute_may_aliases_aux!exprsletcompute_results(show_sets:bool):unit=lettotal_pointed_to=ref0andtotal_lvalues=H.lengthlvalue_hashandcounted_lvalues=ref0andlval_elts:(string*(stringlist))listref=ref[]inletprint_result(name,set)=letrecprint_sets=matchswith[]->()|h::[]->print_stringh|h::t->print_string(h^", ");print_settandptsize=List.lengthsetintotal_pointed_to:=!total_pointed_to+ptsize;ifptsize>0thenbeginprint_string(name^"("^(string_of_intptsize)^") -> ");print_setset;print_newline()endin(* Make the most pessimistic assumptions about globals if an
undefined function is present. Such a function can write to every
global variable *)lethose_globals():unit=List.iter(funvd->A.assign_undefined(analyze_var_declvd))!all_globalsinletshow_progress_fn(counted:intref)(total:int):unit=incrcounted;if!show_progressthenPrintf.printf"Computed flow for %d of %d sets\n"!countedtotalinif!conservative_undefineds&&!found_undefinedthenhose_globals();A.finished_constraints();ifshow_setsthenbeginprint_endline"Computing points-to sets...";Hashtbl.iter(funvinf->funlv->show_progress_fncounted_lvaluestotal_lvalues;trylval_elts:=(vinf.vname,A.points_to_nameslv)::!lval_eltswithA.UnknownLocation->())lvalue_hash;List.iterprint_result!lval_elts;Printf.printf"Total number of things pointed to: %d\n"!total_pointed_toend;if!debug_may_aliasesthenbeginPrintf.printf"Printing may alias relationships\n";compute_may_aliasestrueendletprint_types():unit=print_string"Printing inferred types of lvalues...\n";Hashtbl.iter(funvi->funlv->Printf.printf"%s : %s\n"vi.vname(A.string_of_lvaluelv))lvalue_hash(** Alias queries. For each function, gather sets of locals, formals, and
globals. Do n^2 work for each of these functions, reporting whether or not
each pair of values is aliased. Aliasing is determined by taking points-to
set intersections.
*)letcompute_aliases=compute_may_aliases(***********************************************************************)(* *)(* Abstract Location Interface *)(* *)(***********************************************************************)typeabsloc=A.abslocletlvalue_of_varinfo(vi:varinfo):A.lvalue=H.findlvalue_hashviletlvalue_of_lval=traverse_lvallettau_of_expr=traverse_expr(** return an abstract location for a varinfo, resp. lval *)letabsloc_of_varinfovi=A.absloc_of_lvalue(lvalue_of_varinfovi)letabsloc_of_lvallv=A.absloc_of_lvalue(lvalue_of_lvallv)letabsloc_e_points_toe=A.absloc_epoints_to(tau_of_expre)letabsloc_lval_aliaseslv=A.absloc_points_to(lvalue_of_lvallv)(* all abslocs that e transitively points to *)letabsloc_e_transitive_points_to(e:Cil.exp):absloclist=letreclv_trans_ptsto(worklist:varinfolist)(acc:varinfolist):absloclist=matchworklistwith[]->Util.list_mapabsloc_of_varinfoacc|vi::wklst''->ifList.memviaccthenlv_trans_ptstowklst''accelselv_trans_ptsto(List.rev_append(A.points_to(lvalue_of_varinfovi))wklst'')(vi::acc)inlv_trans_ptsto(A.epoints_to(tau_of_expre))[]letabsloc_eqab=A.absloc_eq(a,b)letd_absloc:unit->absloc->Pretty.doc=A.d_abslocletptrResults=reffalseletptrTypes=reffalse(** Turn this into a CIL feature *)letfeature={fd_name="ptranal";fd_enabled=false;fd_description="alias analysis";fd_extraopt=[("--ptr_may_aliases",Arg.Unit(fun_->debug_may_aliases:=true)," Print out results of may alias queries");("--ptr_unify",Arg.Unit(fun_->no_sub:=true)," Make the alias analysis unification-based");("--ptr_model_strings",Arg.Unit(fun_->model_strings:=true)," Make the alias analysis model string constants");("--ptr_conservative",Arg.Unit(fun_->conservative_undefineds:=true)," Treat undefineds conservatively in alias analysis");("--ptr_results",Arg.Unit(fun_->ptrResults:=true)," print the results of the alias analysis");("--ptr_mono",Arg.Unit(fun_->analyze_mono:=true)," run alias analysis monomorphically");("--ptr_types",Arg.Unit(fun_->ptrTypes:=true)," print inferred points-to analysis types")];fd_doit=(function(f:file)->analyze_filef;compute_results!ptrResults;if!ptrTypesthenprint_types());fd_post_check=false(* No changes *)}let()=Feature.registerfeature