|
|
@ -8,10 +8,6 @@ module L = Logging
|
|
|
|
|
|
|
|
|
|
|
|
type t
|
|
|
|
type t
|
|
|
|
|
|
|
|
|
|
|
|
module ConstantMap = Map.Make(struct
|
|
|
|
|
|
|
|
type t = string
|
|
|
|
|
|
|
|
let compare = string_compare
|
|
|
|
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let string_widening_limit = 1000
|
|
|
|
let string_widening_limit = 1000
|
|
|
|
let verbose = false
|
|
|
|
let verbose = false
|
|
|
@ -24,85 +20,81 @@ let merge_values key c1_opt c2_opt =
|
|
|
|
| None, Some c -> Some c
|
|
|
|
| None, Some c -> Some c
|
|
|
|
| _ -> Some None
|
|
|
|
| _ -> Some None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
module ConstantMap = Sil.ExpMap
|
|
|
|
|
|
|
|
|
|
|
|
(** Dataflow struct *)
|
|
|
|
(** Dataflow struct *)
|
|
|
|
module ConstantFlow = Dataflow.MakeDF(struct
|
|
|
|
module ConstantFlow = Dataflow.MakeDF(struct
|
|
|
|
type t = (Sil.const option) ConstantMap.t
|
|
|
|
type t = (Sil.const option) ConstantMap.t
|
|
|
|
|
|
|
|
|
|
|
|
let pp fmt constants =
|
|
|
|
let pp fmt constants =
|
|
|
|
let print_kv k = function
|
|
|
|
let pp_key fmt = Sil.pp_exp pe_text fmt in
|
|
|
|
| Some v -> Format.fprintf fmt " %s -> %a@." k (Sil.pp_const pe_text) v
|
|
|
|
let print_kv k = function
|
|
|
|
| _ -> Format.fprintf fmt " %s -> None@." k in
|
|
|
|
| Some v -> Format.fprintf fmt " %a -> %a@." pp_key k (Sil.pp_const pe_text) v
|
|
|
|
Format.fprintf fmt "[@.";
|
|
|
|
| _ -> Format.fprintf fmt " %a -> None@." pp_key k in
|
|
|
|
ConstantMap.iter print_kv constants;
|
|
|
|
Format.fprintf fmt "[@.";
|
|
|
|
Format.fprintf fmt "]@."
|
|
|
|
ConstantMap.iter print_kv constants;
|
|
|
|
|
|
|
|
Format.fprintf fmt "]@."
|
|
|
|
(* Item-wise equality where values are equal iff
|
|
|
|
|
|
|
|
|
|
|
|
(* Item - wise equality where values are equal iff
|
|
|
|
- both are None
|
|
|
|
- both are None
|
|
|
|
- both are a constant and equal wrt. Sil.const_equal *)
|
|
|
|
- both are a constant and equal wrt. Sil.const_equal *)
|
|
|
|
let equal m n = ConstantMap.equal (opt_equal Sil.const_equal) m n
|
|
|
|
let equal m n = ConstantMap.equal (opt_equal Sil.const_equal) m n
|
|
|
|
|
|
|
|
|
|
|
|
let join = ConstantMap.merge merge_values
|
|
|
|
let join = ConstantMap.merge merge_values
|
|
|
|
|
|
|
|
|
|
|
|
let proc_throws pn = Dataflow.DontKnow
|
|
|
|
let proc_throws pn = Dataflow.DontKnow
|
|
|
|
|
|
|
|
|
|
|
|
let do_node node constants =
|
|
|
|
let do_node node constants =
|
|
|
|
|
|
|
|
|
|
|
|
let do_instr constants instr =
|
|
|
|
let do_instr constants instr =
|
|
|
|
try
|
|
|
|
try
|
|
|
|
let update key value constants =
|
|
|
|
let update key value constants =
|
|
|
|
ConstantMap.merge
|
|
|
|
ConstantMap.merge
|
|
|
|
merge_values
|
|
|
|
merge_values
|
|
|
|
constants
|
|
|
|
constants
|
|
|
|
(ConstantMap.add key value ConstantMap.empty) in
|
|
|
|
(ConstantMap.add key value ConstantMap.empty) in
|
|
|
|
|
|
|
|
|
|
|
|
match instr with
|
|
|
|
match instr with
|
|
|
|
| Sil.Letderef (i, Sil.Lvar p, _, _) -> (* tmp = var *)
|
|
|
|
| Sil.Letderef (i, Sil.Lvar p, _, _) -> (* tmp = var *)
|
|
|
|
let lvar = Ident.to_string i in
|
|
|
|
update (Sil.Var i) (ConstantMap.find (Sil.Lvar p) constants) constants
|
|
|
|
let rvar = Sil.pvar_to_string p in
|
|
|
|
|
|
|
|
update lvar (ConstantMap.find rvar constants) constants
|
|
|
|
| Sil.Set (Sil.Lvar p, _, Sil.Const c, _) -> (* var = const *)
|
|
|
|
|
|
|
|
update (Sil.Lvar p) (Some c) constants
|
|
|
|
| Sil.Set (Sil.Lvar p, _, Sil.Const c, _) -> (* var = const *)
|
|
|
|
|
|
|
|
update (Sil.pvar_to_string p) (Some c) constants
|
|
|
|
| Sil.Set (Sil.Lvar p, _, Sil.Var i, _) -> (* var = tmp *)
|
|
|
|
|
|
|
|
update (Sil.Lvar p) (ConstantMap.find (Sil.Var i) constants) constants
|
|
|
|
| Sil.Set (Sil.Lvar p, _, Sil.Var i, _) -> (* var = tmp *)
|
|
|
|
|
|
|
|
let lvar = Sil.pvar_to_string p in
|
|
|
|
(* Handle propagation of string with StringBuilder. Does not handle null case *)
|
|
|
|
let rvar = Ident.to_string i in
|
|
|
|
| Sil.Call (_, Sil.Const (Sil.Cfun pn), (Sil.Var sb, _):: [], _, _)
|
|
|
|
update lvar (ConstantMap.find rvar constants) constants
|
|
|
|
when Procname.java_get_class pn = "java.lang.StringBuilder"
|
|
|
|
|
|
|
|
&& Procname.java_get_method pn = "<init>" -> (* StringBuilder.<init> *)
|
|
|
|
(* Handle propagation of string with StringBuilder. Does not handle null case *)
|
|
|
|
update (Sil.Var sb) (Some (Sil.Cstr "")) constants
|
|
|
|
| Sil.Call (_, Sil.Const (Sil.Cfun pn), (Sil.Var sb, _):: [], _, _)
|
|
|
|
|
|
|
|
when Procname.java_get_class pn = "java.lang.StringBuilder"
|
|
|
|
| Sil.Call (i:: [], Sil.Const (Sil.Cfun pn), (Sil.Var i1, _):: [], _, _)
|
|
|
|
&& Procname.java_get_method pn = "<init>" -> (* StringBuilder.<init> *)
|
|
|
|
when Procname.java_get_class pn = "java.lang.StringBuilder"
|
|
|
|
update (Ident.to_string sb) (Some (Sil.Cstr "")) constants
|
|
|
|
&& Procname.java_get_method pn = "toString" -> (* StringBuilder.toString *)
|
|
|
|
|
|
|
|
update (Sil.Var i) (ConstantMap.find (Sil.Var i1) constants) constants
|
|
|
|
| Sil.Call (i:: [], Sil.Const (Sil.Cfun pn), (Sil.Var i1, _):: [], _, _)
|
|
|
|
|
|
|
|
when Procname.java_get_class pn = "java.lang.StringBuilder"
|
|
|
|
| Sil.Call (i:: [], Sil.Const (Sil.Cfun pn), (Sil.Var i1, _):: (Sil.Var i2, _):: [], _, _)
|
|
|
|
&& Procname.java_get_method pn = "toString" -> (* StringBuilder.toString *)
|
|
|
|
when Procname.java_get_class pn = "java.lang.StringBuilder"
|
|
|
|
let lvar = Ident.to_string i in
|
|
|
|
&& Procname.java_get_method pn = "append" -> (* StringBuilder.append *)
|
|
|
|
let rvar = Ident.to_string i1 in
|
|
|
|
(match
|
|
|
|
update lvar (ConstantMap.find rvar constants) constants
|
|
|
|
ConstantMap.find (Sil.Var i1) constants,
|
|
|
|
|
|
|
|
ConstantMap.find (Sil.Var i2) constants with
|
|
|
|
| Sil.Call (i:: [], Sil.Const (Sil.Cfun pn), (Sil.Var i1, _):: (Sil.Var i2, _):: [], _, _)
|
|
|
|
| Some (Sil.Cstr s1), Some (Sil.Cstr s2) ->
|
|
|
|
when Procname.java_get_class pn = "java.lang.StringBuilder"
|
|
|
|
begin
|
|
|
|
&& Procname.java_get_method pn = "append" -> (* StringBuilder.append *)
|
|
|
|
let s = s1 ^ s2 in
|
|
|
|
let lvar = Ident.to_string i in
|
|
|
|
let u =
|
|
|
|
let rvar1 = Ident.to_string i1 in
|
|
|
|
if String.length s < string_widening_limit then
|
|
|
|
let rvar2 = Ident.to_string i2 in
|
|
|
|
Some (Sil.Cstr s)
|
|
|
|
(match ConstantMap.find rvar1 constants, ConstantMap.find rvar2 constants with
|
|
|
|
else
|
|
|
|
| Some (Sil.Cstr s1), Some (Sil.Cstr s2) ->
|
|
|
|
None in
|
|
|
|
begin
|
|
|
|
update (Sil.Var i) u constants
|
|
|
|
let s = s1 ^ s2 in
|
|
|
|
end
|
|
|
|
let u =
|
|
|
|
| _ -> constants)
|
|
|
|
if String.length s < string_widening_limit then
|
|
|
|
|
|
|
|
Some (Sil.Cstr s)
|
|
|
|
| _ -> constants
|
|
|
|
else
|
|
|
|
with Not_found -> constants in
|
|
|
|
None in
|
|
|
|
|
|
|
|
update lvar u constants
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
| _ -> constants)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| _ -> constants
|
|
|
|
|
|
|
|
with Not_found -> constants in
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if verbose then
|
|
|
|
if verbose then
|
|
|
|
begin
|
|
|
|
begin
|
|
|
@ -119,7 +111,7 @@ module ConstantFlow = Dataflow.MakeDF(struct
|
|
|
|
(Cfg.Node.get_instrs node) in
|
|
|
|
(Cfg.Node.get_instrs node) in
|
|
|
|
if verbose then L.stdout "%a\n@." pp constants;
|
|
|
|
if verbose then L.stdout "%a\n@." pp constants;
|
|
|
|
[constants], [constants]
|
|
|
|
[constants], [constants]
|
|
|
|
end)
|
|
|
|
end)
|
|
|
|
|
|
|
|
|
|
|
|
let run proc_desc =
|
|
|
|
let run proc_desc =
|
|
|
|
let transitions = ConstantFlow.run proc_desc ConstantMap.empty in
|
|
|
|
let transitions = ConstantFlow.run proc_desc ConstantMap.empty in
|
|
|
@ -128,3 +120,15 @@ let run proc_desc =
|
|
|
|
| ConstantFlow.Transition (_, post_states, _) -> ConstantFlow.join post_states ConstantMap.empty
|
|
|
|
| ConstantFlow.Transition (_, post_states, _) -> ConstantFlow.join post_states ConstantMap.empty
|
|
|
|
| ConstantFlow.Dead_state -> ConstantMap.empty in
|
|
|
|
| ConstantFlow.Dead_state -> ConstantMap.empty in
|
|
|
|
get_constants
|
|
|
|
get_constants
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type const_map = Cfg.Node.t -> Sil.exp -> Sil.const option
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(** Build a const map lazily. *)
|
|
|
|
|
|
|
|
let build_const_map pdesc =
|
|
|
|
|
|
|
|
let const_map = lazy (run pdesc) in
|
|
|
|
|
|
|
|
let f node exp =
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
let map = (Lazy.force const_map) node in
|
|
|
|
|
|
|
|
ConstantMap.find exp map
|
|
|
|
|
|
|
|
with Not_found -> None in
|
|
|
|
|
|
|
|
f
|
|
|
|