[Cost, InferBo] generalize ArrayLists to Collections and Iterators

Reviewed By: mbouaziz

Differential Revision: D9150202

fbshipit-source-id: 0b7f60058
master
Ezgi Çiçek 6 years ago committed by Facebook Github Bot
parent 9022228804
commit bedf32bed5

@ -144,6 +144,27 @@ let name_cons
{on_objc_cpp; on_qual_name; get_markers} {on_objc_cpp; on_qual_name; get_markers}
let name_cons_f
: ('context, 'f_in, 'f_out, 'captured_types, 'markers_in, 'markers_out, _) path_matcher
-> ('context -> string -> bool)
-> ('context, 'f_in, 'f_out, 'captured_types, 'markers_in, 'markers_out) name_matcher =
fun m f_name ->
let {on_templated_name; get_markers} = m in
let on_qual_name context f qual_name =
match QualifiedCppName.extract_last qual_name with
| Some (last, rest) when f_name context last ->
on_templated_name context f (rest, [])
| _ ->
None
in
let on_objc_cpp context f (objc_cpp: Typ.Procname.ObjC_Cpp.t) =
if f_name context objc_cpp.method_name then
on_templated_name context f (templated_name_of_class_name objc_cpp.class_name)
else None
in
{on_objc_cpp; on_qual_name; get_markers}
let all_names_cons let all_names_cons
: ('context, 'f_in, 'f_out, 'captured_types, 'markers_in, 'markers_out, non_empty) path_matcher : ('context, 'f_in, 'f_out, 'captured_types, 'markers_in, 'markers_out, non_empty) path_matcher
-> ( 'context -> ( 'context
@ -321,6 +342,10 @@ module type Common = sig
val ( ~- ) : string -> ('context, 'f, 'f, unit, 'markers, 'markers) name_matcher val ( ~- ) : string -> ('context, 'f, 'f, unit, 'markers, 'markers) name_matcher
(** Starts a path with a name *) (** Starts a path with a name *)
val ( ~+ ) :
('context -> string -> bool) -> ('context, 'f, 'f, unit, 'markers, 'markers) name_matcher
(** Starts a path with a matching name that satisfies the given function *)
val ( &+ ) : val ( &+ ) :
( 'context ( 'context
, 'f_in , 'f_in
@ -469,6 +494,8 @@ module Common = struct
let ( ~- ) name = empty &::! name let ( ~- ) name = empty &::! name
let ( ~+ ) f_name = name_cons_f empty f_name
let ( &+ ) templ_matcher template_arg = templ_cons templ_matcher template_arg let ( &+ ) templ_matcher template_arg = templ_cons templ_matcher template_arg
let ( &+...>! ) templ_matcher () = templ_matcher &+ any_template_args >! () let ( &+...>! ) templ_matcher () = templ_matcher &+ any_template_args >! ()

@ -103,6 +103,10 @@ module type Common = sig
val ( ~- ) : string -> ('context, 'f, 'f, unit, 'markers, 'markers) name_matcher val ( ~- ) : string -> ('context, 'f, 'f, unit, 'markers, 'markers) name_matcher
(** Starts a path with a name *) (** Starts a path with a name *)
val ( ~+ ) :
('context -> string -> bool) -> ('context, 'f, 'f, unit, 'markers, 'markers) name_matcher
(** Starts a path with a matching name that satisfies the given function *)
val ( &+ ) : val ( &+ ) :
( 'context ( 'context
, 'f_in , 'f_in

@ -49,6 +49,15 @@ let is_subtype_of_str tenv cn1 classname_str =
is_subtype tenv cn1 typename is_subtype tenv cn1 typename
let implements interface tenv typename =
let is_interface s _ = String.equal interface (Typ.Name.name s) in
supertype_exists tenv is_interface (Typ.Name.Java.from_string typename)
let implements_iterator = implements "java.util.Iterator"
let implements_collection = implements "java.util.Collection"
(** The type the method is invoked on *) (** The type the method is invoked on *)
let get_this_type proc_attributes = let get_this_type proc_attributes =
match proc_attributes.ProcAttributes.formals with (_, t) :: _ -> Some t | _ -> None match proc_attributes.ProcAttributes.formals with (_, t) :: _ -> Some t | _ -> None

@ -30,6 +30,12 @@ val is_subtype : Tenv.t -> Typ.Name.t -> Typ.Name.t -> bool
val is_subtype_of_str : Tenv.t -> Typ.Name.t -> string -> bool val is_subtype_of_str : Tenv.t -> Typ.Name.t -> string -> bool
(** Resolve [typ_str] in [tenv], then check [typ] <: [typ_str] *) (** Resolve [typ_str] in [tenv], then check [typ] <: [typ_str] *)
val implements_iterator : Tenv.t -> string -> bool
(** Check whether class implements Java's Iterator *)
val implements_collection : Tenv.t -> string -> bool
(** Check whether class implements a Java's Collection *)
val supertype_exists : Tenv.t -> (Typ.Name.t -> Typ.Struct.t -> bool) -> Typ.Name.t -> bool val supertype_exists : Tenv.t -> (Typ.Name.t -> Typ.Struct.t -> bool) -> Typ.Name.t -> bool
(** Holds iff the predicate holds on a supertype of the named type, including the type itself *) (** Holds iff the predicate holds on a supertype of the named type, including the type itself *)

@ -176,7 +176,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Prune (exp, _, _, _) -> | Prune (exp, _, _, _) ->
Sem.Prune.prune exp mem Sem.Prune.prune exp mem
| Call (ret, Const (Cfun callee_pname), params, location, _) -> ( | Call (ret, Const (Cfun callee_pname), params, location, _) -> (
match Models.Call.dispatch () callee_pname params with match Models.Call.dispatch tenv callee_pname params with
| Some {Models.exec} -> | Some {Models.exec} ->
let node_hash = CFG.Node.hash node in let node_hash = CFG.Node.hash node in
let model_env = let model_env =
@ -268,7 +268,7 @@ module Init = struct
pname symbol_table path tenv ~node_hash location ~depth loc elt ~offset ?size pname symbol_table path tenv ~node_hash location ~depth loc elt ~offset ?size
~inst_num ~new_sym_num ~new_alloc_num mem ~inst_num ~new_sym_num ~new_alloc_num mem
| Typ.Tstruct typename -> ( | Typ.Tstruct typename -> (
match Models.TypName.dispatch () typename with match Models.TypName.dispatch tenv typename with
| Some {Models.declare_symbolic} -> | Some {Models.declare_symbolic} ->
let model_env = Models.mk_model_env pname node_hash location tenv symbol_table in let model_env = Models.mk_model_env pname node_hash location tenv symbol_table in
declare_symbolic ~decl_sym_val:(decl_sym_val ~may_last_field) path model_env ~depth declare_symbolic ~decl_sym_val:(decl_sym_val ~may_last_field) path model_env ~depth
@ -325,7 +325,7 @@ module Init = struct
BoUtils.Exec.decl_local_array ~decl_local pname ~node_hash location loc typ ~length BoUtils.Exec.decl_local_array ~decl_local pname ~node_hash location loc typ ~length
?stride ~inst_num ~dimension mem ?stride ~inst_num ~dimension mem
| Typ.Tstruct typname -> ( | Typ.Tstruct typname -> (
match Models.TypName.dispatch () typname with match Models.TypName.dispatch tenv typname with
| Some {Models.declare_local} -> | Some {Models.declare_local} ->
let model_env = Models.mk_model_env pname node_hash location tenv symbol_table in let model_env = Models.mk_model_env pname node_hash location tenv symbol_table in
declare_local ~decl_local model_env loc ~inst_num ~dimension mem declare_local ~decl_local model_env loc ~inst_num ~dimension mem
@ -477,7 +477,7 @@ module Report = struct
| Sil.Load (_, exp, _, location) | Sil.Store (exp, _, _, location) -> | Sil.Load (_, exp, _, location) | Sil.Store (exp, _, _, location) ->
check_expr pname exp location mem cond_set check_expr pname exp location mem cond_set
| Sil.Call (_, Const (Cfun callee_pname), params, location, _) -> ( | Sil.Call (_, Const (Cfun callee_pname), params, location, _) -> (
match Models.Call.dispatch () callee_pname params with match Models.Call.dispatch tenv callee_pname params with
| Some {Models.check} -> | Some {Models.check} ->
let node_hash = CFG.Node.hash node in let node_hash = CFG.Node.hash node in
check (Models.mk_model_env pname node_hash location tenv symbol_table) mem cond_set check (Models.mk_model_env pname node_hash location tenv symbol_table) mem cond_set

@ -303,18 +303,18 @@ module StdArray = struct
{declare_local; declare_symbolic} {declare_local; declare_symbolic}
end end
(* Java's ArrayLists are represented by their size. We don't care about the elements. (* Java's Collections are represented by their size. We don't care about the elements.
- when they are constructed, we set the size to 0 - when they are constructed, we set the size to 0
- each time we add an element, we increase the length of the array - each time we add an element, we increase the length of the array
- each time we delete an element, we decrease the length of the array *) - each time we delete an element, we decrease the length of the array *)
module ArrayList = struct module Collection = struct
let typ = let typ =
let declare_local ~decl_local:_ {pname; node_hash; location} loc ~inst_num ~dimension mem = let declare_local ~decl_local:_ {pname; node_hash; location} loc ~inst_num ~dimension mem =
BoUtils.Exec.decl_local_arraylist pname ~node_hash location loc ~inst_num ~dimension mem BoUtils.Exec.decl_local_collection pname ~node_hash location loc ~inst_num ~dimension mem
in in
let declare_symbolic ~decl_sym_val:_ path {pname; location; symbol_table} ~depth:_ loc let declare_symbolic ~decl_sym_val:_ path {pname; location; symbol_table} ~depth:_ loc
~inst_num:_ ~new_sym_num ~new_alloc_num:_ mem = ~inst_num:_ ~new_sym_num ~new_alloc_num:_ mem =
BoUtils.Exec.decl_sym_arraylist pname symbol_table path location loc ~new_sym_num mem BoUtils.Exec.decl_sym_collection pname symbol_table path location loc ~new_sym_num mem
in in
{declare_local; declare_symbolic} {declare_local; declare_symbolic}
@ -383,7 +383,7 @@ module ArrayList = struct
let add_at_index (alist_id: Ident.t) index_exp = let add_at_index (alist_id: Ident.t) index_exp =
let check {pname; location} mem cond_set = let check {pname; location} mem cond_set =
let array_exp = Exp.Var alist_id in let array_exp = Exp.Var alist_id in
BoUtils.Check.arraylist_access ~array_exp ~index_exp ~is_arraylist_add:true mem pname BoUtils.Check.collection_access ~array_exp ~index_exp ~is_collection_add:true mem pname
location cond_set location cond_set
in in
{exec= change_size_by ~size_f:incr_size alist_id; check} {exec= change_size_by ~size_f:incr_size alist_id; check}
@ -392,7 +392,7 @@ module ArrayList = struct
let remove_at_index alist_id index_exp = let remove_at_index alist_id index_exp =
let check {pname; location} mem cond_set = let check {pname; location} mem cond_set =
let array_exp = Exp.Var alist_id in let array_exp = Exp.Var alist_id in
BoUtils.Check.arraylist_access ~array_exp ~index_exp mem pname location cond_set BoUtils.Check.collection_access ~array_exp ~index_exp mem pname location cond_set
in in
{exec= change_size_by ~size_f:decr_size alist_id; check} {exec= change_size_by ~size_f:decr_size alist_id; check}
@ -404,7 +404,7 @@ module ArrayList = struct
in in
let check {pname; location} mem cond_set = let check {pname; location} mem cond_set =
let array_exp = Exp.Var alist_id in let array_exp = Exp.Var alist_id in
BoUtils.Check.arraylist_access ~index_exp ~array_exp ~is_arraylist_add:true mem pname BoUtils.Check.collection_access ~index_exp ~array_exp ~is_collection_add:true mem pname
location cond_set location cond_set
in in
{exec; check} {exec; check}
@ -414,13 +414,13 @@ module ArrayList = struct
let exec _model_env ~ret:_ mem = mem in let exec _model_env ~ret:_ mem = mem in
let check {pname; location} mem cond_set = let check {pname; location} mem cond_set =
let array_exp = Exp.Var alist_id in let array_exp = Exp.Var alist_id in
BoUtils.Check.arraylist_access ~index_exp ~array_exp mem pname location cond_set BoUtils.Check.collection_access ~index_exp ~array_exp mem pname location cond_set
in in
{exec; check} {exec; check}
end end
module Call = struct module Call = struct
let dispatch : (unit, model) ProcnameDispatcher.Call.dispatcher = let dispatch : (Tenv.t, model) ProcnameDispatcher.Call.dispatcher =
let open ProcnameDispatcher.Call in let open ProcnameDispatcher.Call in
let mk_std_array () = -"std" &:: "array" < any_typ &+ capt_int in let mk_std_array () = -"std" &:: "array" < any_typ &+ capt_int in
let std_array0 = mk_std_array () in let std_array0 = mk_std_array () in
@ -433,7 +433,8 @@ module Call = struct
; -"fgetc" <>--> by_value Dom.Val.Itv.m1_255 ; -"fgetc" <>--> by_value Dom.Val.Itv.m1_255
; -"infer_print" <>$ capt_exp $!--> infer_print ; -"infer_print" <>$ capt_exp $!--> infer_print
; -"malloc" <>$ capt_exp $+...$--> malloc ; -"malloc" <>$ capt_exp $+...$--> malloc
; -"__new" <>$ capt_exp_of_typ (-"java.util.ArrayList") $+...$--> ArrayList.new_list ; -"__new" <>$ capt_exp_of_typ (+PatternMatch.implements_collection)
$+...$--> Collection.new_list
; -"__new" <>$ capt_exp $+...$--> malloc ; -"__new" <>$ capt_exp $+...$--> malloc
; -"__new_array" <>$ capt_exp $+...$--> malloc ; -"__new_array" <>$ capt_exp $+...$--> malloc
; -"__placement_new" <>$ any_arg $+ capt_exp $!--> placement_new ; -"__placement_new" <>$ any_arg $+ capt_exp $!--> placement_new
@ -449,29 +450,31 @@ module Call = struct
; std_array2 >:: "at" $ capt_arg $+ capt_arg $!--> StdArray.at ; std_array2 >:: "at" $ capt_arg $+ capt_arg $!--> StdArray.at
; std_array2 >:: "operator[]" $ capt_arg $+ capt_arg $!--> StdArray.at ; std_array2 >:: "operator[]" $ capt_arg $+ capt_arg $!--> StdArray.at
; -"std" &:: "array" &::.*--> StdArray.no_model ; -"std" &:: "array" &::.*--> StdArray.no_model
; -"java.util.ArrayList" &:: "get" <>$ capt_var_exn $+ capt_exp ; +PatternMatch.implements_collection &:: "get" <>$ capt_var_exn $+ capt_exp
$--> ArrayList.get_or_set_at_index $--> Collection.get_or_set_at_index
; -"java.util.ArrayList" &:: "set" <>$ capt_var_exn $+ capt_exp $+ any_arg ; +PatternMatch.implements_collection &:: "set" <>$ capt_var_exn $+ capt_exp $+ any_arg
$--> ArrayList.get_or_set_at_index $--> Collection.get_or_set_at_index
; -"java.util.ArrayList" &:: "remove" <>$ capt_var_exn $+ capt_exp ; +PatternMatch.implements_collection &:: "remove" <>$ capt_var_exn $+ capt_exp
$--> ArrayList.remove_at_index $--> Collection.remove_at_index
; -"java.util.ArrayList" &:: "add" <>$ capt_var_exn $+ any_arg $--> ArrayList.add ; +PatternMatch.implements_collection &:: "add" <>$ capt_var_exn $+ any_arg
; -"java.util.ArrayList" &:: "add" <>$ capt_var_exn $+ capt_exp $+ any_arg $--> Collection.add
$!--> ArrayList.add_at_index ; +PatternMatch.implements_collection &:: "add" <>$ capt_var_exn $+ capt_exp $+ any_arg
; -"java.util.ArrayList" &:: "iterator" <>$ capt_exp $!--> ArrayList.iterator $!--> Collection.add_at_index
; -"java.util.Iterator" &:: "hasNext" <>$ capt_exp $!--> ArrayList.hasNext ; +PatternMatch.implements_collection &:: "iterator" <>$ capt_exp $!--> Collection.iterator
; -"java.util.ArrayList" &:: "addAll" <>$ capt_var_exn $+ capt_exp $--> ArrayList.addAll ; +PatternMatch.implements_iterator &:: "hasNext" <>$ capt_exp $!--> Collection.hasNext
; -"java.util.ArrayList" &:: "addAll" <>$ capt_var_exn $+ capt_exp $+ capt_exp ; +PatternMatch.implements_collection &:: "addAll" <>$ capt_var_exn $+ capt_exp
$!--> ArrayList.addAll_at_index $--> Collection.addAll
; -"java.util.ArrayList" &:: "size" <>$ capt_exp $!--> ArrayList.size ] ; +PatternMatch.implements_collection &:: "addAll" <>$ capt_var_exn $+ capt_exp $+ capt_exp
$!--> Collection.addAll_at_index
; +PatternMatch.implements_collection &:: "size" <>$ capt_exp $!--> Collection.size ]
end end
module TypName = struct module TypName = struct
let dispatch : (unit, typ_model) ProcnameDispatcher.TypName.dispatcher = let dispatch : (Tenv.t, typ_model) ProcnameDispatcher.TypName.dispatcher =
let open ProcnameDispatcher.TypName in let open ProcnameDispatcher.TypName in
make_dispatcher make_dispatcher
[ -"std" &:: "array" < capt_typ `T &+ capt_int >--> StdArray.typ [ -"std" &:: "array" < capt_typ `T &+ capt_int >--> StdArray.typ
; -"java.util.Iterator" &::.*--> ArrayList.typ ; +PatternMatch.implements_collection &::.*--> Collection.typ
; -"java.util.ArrayList" &::.*--> ArrayList.typ ; +PatternMatch.implements_iterator &::.*--> Collection.typ
; -"std" &:: "array" &::.*--> StdArray.no_typ_model ] ; -"std" &:: "array" &::.*--> StdArray.no_typ_model ]
end end

@ -215,15 +215,15 @@ module ArrayAccessCondition = struct
(* check buffer overrun and return its confidence *) (* check buffer overrun and return its confidence *)
let check : is_arraylist_add:bool -> t -> checked_condition = let check : is_collection_add:bool -> t -> checked_condition =
fun ~is_arraylist_add c -> fun ~is_collection_add c ->
(* idx = [il, iu], size = [sl, su], (* idx = [il, iu], size = [sl, su],
For arrays : we want to check that 0 <= idx < size For arrays : we want to check that 0 <= idx < size
For adding into arraylists: we want to check that 0 <= idx <= size *) For adding into arraylists: we want to check that 0 <= idx <= size *)
let c' = set_size_pos c in let c' = set_size_pos c in
(* if sl < 0, use sl' = 0 *) (* if sl < 0, use sl' = 0 *)
let not_overrun = let not_overrun =
if is_arraylist_add then ItvPure.le_sem c'.idx c'.size if is_collection_add then ItvPure.le_sem c'.idx c'.size
else if Relation.lt_sat_opt c'.idx_sym_exp c'.size_sym_exp c'.relation then Itv.Boolean.true_ else if Relation.lt_sat_opt c'.idx_sym_exp c'.size_sym_exp c'.relation then Itv.Boolean.true_
else ItvPure.lt_sem c'.idx c'.size else ItvPure.lt_sem c'.idx c'.size
in in
@ -278,12 +278,12 @@ end
module Condition = struct module Condition = struct
type t = type t =
| AllocSize of AllocSizeCondition.t | AllocSize of AllocSizeCondition.t
| ArrayAccess of {is_arraylist_add: bool; c: ArrayAccessCondition.t} | ArrayAccess of {is_collection_add: bool; c: ArrayAccessCondition.t}
let make_alloc_size = Option.map ~f:(fun c -> AllocSize c) let make_alloc_size = Option.map ~f:(fun c -> AllocSize c)
let make_array_access ~is_arraylist_add = let make_array_access ~is_collection_add =
Option.map ~f:(fun c -> ArrayAccess {is_arraylist_add; c}) Option.map ~f:(fun c -> ArrayAccess {is_collection_add; c})
let get_symbols = function let get_symbols = function
@ -296,9 +296,9 @@ module Condition = struct
let subst bound_map rel_map caller_relation = function let subst bound_map rel_map caller_relation = function
| AllocSize c -> | AllocSize c ->
AllocSizeCondition.subst bound_map c |> make_alloc_size AllocSizeCondition.subst bound_map c |> make_alloc_size
| ArrayAccess {is_arraylist_add; c} -> | ArrayAccess {is_collection_add; c} ->
ArrayAccessCondition.subst bound_map rel_map caller_relation c ArrayAccessCondition.subst bound_map rel_map caller_relation c
|> make_array_access ~is_arraylist_add |> make_array_access ~is_collection_add
let have_similar_bounds c1 c2 = let have_similar_bounds c1 c2 =
@ -317,7 +317,7 @@ module Condition = struct
match (lhs, rhs) with match (lhs, rhs) with
| AllocSize lhs, AllocSize rhs -> | AllocSize lhs, AllocSize rhs ->
AllocSizeCondition.xcompare ~lhs ~rhs AllocSizeCondition.xcompare ~lhs ~rhs
| ArrayAccess {is_arraylist_add= b1; c= lhs}, ArrayAccess {is_arraylist_add= b2; c= rhs} | ArrayAccess {is_collection_add= b1; c= lhs}, ArrayAccess {is_collection_add= b2; c= rhs}
when Bool.equal b1 b2 -> when Bool.equal b1 b2 ->
ArrayAccessCondition.xcompare ~lhs ~rhs ArrayAccessCondition.xcompare ~lhs ~rhs
| _ -> | _ ->
@ -341,14 +341,14 @@ module Condition = struct
let check = function let check = function
| AllocSize c -> | AllocSize c ->
AllocSizeCondition.check c AllocSizeCondition.check c
| ArrayAccess {is_arraylist_add; c} -> | ArrayAccess {is_collection_add; c} ->
ArrayAccessCondition.check ~is_arraylist_add c ArrayAccessCondition.check ~is_collection_add c
let forget_locs locs x = let forget_locs locs x =
match x with match x with
| ArrayAccess {is_arraylist_add; c} -> | ArrayAccess {is_collection_add; c} ->
ArrayAccess {is_arraylist_add; c= ArrayAccessCondition.forget_locs locs c} ArrayAccess {is_collection_add; c= ArrayAccessCondition.forget_locs locs c}
| AllocSize _ -> | AllocSize _ ->
x x
end end
@ -534,10 +534,10 @@ module ConditionSet = struct
join [cwt] condset join [cwt] condset
let add_array_access pname location ~idx ~size ~is_arraylist_add ~idx_sym_exp ~size_sym_exp let add_array_access pname location ~idx ~size ~is_collection_add ~idx_sym_exp ~size_sym_exp
~relation val_traces condset = ~relation val_traces condset =
ArrayAccessCondition.make ~idx ~size ~idx_sym_exp ~size_sym_exp ~relation ArrayAccessCondition.make ~idx ~size ~idx_sym_exp ~size_sym_exp ~relation
|> Condition.make_array_access ~is_arraylist_add |> add_opt pname location val_traces condset |> Condition.make_array_access ~is_collection_add |> add_opt pname location val_traces condset
let add_alloc_size pname location ~length val_traces condset = let add_alloc_size pname location ~length val_traces condset =

@ -57,7 +57,7 @@ module Exec = struct
(mem, inst_num + 1) (mem, inst_num + 1)
let decl_local_arraylist let decl_local_collection
: Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> inst_num:int -> dimension:int : Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> inst_num:int -> dimension:int
-> Dom.Mem.astate -> Dom.Mem.astate * int = -> Dom.Mem.astate -> Dom.Mem.astate * int =
fun pname ~node_hash location loc ~inst_num ~dimension mem -> fun pname ~node_hash location loc ~inst_num ~dimension mem ->
@ -128,7 +128,7 @@ module Exec = struct
decl_sym_val pname path tenv ~node_hash location ~depth alloc_loc typ mem decl_sym_val pname path tenv ~node_hash location ~depth alloc_loc typ mem
let decl_sym_arraylist let decl_sym_collection
: Typ.Procname.t -> Itv.SymbolTable.t -> Itv.SymbolPath.partial -> Location.t -> Loc.t : Typ.Procname.t -> Itv.SymbolTable.t -> Itv.SymbolPath.partial -> Location.t -> Loc.t
-> new_sym_num:Itv.Counter.t -> Dom.Mem.astate -> Dom.Mem.astate = -> new_sym_num:Itv.Counter.t -> Dom.Mem.astate -> Dom.Mem.astate =
fun pname symbol_table path location loc ~new_sym_num mem -> fun pname symbol_table path location loc ~new_sym_num mem ->
@ -199,13 +199,13 @@ end
module Check = struct module Check = struct
let check_access ~size ~idx ~size_sym_exp ~idx_sym_exp ~relation ~arr ~idx_traces let check_access ~size ~idx ~size_sym_exp ~idx_sym_exp ~relation ~arr ~idx_traces
?(is_arraylist_add= false) pname location cond_set = ?(is_collection_add= false) pname location cond_set =
let arr_traces = Dom.Val.get_traces arr in let arr_traces = Dom.Val.get_traces arr in
match (size, idx) with match (size, idx) with
| NonBottom length, NonBottom idx -> | NonBottom length, NonBottom idx ->
let traces = TraceSet.merge ~arr_traces ~idx_traces location in let traces = TraceSet.merge ~arr_traces ~idx_traces location in
PO.ConditionSet.add_array_access pname location ~size:length ~idx ~size_sym_exp PO.ConditionSet.add_array_access pname location ~size:length ~idx ~size_sym_exp
~idx_sym_exp ~relation ~is_arraylist_add traces cond_set ~idx_sym_exp ~relation ~is_collection_add traces cond_set
| _ -> | _ ->
cond_set cond_set
@ -230,7 +230,8 @@ module Check = struct
location cond_set location cond_set
let arraylist_access ~array_exp ~index_exp ?(is_arraylist_add= false) mem pname location cond_set = let collection_access ~array_exp ~index_exp ?(is_collection_add= false) mem pname location
cond_set =
let idx = Sem.eval index_exp mem in let idx = Sem.eval index_exp mem in
let arr = Sem.eval array_exp mem in let arr = Sem.eval array_exp mem in
let idx_traces = Dom.Val.get_traces idx in let idx_traces = Dom.Val.get_traces idx in
@ -238,7 +239,7 @@ module Check = struct
let idx = Dom.Val.get_itv idx in let idx = Dom.Val.get_itv idx in
let relation = Dom.Mem.get_relation mem in let relation = Dom.Mem.get_relation mem in
check_access ~size ~idx ~size_sym_exp:None ~idx_sym_exp:None ~relation ~arr ~idx_traces check_access ~size ~idx ~size_sym_exp:None ~idx_sym_exp:None ~relation ~arr ~idx_traces
~is_arraylist_add pname location cond_set ~is_collection_add pname location cond_set
let lindex ~array_exp ~index_exp mem pname location cond_set = let lindex ~array_exp ~index_exp mem pname location cond_set =

@ -25,7 +25,7 @@ module Exec : sig
-> length:IntLit.t option -> ?stride:int -> inst_num:int -> dimension:int -> Dom.Mem.astate -> length:IntLit.t option -> ?stride:int -> inst_num:int -> dimension:int -> Dom.Mem.astate
-> Dom.Mem.astate * int -> Dom.Mem.astate * int
val decl_local_arraylist : val decl_local_collection :
Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> inst_num:int -> dimension:int Typ.Procname.t -> node_hash:int -> Location.t -> Loc.t -> inst_num:int -> dimension:int
-> Dom.Mem.astate -> Dom.Mem.astate * int -> Dom.Mem.astate -> Dom.Mem.astate * int
@ -44,7 +44,7 @@ module Exec : sig
-> node_hash:int -> Location.t -> depth:int -> Loc.t -> Typ.t -> inst_num:int -> node_hash:int -> Location.t -> depth:int -> Loc.t -> Typ.t -> inst_num:int
-> new_alloc_num:Itv.Counter.t -> Dom.Mem.astate -> Dom.Mem.astate -> new_alloc_num:Itv.Counter.t -> Dom.Mem.astate -> Dom.Mem.astate
val decl_sym_arraylist : val decl_sym_collection :
Typ.Procname.t -> Itv.SymbolTable.t -> Itv.SymbolPath.partial -> Location.t -> Loc.t Typ.Procname.t -> Itv.SymbolTable.t -> Itv.SymbolPath.partial -> Location.t -> Loc.t
-> new_sym_num:Itv.Counter.t -> Dom.Mem.astate -> Dom.Mem.astate -> new_sym_num:Itv.Counter.t -> Dom.Mem.astate -> Dom.Mem.astate
@ -65,7 +65,7 @@ module Check : sig
array_exp:Exp.t -> index_exp:Exp.t -> Dom.Mem.astate -> Typ.Procname.t -> Location.t array_exp:Exp.t -> index_exp:Exp.t -> Dom.Mem.astate -> Typ.Procname.t -> Location.t
-> PO.ConditionSet.t -> PO.ConditionSet.t -> PO.ConditionSet.t -> PO.ConditionSet.t
val arraylist_access : val collection_access :
array_exp:Exp.t -> index_exp:Exp.t -> ?is_arraylist_add:bool -> Dom.Mem.astate array_exp:Exp.t -> index_exp:Exp.t -> ?is_collection_add:bool -> Dom.Mem.astate
-> Typ.Procname.t -> Location.t -> PO.ConditionSet.t -> PO.ConditionSet.t -> Typ.Procname.t -> Location.t -> PO.ConditionSet.t -> PO.ConditionSet.t
end end

@ -0,0 +1,34 @@
/*
* Copyright (c) 2018-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import java.util.Collection;
import java.util.Iterator;
import java.util.concurrent.ConcurrentLinkedQueue;
public class CollectionTest {
interface MyCollection<E> extends Collection<E> {}
void iterate_over_mycollection(MyCollection<Integer> list) {
for (int i = 0, size = list.size(); i < size; ++i) {}
}
void iterate_over_some_java_collection(
ConcurrentLinkedQueue<MyCollection<Integer>> mSubscribers) {
for (MyCollection<Integer> list : mSubscribers) {
}
}
// Expected |mSubscribers| * |list| but we get T
// because we are not tracking elements of collections
void iterate_over_mycollection_quad_FP(
ConcurrentLinkedQueue<MyCollection<Integer>> mSubscribers) {
for (MyCollection<Integer> list : mSubscribers) {
iterate_over_mycollection(list);
}
}
}

@ -38,6 +38,11 @@ codetoanalyze/java/performance/Break.java, int Break.break_constant(int), 2, EXP
codetoanalyze/java/performance/Break.java, int Break.break_loop(int,int), 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1 + 7 * p.ub, degree = 1] codetoanalyze/java/performance/Break.java, int Break.break_loop(int,int), 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 1 + 7 * p.ub, degree = 1]
codetoanalyze/java/performance/Break.java, int Break.break_loop(int,int), 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2 + 7 * p.ub, degree = 1] codetoanalyze/java/performance/Break.java, int Break.break_loop(int,int), 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 2 + 7 * p.ub, degree = 1]
codetoanalyze/java/performance/Break.java, void Break.break_outer_loop_FN(int,int), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, [] codetoanalyze/java/performance/Break.java, void Break.break_outer_loop_FN(int,int), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, []
codetoanalyze/java/performance/CollectionTest.java, void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection), 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 5 * list.length.ub, degree = 1]
codetoanalyze/java/performance/CollectionTest.java, void CollectionTest.iterate_over_mycollection(CollectionTest$MyCollection), 1, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 6 + 5 * list.length.ub, degree = 1]
codetoanalyze/java/performance/CollectionTest.java, void CollectionTest.iterate_over_mycollection_quad_FP(ConcurrentLinkedQueue), 0, INFINITE_EXECUTION_TIME_CALL, no_bucket, ERROR, []
codetoanalyze/java/performance/CollectionTest.java, void CollectionTest.iterate_over_some_java_collection(ConcurrentLinkedQueue), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 4 + 9 * (mSubscribers.length.ub + -1) + 4 * mSubscribers.length.ub, degree = 1]
codetoanalyze/java/performance/CollectionTest.java, void CollectionTest.iterate_over_some_java_collection(ConcurrentLinkedQueue), 2, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 9 * (mSubscribers.length.ub + -1) + 4 * mSubscribers.length.ub, degree = 1]
codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [] codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, []
codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 7 * m.ub, degree = 1] codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 3, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 7 * m.ub, degree = 1]
codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 7 * m.ub, degree = 1] codetoanalyze/java/performance/Compound_loop.java, int Compound_loop.compound_while(int), 4, EXPENSIVE_EXECUTION_TIME_CALL, no_bucket, ERROR, [with estimated cost 5 + 7 * m.ub, degree = 1]

Loading…
Cancel
Save