[cost] Add model of NSArray.index_of_object_passing_test

Summary:
This diff add a model of `NSArray.index_of_object_passing_test` in
autoreleasepool size model.

Worst case autorelease cost is "array size x cost of given test function (lambda)".

Reviewed By: ezgicicek

Differential Revision: D23785165

fbshipit-source-id: 95ec9700a
master
Sungkeun Cho 4 years ago committed by Facebook GitHub Bot
parent 336e1c7b99
commit 498b49769c

@ -575,15 +575,20 @@ module Call = struct
List.find_map matchers ~f:(fun (matcher : _ matcher) -> matcher.on_java context java args) List.find_map matchers ~f:(fun (matcher : _ matcher) -> matcher.on_java context java args)
in in
fun context procname args -> fun context procname args ->
match procname with let rec match_procname procname =
| ObjC_Cpp objc_cpp -> match (procname : Procname.t) with
on_objc_cpp context objc_cpp args | ObjC_Cpp objc_cpp ->
| C c -> on_objc_cpp context objc_cpp args
on_c context c args | C c ->
| Java java -> on_c context c args
on_java context java args | Java java ->
| _ -> on_java context java args
None | WithBlockParameters (procname, _) ->
match_procname procname
| _ ->
None
in
match_procname procname
let merge_dispatchers : let merge_dispatchers :

@ -331,8 +331,7 @@ module MakePolynomial (S : NonNegativeSymbolWithDegreeKind) = struct
|> M.fold (fun s p acc -> plus_poly (mult_symb_poly (mult_poly p p1) s) acc) p2.terms |> M.fold (fun s p acc -> plus_poly (mult_symb_poly (mult_poly p p1) s) acc) p2.terms
let mult : t -> t -> t = let mult_common p1 p2 ~join_autoreleasepool_trace =
fun p1 p2 ->
let poly = mult_poly p1.poly p2.poly in let poly = mult_poly p1.poly p2.poly in
let autoreleasepool_trace = let autoreleasepool_trace =
if is_zero_poly poly then None if is_zero_poly poly then None
@ -342,6 +341,15 @@ module MakePolynomial (S : NonNegativeSymbolWithDegreeKind) = struct
{poly; autoreleasepool_trace} {poly; autoreleasepool_trace}
let mult p1 p2 = mult_common p1 p2 ~join_autoreleasepool_trace
(** It takes only the trace of the body part, because the trace for the iteration number will be
taken later from symbolic values. *)
let mult_loop ~iter ~body =
mult_common iter body ~join_autoreleasepool_trace:(fun _iter_poly _body_poly _iter body ->
body )
let rec of_valclass : (NonNegativeInt.t, S.t, 't) Bounds.valclass -> ('t, t, 't) below_above = let rec of_valclass : (NonNegativeInt.t, S.t, 't) Bounds.valclass -> ('t, t, 't) below_above =
function function
| ValTop trace -> | ValTop trace ->
@ -759,6 +767,11 @@ module NonNegativePolynomial = struct
let mult = top_lifted_increasing ~f:NonNegativeNonTopPolynomial.mult let mult = top_lifted_increasing ~f:NonNegativeNonTopPolynomial.mult
let mult_loop ~iter ~body =
top_lifted_increasing iter body ~f:(fun iter body ->
NonNegativeNonTopPolynomial.mult_loop ~iter ~body )
let min_default_left p1 p2 = let min_default_left p1 p2 =
AbstractDomain.StackedUtils.combine ~dir:`Decreasing p1 p2 AbstractDomain.StackedUtils.combine ~dir:`Decreasing p1 p2
~f:NonNegativeNonTopPolynomial.min_default_left ~f_above:TopTraces.join ~f:NonNegativeNonTopPolynomial.min_default_left ~f_above:TopTraces.join

@ -79,6 +79,8 @@ module NonNegativePolynomial : sig
val mult : t -> t -> t val mult : t -> t -> t
val mult_loop : iter:t -> body:t -> t
val min_default_left : t -> t -> t val min_default_left : t -> t -> t
val subst : Procname.t -> Location.t -> t -> Bound.eval_sym -> t val subst : Procname.t -> Location.t -> t -> Bound.eval_sym -> t

@ -128,7 +128,7 @@ module InstrBasicCostWithReason = struct
(inferbo_mem_opt, CostAutoreleaseModels.Call.dispatch tenv callee_pname fun_arg_list) (inferbo_mem_opt, CostAutoreleaseModels.Call.dispatch tenv callee_pname fun_arg_list)
with with
| Some inferbo_mem, Some model -> | Some inferbo_mem, Some model ->
let autoreleasepool_size = model (Lazy.force model_env) ~ret inferbo_mem in let autoreleasepool_size = model get_summary (Lazy.force model_env) ~ret inferbo_mem in
CostDomain.plus_autoreleasepool_size autoreleasepool_size cost CostDomain.plus_autoreleasepool_size autoreleasepool_size cost
| _, _ -> | _, _ ->
if if

