[ConfigImpact] Add known cheap builtin callee: __cast

Summary:
It introduced a FP due to reporting addition of `__cast`.

* This diff added known cheap model for `__cast`.
* In addition, moved `match_builtin` to `BuiltinDecl`.

Reviewed By: ezgicicek

Differential Revision: D27791495

fbshipit-source-id: 55aec1728
master
Sungkeun Cho 4 years ago committed by Facebook GitHub Bot
parent ad2fc1148d
commit e98fe8d24c

@ -184,3 +184,5 @@ let vwscanf = create_procname "vwscanf"
let wscanf = create_procname "wscanf"
let zero_initialization = create_procname "__infer_zero_initialization"
let match_builtin builtin _ s = String.equal s (Procname.get_method builtin)

@ -20,3 +20,5 @@ val __infer_skip_function : Procname.t
val __infer_skip_gcc_asm_stmt : Procname.t
val __infer_generic_selection_expr : Procname.t
val match_builtin : t -> 'a -> string -> bool

@ -1642,30 +1642,29 @@ module Call = struct
let short_typ = Typ.mk (Typ.Tint Typ.IUShort) in
let char_ptr = Typ.mk (Typ.Tptr (char_typ, Pk_pointer)) in
let short_array = Typ.mk (Typ.Tptr (Typ.mk_array short_typ, Pk_pointer)) in
let match_builtin builtin _ s = String.equal s (Procname.get_method builtin) in
make_dispatcher
[ (* Clang common models *)
+match_builtin BuiltinDecl.__cast <>$ capt_exp $+ capt_exp $+...$--> cast
; +match_builtin BuiltinDecl.__exit <>--> bottom
; +match_builtin BuiltinDecl.__get_array_length <>$ capt_exp $!--> get_array_length
; +match_builtin BuiltinDecl.objc_cpp_throw <>--> bottom
; +match_builtin BuiltinDecl.__new
+BuiltinDecl.(match_builtin __cast) <>$ capt_exp $+ capt_exp $+...$--> cast
; +BuiltinDecl.(match_builtin __exit) <>--> bottom
; +BuiltinDecl.(match_builtin __get_array_length) <>$ capt_exp $!--> get_array_length
; +BuiltinDecl.(match_builtin objc_cpp_throw) <>--> bottom
; +BuiltinDecl.(match_builtin __new)
<>$ any_arg_of_typ (+PatternMatch.Java.implements_collection)
$+...$--> Collection.new_collection
; +match_builtin BuiltinDecl.__new
; +BuiltinDecl.(match_builtin __new)
<>$ any_arg_of_typ (+PatternMatch.Java.implements_map)
$+...$--> Collection.new_collection
; +match_builtin BuiltinDecl.__new
; +BuiltinDecl.(match_builtin __new)
<>$ any_arg_of_typ (+PatternMatch.Java.implements_org_json "JSONArray")
$+...$--> Collection.new_collection
; +match_builtin BuiltinDecl.__new
; +BuiltinDecl.(match_builtin __new)
<>$ any_arg_of_typ (+PatternMatch.Java.implements_pseudo_collection)
$+...$--> Collection.new_collection
; +match_builtin BuiltinDecl.__new <>$ capt_exp $+...$--> malloc ~can_be_zero:true
; +match_builtin BuiltinDecl.__new_array <>$ capt_exp $+...$--> malloc ~can_be_zero:true
; +match_builtin BuiltinDecl.__placement_new
; +BuiltinDecl.(match_builtin __new) <>$ capt_exp $+...$--> malloc ~can_be_zero:true
; +BuiltinDecl.(match_builtin __new_array) <>$ capt_exp $+...$--> malloc ~can_be_zero:true
; +BuiltinDecl.(match_builtin __placement_new)
<>$ capt_exp $+ capt_arg $+? capt_arg $!--> placement_new
; +match_builtin BuiltinDecl.__set_array_length
; +BuiltinDecl.(match_builtin __set_array_length)
<>$ capt_arg $+ capt_exp $!--> set_array_length
; -"calloc" <>$ capt_exp $+ capt_exp $!--> calloc ~can_be_zero:false
; -"exit" <>--> bottom
@ -1685,7 +1684,7 @@ module Call = struct
; -"strndup" <>$ capt_exp $+ capt_exp $+...$--> strndup
; -"vsnprintf" <>--> by_value Dom.Val.Itv.nat
; (* ObjC models *)
+match_builtin BuiltinDecl.__objc_alloc_no_fail <>$ capt_exp $+...$--> objc_malloc
+BuiltinDecl.(match_builtin __objc_alloc_no_fail) <>$ capt_exp $+...$--> objc_malloc
; -"CFArrayCreate" <>$ any_arg $+ capt_exp $+ capt_exp
$+...$--> NSCollection.create_from_array
; -"CFArrayCreateCopy" <>$ any_arg $+ capt_exp $!--> create_copy_array

@ -40,13 +40,12 @@ let getStarValue tenv s =
module ProcName = struct
let dispatch : (Tenv.t, PurityDomain.t, unit) ProcnameDispatcher.ProcName.dispatcher =
let open ProcnameDispatcher.ProcName in
let match_builtin builtin _ s = String.equal s (Procname.get_method builtin) in
make_dispatcher
[ +pure_builtins <>--> PurityDomain.pure
; -"__variable_initialization" <>--> PurityDomain.pure
; +match_builtin BuiltinDecl.__new <>--> PurityDomain.pure
; +match_builtin BuiltinDecl.__new_array <>--> PurityDomain.pure
; +match_builtin BuiltinDecl.__cast <>--> PurityDomain.pure
; +BuiltinDecl.(match_builtin __new) <>--> PurityDomain.pure
; +BuiltinDecl.(match_builtin __new_array) <>--> PurityDomain.pure
; +BuiltinDecl.(match_builtin __cast) <>--> PurityDomain.pure
; -"__variable_initialization" <>--> PurityDomain.pure
; +(fun _ name -> BuiltinDecl.is_declared (Procname.from_string_c_fun name))
<>--> PurityDomain.impure_global

@ -341,33 +341,56 @@ module Dom = struct
fields field_checks } )
let is_known_expensive_method =
let dispatch : (Tenv.t, unit, unit) ProcnameDispatcher.Call.dispatcher =
type known_expensiveness = KnownCheap | KnownExpensive
let get_expensiveness_model =
let dispatch : (Tenv.t, known_expensiveness, unit) ProcnameDispatcher.Call.dispatcher =
let open ProcnameDispatcher.Call in
make_dispatcher
[ +PatternMatch.Java.implements_google "common.base.Preconditions"
&:: "checkArgument" $ any_arg $+ any_arg $+...$--> ()
[ +BuiltinDecl.(match_builtin __cast) <>--> KnownCheap
; +PatternMatch.Java.implements_google "common.base.Preconditions"
&:: "checkArgument" $ any_arg $+ any_arg $+...$--> KnownExpensive
; +PatternMatch.Java.implements_google "common.base.Preconditions"
&:: "checkElementIndex" $ any_arg $+ any_arg $+ any_arg $+...$--> ()
&:: "checkElementIndex" $ any_arg $+ any_arg $+ any_arg $+...$--> KnownExpensive
; +PatternMatch.Java.implements_google "common.base.Preconditions"
&:: "checkNotNull" $ any_arg $+ any_arg $+...$--> ()
&:: "checkNotNull" $ any_arg $+ any_arg $+...$--> KnownExpensive
; +PatternMatch.Java.implements_google "common.base.Preconditions"
&:: "checkPositionIndex" $ any_arg $+ any_arg $+ any_arg $+...$--> ()
&:: "checkPositionIndex" $ any_arg $+ any_arg $+ any_arg $+...$--> KnownExpensive
; +PatternMatch.Java.implements_google "common.base.Preconditions"
&:: "checkState" $ any_arg $+ any_arg $+...$--> ()
; +PatternMatch.Java.implements_lang "String" &:: "concat" &--> ()
; +PatternMatch.Java.implements_lang "StringBuilder" &:: "append" &--> () ]
&:: "checkState" $ any_arg $+ any_arg $+...$--> KnownExpensive
; +PatternMatch.Java.implements_lang "String" &:: "concat" &--> KnownExpensive
; +PatternMatch.Java.implements_lang "StringBuilder" &:: "append" &--> KnownExpensive ]
in
fun tenv pname args ->
let args =
List.map args ~f:(fun (exp, typ) ->
ProcnameDispatcher.Call.FuncArg.{exp; typ; arg_payload= ()} )
in
dispatch tenv pname args |> Option.is_some
dispatch tenv pname args
let call tenv analyze_dependency ~is_cheap_call callee args location
({config_checks; field_checks; unchecked_callees; unchecked_callees_cond} as astate) =
let join_unchecked_callees new_unchecked_callees new_unchecked_callees_cond =
if FieldChecks.is_top field_checks then
{ astate with
unchecked_callees= UncheckedCallees.join unchecked_callees new_unchecked_callees
; unchecked_callees_cond=
UncheckedCalleesCond.join unchecked_callees_cond new_unchecked_callees_cond }
else
let fields_to_add = FieldChecks.get_fields field_checks in
let unchecked_callees_cond =
UncheckedCalleesCond.weak_update fields_to_add new_unchecked_callees
unchecked_callees_cond
in
let unchecked_callees_cond =
UncheckedCalleesCond.fold
(fun fields callees acc ->
UncheckedCalleesCond.weak_update (Fields.union fields fields_to_add) callees acc )
new_unchecked_callees_cond unchecked_callees_cond
in
{astate with unchecked_callees_cond}
in
if ConfigChecks.is_top config_checks then
let (callee_summary : Summary.t option) =
match analyze_dependency callee with
@ -376,53 +399,40 @@ module Dom = struct
| Some (_, (_, analysis_data, _)) ->
analysis_data
in
let is_expensive = is_known_expensive_method tenv callee args in
let expensiveness_model = get_expensiveness_model tenv callee args in
let has_expensive_callee =
Option.exists callee_summary ~f:Summary.has_known_expensive_callee
in
if is_cheap_call && (not is_expensive) && not has_expensive_callee then
(* If callee is cheap by heuristics, ignore it. *)
astate
else
let new_unchecked_callees, new_unchecked_callees_cond =
if is_expensive then
( UncheckedCallees.singleton
(UncheckedCallee.make ~is_known_expensive:true callee location)
, UncheckedCalleesCond.empty )
else
match callee_summary with
| Some
{ Summary.unchecked_callees= callee_summary
; unchecked_callees_cond= callee_summary_cond
; has_call_stmt }
when has_call_stmt ->
(* If callee's summary is not leaf, use it. *)
( UncheckedCallees.replace_location_by_call location callee_summary
, UncheckedCalleesCond.replace_location_by_call location callee_summary_cond )
| _ ->
(* Otherwise, add callee's name. *)
( UncheckedCallees.singleton
(UncheckedCallee.make ~is_known_expensive:false callee location)
, UncheckedCalleesCond.empty )
in
if FieldChecks.is_top field_checks then
{ astate with
unchecked_callees= UncheckedCallees.join unchecked_callees new_unchecked_callees
; unchecked_callees_cond=
UncheckedCalleesCond.join unchecked_callees_cond new_unchecked_callees_cond }
else
let fields_to_add = FieldChecks.get_fields field_checks in
let unchecked_callees_cond =
UncheckedCalleesCond.weak_update fields_to_add new_unchecked_callees
unchecked_callees_cond
in
let unchecked_callees_cond =
UncheckedCalleesCond.fold
(fun fields callees acc ->
UncheckedCalleesCond.weak_update (Fields.union fields fields_to_add) callees acc )
new_unchecked_callees_cond unchecked_callees_cond
in
{astate with unchecked_callees_cond}
match expensiveness_model with
| None when is_cheap_call && not has_expensive_callee ->
(* If callee is cheap by heuristics, ignore it. *)
astate
| Some KnownCheap ->
(* If callee is known cheap by model, ignore it. *)
astate
| Some KnownExpensive ->
(* If callee is known expensive by model, add callee's name. *)
join_unchecked_callees
(UncheckedCallees.singleton
(UncheckedCallee.make ~is_known_expensive:true callee location))
UncheckedCalleesCond.empty
| None -> (
match callee_summary with
| Some
{ Summary.unchecked_callees= callee_summary
; unchecked_callees_cond= callee_summary_cond
; has_call_stmt }
when has_call_stmt ->
(* If callee's summary is not leaf, use it. *)
join_unchecked_callees
(UncheckedCallees.replace_location_by_call location callee_summary)
(UncheckedCalleesCond.replace_location_by_call location callee_summary_cond)
| _ ->
(* Otherwise, add callee's name. *)
join_unchecked_callees
(UncheckedCallees.singleton
(UncheckedCallee.make ~is_known_expensive:false callee location))
UncheckedCalleesCond.empty )
else astate
end

@ -11,11 +11,10 @@ module BasicCost = CostDomain.BasicCost
module ProcName = struct
let dispatch : (Tenv.t, BasicCost.t, unit) ProcnameDispatcher.ProcName.dispatcher =
let open ProcnameDispatcher.ProcName in
let match_builtin builtin _ s = String.equal s (Procname.get_method builtin) in
make_dispatcher
[ +match_builtin BuiltinDecl.__new <>--> BasicCost.one ()
; +match_builtin BuiltinDecl.__new_array <>--> BasicCost.one ()
; +match_builtin BuiltinDecl.__objc_alloc_no_fail <>--> BasicCost.one ()
; +match_builtin BuiltinDecl.malloc <>--> BasicCost.one ()
; +match_builtin BuiltinDecl.malloc_no_fail <>--> BasicCost.one () ]
[ +BuiltinDecl.(match_builtin __new) <>--> BasicCost.one ()
; +BuiltinDecl.(match_builtin __new_array) <>--> BasicCost.one ()
; +BuiltinDecl.(match_builtin __objc_alloc_no_fail) <>--> BasicCost.one ()
; +BuiltinDecl.(match_builtin malloc) <>--> BasicCost.one ()
; +BuiltinDecl.(match_builtin malloc_no_fail) <>--> BasicCost.one () ]
end

@ -1314,7 +1314,6 @@ module StringSet = Caml.Set.Make (String)
module ProcNameDispatcher = struct
let dispatch : (Tenv.t * Procname.t, model, arg_payload) ProcnameDispatcher.Call.dispatcher =
let open ProcnameDispatcher.Call in
let match_builtin builtin _ s = String.equal s (Procname.get_method builtin) in
let pushback_modeled =
StringSet.of_list
["add"; "addAll"; "append"; "delete"; "remove"; "replace"; "poll"; "put"; "putAll"]
@ -1355,25 +1354,27 @@ module ProcNameDispatcher = struct
let map_context_tenv f (x, _) = f x in
make_dispatcher
( transfer_ownership_matchers @ abort_matchers
@ [ +match_builtin BuiltinDecl.free <>$ capt_arg_payload $--> C.free
; +match_builtin BuiltinDecl.malloc <>$ capt_exp $--> C.malloc
; +match_builtin BuiltinDecl.__delete <>$ capt_arg_payload $--> Cplusplus.delete
; +match_builtin BuiltinDecl.__new <>$ capt_exp $--> Misc.alloc_not_null_call_ev ~desc:"new"
; +match_builtin BuiltinDecl.__new_array
@ [ +BuiltinDecl.(match_builtin free) <>$ capt_arg_payload $--> C.free
; +BuiltinDecl.(match_builtin malloc) <>$ capt_exp $--> C.malloc
; +BuiltinDecl.(match_builtin __delete) <>$ capt_arg_payload $--> Cplusplus.delete
; +BuiltinDecl.(match_builtin __new)
<>$ capt_exp
$--> Misc.alloc_not_null_call_ev ~desc:"new"
; +match_builtin BuiltinDecl.__placement_new &++> Cplusplus.placement_new
; +match_builtin BuiltinDecl.objc_cpp_throw <>--> Misc.early_exit
; +match_builtin BuiltinDecl.__cast
; +BuiltinDecl.(match_builtin __new_array)
<>$ capt_exp
$--> Misc.alloc_not_null_call_ev ~desc:"new"
; +BuiltinDecl.(match_builtin __placement_new) &++> Cplusplus.placement_new
; +BuiltinDecl.(match_builtin objc_cpp_throw) <>--> Misc.early_exit
; +BuiltinDecl.(match_builtin __cast)
<>$ capt_arg_payload $+...$--> Misc.id_first_arg ~desc:"cast"
; +match_builtin BuiltinDecl.abort <>--> Misc.early_exit
; +match_builtin BuiltinDecl.exit <>--> Misc.early_exit
; +match_builtin BuiltinDecl.__infer_initializer_list
; +BuiltinDecl.(match_builtin abort) <>--> Misc.early_exit
; +BuiltinDecl.(match_builtin exit) <>--> Misc.early_exit
; +BuiltinDecl.(match_builtin __infer_initializer_list)
<>$ capt_arg_payload
$+...$--> Misc.id_first_arg ~desc:"infer_init_list"
; +map_context_tenv (PatternMatch.Java.implements_lang "System")
&:: "exit" <>--> Misc.early_exit
; +match_builtin BuiltinDecl.__get_array_length <>--> Misc.return_unknown_size
; +BuiltinDecl.(match_builtin __get_array_length) <>--> Misc.return_unknown_size
; (* consider that all fbstrings are small strings to avoid false positives due to manual
ref-counting *)
-"folly" &:: "fbstring_core" &:: "category" &--> Misc.return_int Int64.zero
@ -1663,7 +1664,7 @@ module ProcNameDispatcher = struct
; +map_context_tenv PatternMatch.Java.implements_iterator
&:: "next" <>$ capt_arg_payload
$!--> JavaIterator.next ~desc:"Iterator.next()"
; +match_builtin BuiltinDecl.__instanceof
; +BuiltinDecl.(match_builtin __instanceof)
<>$ capt_arg_payload $+ capt_exp $--> Java.instance_of
; ( +map_context_tenv PatternMatch.Java.implements_enumeration
&:: "nextElement" <>$ capt_arg_payload
@ -1677,7 +1678,7 @@ module ProcNameDispatcher = struct
&--> C.malloc_no_param
; +map_context_tenv PatternMatch.ObjectiveC.is_core_foundation_create_or_copy
&--> C.malloc_no_param
; +match_builtin BuiltinDecl.malloc_no_fail <>$ capt_exp $--> C.malloc_not_null
; +BuiltinDecl.(match_builtin malloc_no_fail) <>$ capt_exp $--> C.malloc_not_null
; +map_context_tenv PatternMatch.ObjectiveC.is_modelled_as_alloc
&--> C.malloc_not_null_no_param
; +map_context_tenv PatternMatch.ObjectiveC.is_core_graphics_release
@ -1687,9 +1688,9 @@ module ProcNameDispatcher = struct
<>$ capt_arg_payload $--> ObjCCoreFoundation.cf_bridging_release
; -"CFAutorelease" <>$ capt_arg_payload $--> ObjCCoreFoundation.cf_bridging_release
; -"CFBridgingRelease" <>$ capt_arg_payload $--> ObjCCoreFoundation.cf_bridging_release
; +match_builtin BuiltinDecl.__objc_bridge_transfer
; +BuiltinDecl.(match_builtin __objc_bridge_transfer)
<>$ capt_arg_payload $--> ObjCCoreFoundation.cf_bridging_release
; +match_builtin BuiltinDecl.__objc_alloc_no_fail
; +BuiltinDecl.(match_builtin __objc_alloc_no_fail)
<>$ capt_exp
$--> ObjC.alloc_not_null_alloc_ev ~desc:"alloc"
; -"NSObject" &:: "init" <>$ capt_arg_payload $--> Misc.id_first_arg ~desc:"NSObject.init"

Loading…
Cancel
Save