|
|
@ -4,6 +4,7 @@
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* This source code is licensed under the MIT license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
* LICENSE file in the root directory of this source tree.
|
|
|
|
*)
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
|
|
open! IStd
|
|
|
|
open! IStd
|
|
|
|
module L = Logging
|
|
|
|
module L = Logging
|
|
|
|
|
|
|
|
|
|
|
@ -16,19 +17,14 @@ module L = Logging
|
|
|
|
- catch / throw with exception classes
|
|
|
|
- catch / throw with exception classes
|
|
|
|
*)
|
|
|
|
*)
|
|
|
|
|
|
|
|
|
|
|
|
module Payload = SummaryPayload.Make (struct
|
|
|
|
let do_call {InterproceduralAnalysis.analyze_dependency} callee loc init =
|
|
|
|
type t = ClassLoadsDomain.summary
|
|
|
|
analyze_dependency callee
|
|
|
|
|
|
|
|
|> Option.fold ~init ~f:(fun acc (_, summary) ->
|
|
|
|
let field = Payloads.Fields.class_loads
|
|
|
|
ClassLoadsDomain.integrate_summary callee loc acc summary )
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let do_call summary callee loc init =
|
|
|
|
|
|
|
|
Payload.read ~caller_summary:summary ~callee_pname:callee
|
|
|
|
|
|
|
|
|> Option.fold ~init ~f:(ClassLoadsDomain.integrate_summary callee loc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** fully load a class given the typename *)
|
|
|
|
(** fully load a class given the typename *)
|
|
|
|
let rec load_class summary tenv loc astate class_name =
|
|
|
|
let rec load_class ({InterproceduralAnalysis.tenv} as analysis_data) loc astate class_name =
|
|
|
|
(* don't bother if class is already loaded *)
|
|
|
|
(* don't bother if class is already loaded *)
|
|
|
|
if ClassLoadsDomain.mem_typename class_name astate then astate
|
|
|
|
if ClassLoadsDomain.mem_typename class_name astate then astate
|
|
|
|
else
|
|
|
|
else
|
|
|
@ -38,86 +34,87 @@ let rec load_class summary tenv loc astate class_name =
|
|
|
|
let astate2 =
|
|
|
|
let astate2 =
|
|
|
|
let class_initializer = Procname.(Java (Java.get_class_initializer class_name)) in
|
|
|
|
let class_initializer = Procname.(Java (Java.get_class_initializer class_name)) in
|
|
|
|
(* NB may recurse if we are in class init but the shortcircuiting above makes it a no-op *)
|
|
|
|
(* NB may recurse if we are in class init but the shortcircuiting above makes it a no-op *)
|
|
|
|
do_call summary class_initializer loc astate1
|
|
|
|
do_call analysis_data class_initializer loc astate1
|
|
|
|
in
|
|
|
|
in
|
|
|
|
(* finally, recursively load all superclasses *)
|
|
|
|
(* finally, recursively load all superclasses *)
|
|
|
|
Tenv.lookup tenv class_name
|
|
|
|
Tenv.lookup tenv class_name
|
|
|
|
|> Option.value_map ~default:[] ~f:(fun tstruct -> tstruct.Struct.supers)
|
|
|
|
|> Option.value_map ~default:[] ~f:(fun tstruct -> tstruct.Struct.supers)
|
|
|
|
|> List.fold ~init:astate2 ~f:(load_class summary tenv loc)
|
|
|
|
|> List.fold ~init:astate2 ~f:(load_class analysis_data loc)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let load_type summary tenv loc (typ : Typ.t) astate =
|
|
|
|
let load_type analysis_data loc (typ : Typ.t) astate =
|
|
|
|
match typ with
|
|
|
|
match typ with
|
|
|
|
| {desc= Tstruct name} | {desc= Tptr ({desc= Tstruct name}, _)} ->
|
|
|
|
| {desc= Tstruct name} | {desc= Tptr ({desc= Tstruct name}, _)} ->
|
|
|
|
load_class summary tenv loc astate name
|
|
|
|
load_class analysis_data loc astate name
|
|
|
|
| _ ->
|
|
|
|
| _ ->
|
|
|
|
astate
|
|
|
|
astate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let rec load_array summary tenv loc (typ : Typ.t) astate =
|
|
|
|
let rec load_array analysis_data loc (typ : Typ.t) astate =
|
|
|
|
match typ with
|
|
|
|
match typ with
|
|
|
|
| {desc= Tarray {elt}} ->
|
|
|
|
| {desc= Tarray {elt}} ->
|
|
|
|
load_array summary tenv loc elt astate
|
|
|
|
load_array analysis_data loc elt astate
|
|
|
|
| _ ->
|
|
|
|
| _ ->
|
|
|
|
load_type summary tenv loc typ astate
|
|
|
|
load_type analysis_data loc typ astate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let rec add_loads_of_exp summary tenv loc (exp : Exp.t) astate =
|
|
|
|
let rec add_loads_of_exp analysis_data loc (exp : Exp.t) astate =
|
|
|
|
match exp with
|
|
|
|
match exp with
|
|
|
|
| Const (Cclass class_ident) ->
|
|
|
|
| Const (Cclass class_ident) ->
|
|
|
|
(* [X.class] expressions *)
|
|
|
|
(* [X.class] expressions *)
|
|
|
|
let class_str = Ident.name_to_string class_ident |> JavaClassName.from_string in
|
|
|
|
let class_str = Ident.name_to_string class_ident |> JavaClassName.from_string in
|
|
|
|
let class_name = Typ.JavaClass class_str in
|
|
|
|
let class_name = Typ.JavaClass class_str in
|
|
|
|
load_class summary tenv loc astate class_name
|
|
|
|
load_class analysis_data loc astate class_name
|
|
|
|
| Sizeof {typ= {desc= Tarray {elt}}} ->
|
|
|
|
| Sizeof {typ= {desc= Tarray {elt}}} ->
|
|
|
|
(* anewarray / multinewarray *)
|
|
|
|
(* anewarray / multinewarray *)
|
|
|
|
load_array summary tenv loc elt astate
|
|
|
|
load_array analysis_data loc elt astate
|
|
|
|
| Cast (_, e) | UnOp (_, e, _) | Exn e ->
|
|
|
|
| Cast (_, e) | UnOp (_, e, _) | Exn e ->
|
|
|
|
(* NB Cast is only used for primitive types *)
|
|
|
|
(* NB Cast is only used for primitive types *)
|
|
|
|
add_loads_of_exp summary tenv loc e astate
|
|
|
|
add_loads_of_exp analysis_data loc e astate
|
|
|
|
| BinOp (_, e1, e2) ->
|
|
|
|
| BinOp (_, e1, e2) ->
|
|
|
|
add_loads_of_exp summary tenv loc e1 astate |> add_loads_of_exp summary tenv loc e2
|
|
|
|
add_loads_of_exp analysis_data loc e1 astate |> add_loads_of_exp analysis_data loc e2
|
|
|
|
| Lfield (e, _, typ') ->
|
|
|
|
| Lfield (e, _, typ') ->
|
|
|
|
(* getfield / getstatic / putfield / putstatic *)
|
|
|
|
(* getfield / getstatic / putfield / putstatic *)
|
|
|
|
load_type summary tenv loc typ' astate |> add_loads_of_exp summary tenv loc e
|
|
|
|
load_type analysis_data loc typ' astate |> add_loads_of_exp analysis_data loc e
|
|
|
|
| Var _ | Const _ | Closure _ | Sizeof _ | Lindex _ | Lvar _ ->
|
|
|
|
| Var _ | Const _ | Closure _ | Sizeof _ | Lindex _ | Lvar _ ->
|
|
|
|
astate
|
|
|
|
astate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let exec_call summary tenv callee args loc astate =
|
|
|
|
let exec_call analysis_data callee args loc astate =
|
|
|
|
match args with
|
|
|
|
match args with
|
|
|
|
| [_; (Exp.Sizeof {typ}, _)] when Procname.equal callee BuiltinDecl.__instanceof ->
|
|
|
|
| [_; (Exp.Sizeof {typ}, _)] when Procname.equal callee BuiltinDecl.__instanceof ->
|
|
|
|
(* this matches downcasts/instanceof and exception handlers *)
|
|
|
|
(* this matches downcasts/instanceof and exception handlers *)
|
|
|
|
load_type summary tenv loc typ astate
|
|
|
|
load_type analysis_data loc typ astate
|
|
|
|
| _ ->
|
|
|
|
| _ ->
|
|
|
|
(* invokeinterface / invokespecial / invokestatic / invokevirtual / new *)
|
|
|
|
(* invokeinterface / invokespecial / invokestatic / invokevirtual / new *)
|
|
|
|
List.fold args ~init:astate ~f:(fun acc (exp, _) -> add_loads_of_exp summary tenv loc exp acc)
|
|
|
|
List.fold args ~init:astate ~f:(fun acc (exp, _) -> add_loads_of_exp analysis_data loc exp acc)
|
|
|
|
|> do_call summary callee loc
|
|
|
|
|> do_call analysis_data callee loc
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let exec_instr summary tenv astate _ (instr : Sil.instr) =
|
|
|
|
let exec_instr analysis_data astate _ (instr : Sil.instr) =
|
|
|
|
match instr with
|
|
|
|
match instr with
|
|
|
|
| Call (_, Const (Cfun callee), args, loc, _) ->
|
|
|
|
| Call (_, Const (Cfun callee), args, loc, _) ->
|
|
|
|
exec_call summary tenv callee args loc astate
|
|
|
|
exec_call analysis_data callee args loc astate
|
|
|
|
| Load {e= exp; loc} | Prune (exp, loc, _, _) ->
|
|
|
|
| Load {e= exp; loc} | Prune (exp, loc, _, _) ->
|
|
|
|
(* NB the java frontend seems to always translate complex guards into a sequence of
|
|
|
|
(* NB the java frontend seems to always translate complex guards into a sequence of
|
|
|
|
instructions plus a prune on logical vars only. So the below is only for completeness. *)
|
|
|
|
instructions plus a prune on logical vars only. So the below is only for completeness. *)
|
|
|
|
add_loads_of_exp summary tenv loc exp astate
|
|
|
|
add_loads_of_exp analysis_data loc exp astate
|
|
|
|
| Store {e1; e2; loc} ->
|
|
|
|
| Store {e1; e2; loc} ->
|
|
|
|
add_loads_of_exp summary tenv loc e1 astate |> add_loads_of_exp summary tenv loc e2
|
|
|
|
add_loads_of_exp analysis_data loc e1 astate |> add_loads_of_exp analysis_data loc e2
|
|
|
|
| _ ->
|
|
|
|
| _ ->
|
|
|
|
astate
|
|
|
|
astate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let report_loads summary astate =
|
|
|
|
let report_loads {InterproceduralAnalysis.proc_desc; err_log} astate =
|
|
|
|
let report_load ({ClassLoadsDomain.Event.loc; elem} as event) =
|
|
|
|
let report_load ({ClassLoadsDomain.Event.loc; elem} as event) =
|
|
|
|
if String.is_prefix ~prefix:"java." elem then ()
|
|
|
|
if String.is_prefix ~prefix:"java." elem then ()
|
|
|
|
else
|
|
|
|
else
|
|
|
|
let ltr = ClassLoadsDomain.Event.make_loc_trace event in
|
|
|
|
let ltr = ClassLoadsDomain.Event.make_loc_trace event in
|
|
|
|
let msg = Format.asprintf "Class %s loaded" elem in
|
|
|
|
let msg = Format.asprintf "Class %s loaded" elem in
|
|
|
|
SummaryReporting.log_warning summary ~loc ~ltr IssueType.class_load msg
|
|
|
|
let attrs = Procdesc.get_attributes proc_desc in
|
|
|
|
|
|
|
|
Reporting.log_warning attrs err_log ~loc ~ltr IssueType.class_load msg
|
|
|
|
in
|
|
|
|
in
|
|
|
|
let pname = Summary.get_proc_name summary in
|
|
|
|
let pname = Procdesc.get_proc_name proc_desc in
|
|
|
|
Procname.get_class_name pname
|
|
|
|
Procname.get_class_name pname
|
|
|
|
|> Option.iter ~f:(fun clazz ->
|
|
|
|
|> Option.iter ~f:(fun clazz ->
|
|
|
|
let method_strname = Procname.get_method pname in
|
|
|
|
let method_strname = Procname.get_method pname in
|
|
|
@ -126,19 +123,16 @@ let report_loads summary astate =
|
|
|
|
ClassLoadsDomain.iter report_load astate )
|
|
|
|
ClassLoadsDomain.iter report_load astate )
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let analyze_procedure {Callbacks.exe_env; summary} =
|
|
|
|
let analyze_procedure ({InterproceduralAnalysis.proc_desc} as analysis_data) =
|
|
|
|
let proc_desc = Summary.get_proc_desc summary in
|
|
|
|
|
|
|
|
let proc_name = Procdesc.get_proc_name proc_desc in
|
|
|
|
let proc_name = Procdesc.get_proc_name proc_desc in
|
|
|
|
let tenv = Exe_env.get_tenv exe_env proc_name in
|
|
|
|
|
|
|
|
L.debug Analysis Verbose "CL: ANALYZING %a@." Procname.pp proc_name ;
|
|
|
|
L.debug Analysis Verbose "CL: ANALYZING %a@." Procname.pp proc_name ;
|
|
|
|
let loc = Procdesc.get_loc proc_desc in
|
|
|
|
let loc = Procdesc.get_loc proc_desc in
|
|
|
|
(* load the method's class *)
|
|
|
|
(* load the method's class *)
|
|
|
|
let init =
|
|
|
|
let init =
|
|
|
|
Procname.get_class_type_name proc_name
|
|
|
|
Procname.get_class_type_name proc_name
|
|
|
|
|> Option.fold ~init:ClassLoadsDomain.bottom ~f:(load_class summary tenv loc)
|
|
|
|
|> Option.fold ~init:ClassLoadsDomain.bottom ~f:(load_class analysis_data loc)
|
|
|
|
in
|
|
|
|
in
|
|
|
|
let post = Procdesc.fold_instrs proc_desc ~init ~f:(exec_instr summary tenv) in
|
|
|
|
let post = Procdesc.fold_instrs proc_desc ~init ~f:(exec_instr analysis_data) in
|
|
|
|
report_loads summary post ;
|
|
|
|
report_loads analysis_data post ;
|
|
|
|
let result = Payload.update_summary post summary in
|
|
|
|
|
|
|
|
L.debug Analysis Verbose "CL: FINISHED ANALYZING %a@." Procname.pp proc_name ;
|
|
|
|
L.debug Analysis Verbose "CL: FINISHED ANALYZING %a@." Procname.pp proc_name ;
|
|
|
|
result
|
|
|
|
Some post
|
|
|
|