@ -7,21 +7,50 @@
open! IStd open! IStd
module BasicCost = CostDomain.BasicCost module BasicCost = CostDomain.BasicCost
module BasicCostWithReason = CostDomain.BasicCostWithReason
open BufferOverrunUtils.ModelEnv open BufferOverrunUtils.ModelEnv
let unit_cost {pname; location} ~ret:_ _inferbo_mem = let unit_cost _get_summary {pname; location} ~ret:_ _inferbo_mem =
let autoreleasepool_trace = let autoreleasepool_trace =
Bounds.BoundTrace.of_modeled_function (Procname.to_string pname) location Bounds.BoundTrace.of_modeled_function (Procname.to_string pname) location
in in
BasicCost.one ~autoreleasepool_trace () BasicCost.one ~autoreleasepool_trace ()
module NSArray = struct
let index_of_object_passing_test array get_summary ({pname; location= _} as model_env) ~ret
inferbo_mem =
match pname with
| WithBlockParameters (_, [block_name]) -> (
match get_summary (Procname.Block block_name) with
| Some {CostDomain.post= callee_summary} ->
let {BasicCostWithReason.cost= callee_cost} =
CostDomain.get_cost_kind AutoreleasepoolSize callee_summary
in
let length =
CostModels.BoundsOfNSCollection.linear_length
~of_function:(Procname.to_simplified_string pname)
array model_env ~ret inferbo_mem
in
BasicCost.mult_loop ~iter:length ~body:callee_cost
| None ->
BasicCost.zero )
| _ ->
BasicCost.zero
end
module Call = struct module Call = struct
let dispatch : (Tenv.t, CostUtils.model, unit) ProcnameDispatcher.Call.dispatcher = let dispatch :
( Tenv.t
, (Procname.t -> CostDomain.summary option) -> CostUtils.model
, unit )
ProcnameDispatcher.Call.dispatcher =
let open ProcnameDispatcher.Call in let open ProcnameDispatcher.Call in
make_dispatcher make_dispatcher
[ +PatternMatch.ObjectiveC.implements "NSObject" &:: "autorelease" &--> unit_cost [ +PatternMatch.ObjectiveC.implements "NSObject" &:: "autorelease" &--> unit_cost
; -"CFAutorelease" &--> unit_cost ; -"CFAutorelease" &--> unit_cost
; +PatternMatch.ObjectiveC.implements "NSArray"
&:: "indexOfObjectPassingTest:" $ capt_exp $--> NSArray.index_of_object_passing_test
; +PatternMatch.ObjectiveC.implements "NSKeyedUnarchiver" ; +PatternMatch.ObjectiveC.implements "NSKeyedUnarchiver"
&:: "initForReadingFromData:error:" &--> unit_cost &:: "initForReadingFromData:error:" &--> unit_cost
; +PatternMatch.ObjectiveC.implements "NSKeyedUnarchiver" ; +PatternMatch.ObjectiveC.implements "NSKeyedUnarchiver"

@ -8,5 +8,9 @@
open! IStd open! IStd
module Call : sig module Call : sig
val dispatch : (Tenv.t, CostUtils.model, unit) ProcnameDispatcher.Call.dispatcher val dispatch :
( Tenv.t
, (Procname.t -> CostDomain.summary option) -> CostUtils.model
, unit )
ProcnameDispatcher.Call.dispatcher
end end

@ -12,7 +12,7 @@
@implementation ArcBlock @implementation ArcBlock
+ (void)callIndexOfObjectPassingTest_linear_FN:(NSArray*)x { + (void)callIndexOfObjectPassingTest_linear:(NSArray*)x {
int i = [x indexOfObjectPassingTest:^BOOL( int i = [x indexOfObjectPassingTest:^BOOL(
NSObject* obj, NSUInteger idx, BOOL* stop) { NSObject* obj, NSUInteger idx, BOOL* stop) {
NoArcCallee* o = [NoArcCallee giveMeObject]; NoArcCallee* o = [NoArcCallee giveMeObject];

@ -1,7 +1,7 @@
${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.indexOfObjectPassingTest:[objc_blockArcBlock.callIndexOfObjectPassingTest_linear_FN:_1], 0, OnUIThread:false, [] ${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.indexOfObjectPassingTest:[objc_blockArcBlock.callIndexOfObjectPassingTest_linear:_1], 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_block.m, ArcBlock.callIndexOfObjectPassingTest_linear_FN:, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/arc_block.m, ArcBlock.callIndexOfObjectPassingTest_linear:, x->elements.length.ub, OnUIThread:false, [{x->elements.length.ub},Modeled call to indexOfObjectPassingTest:,autorelease,Call to NoArcCallee.giveMeObject,Modeled call to NSObject.autorelease]
codetoanalyze/objc/autoreleasepool/arc_block.m, ArcBlock.dealloc, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/arc_block.m, ArcBlock.dealloc, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_block.m, objc_blockArcBlock.callIndexOfObjectPassingTest_linear_FN:_1, 1, OnUIThread:false, [autorelease,Call to NoArcCallee.giveMeObject,Modeled call to NSObject.autorelease] codetoanalyze/objc/autoreleasepool/arc_block.m, objc_blockArcBlock.callIndexOfObjectPassingTest_linear:_1, 1, OnUIThread:false, [autorelease,Call to NoArcCallee.giveMeObject,Modeled call to NSObject.autorelease]
codetoanalyze/objc/autoreleasepool/arc_callee.m, ArcCallee.allocObject, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/arc_callee.m, ArcCallee.allocObject, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_callee.m, ArcCallee.copyObject:, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/arc_callee.m, ArcCallee.copyObject:, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_callee.m, ArcCallee.dealloc, 0, OnUIThread:false, [] codetoanalyze/objc/autoreleasepool/arc_callee.m, ArcCallee.dealloc, 0, OnUIThread:false, []

Loading…
Cancel
Save