[cost] Enable passing enumerator as paramter in ObjC

Summary:
This diff revises memory model of enumerator in ObjC to enable passing it as a parameter.

The cost checker was not able to analyze a function precisely when it gets an enumerator as a
parameter because the offset of an enumerator was available only when the analyzer knew the correct
relation between the enumerator and an array.

This diff simplifies the enumerator to have a similar value with `array->elements`, so its offset can
be taken without the relation between enumerator and array to get them.

Reviewed By: ezgicicek

Differential Revision: D24446574

fbshipit-source-id: 27cdc051e
master
Sungkeun Cho 4 years ago committed by Facebook GitHub Bot
parent 198c700e87
commit 95efb32fb4

@ -526,6 +526,9 @@ module Name = struct
|> QualifiedCppName.Set.of_list
in
function ObjcClass name -> not (QualifiedCppName.Set.mem name tagged_classes) | _ -> false
let objc_ns_enumerator = from_string "NSEnumerator"
end
module Set = PrettyPrintable.MakePPSet (struct

@ -271,6 +271,8 @@ module Name : sig
val from_qual_name : QualifiedCppName.t -> t
val protocol_from_qual_name : QualifiedCppName.t -> t
val objc_ns_enumerator : t
end
module Set : PrettyPrintable.PPSet with type elt = t

@ -546,6 +546,8 @@ module PowLoc = struct
mk_known (LocSet.add l ploc)
let of_list locs = List.fold locs ~init:bot ~f:(fun acc loc -> add loc acc)
let mem l = function
| Bottom ->
false

@ -119,6 +119,8 @@ module PowLoc : sig
val add : Loc.t -> t -> t
val of_list : Loc.t list -> t
val exists : (Loc.t -> bool) -> t -> bool
val mem : Loc.t -> t -> bool

@ -279,6 +279,14 @@ module ArrInfo = struct
Itv.is_length_path_of prefix length
| _ ->
false
let prune_offset_le_size info =
match info with
| C {offset; size; stride} ->
C {offset= Itv.prune_le offset size; size; stride}
| Java _ | Top ->
info
end
include AbstractDomain.Map (Allocsite) (ArrInfo)
@ -386,6 +394,8 @@ let prune_eq : t -> t -> t = fun a1 a2 -> do_prune ArrInfo.prune_eq a1 a2
let prune_ne : t -> t -> t = fun a1 a2 -> do_prune ArrInfo.prune_ne a1 a2
let prune_offset_le_size a = map ArrInfo.prune_offset_le_size a
let set_length : Itv.t -> t -> t = fun length a -> map (ArrInfo.set_length length) a
let set_stride : Z.t -> t -> t = fun stride a -> map (ArrInfo.set_stride stride) a

@ -58,6 +58,9 @@ val prune_eq : t -> t -> t
val prune_ne : t -> t -> t
(** [prune_ne x y] returns a pruned value of [x] by [!= y]. *)
val prune_offset_le_size : t -> t
(** Prune offset by [offset <= size] *)
val minus_offset : t -> Itv.t -> t
val plus_offset : t -> Itv.t -> t

@ -429,8 +429,6 @@ module Val = struct
let prune_lt : t -> t -> t = prune_binop Binop.Lt
let prune_le : t -> t -> t = prune_binop Binop.Le
let is_pointer_to_non_array x = (not (PowLoc.is_bot x.powloc)) && ArrayBlk.is_bot x.arrayblk
(* In the pointer arithmetics, it returns top, if we cannot
@ -565,6 +563,14 @@ module Val = struct
itv_val ~non_int:false |> set_itv_updated_by_addition
| Tptr ({desc= Tfun}, _) ->
of_func_ptrs (FuncPtr.Set.of_path path)
| Tptr ({desc= Tstruct name}, _) when Typ.equal_name name Typ.Name.Objc.objc_ns_enumerator ->
(* NOTE: It generates a value of NSEnumerator specifically. Especially, it assigns zero to
the offset, rather than a symbol, to avoid precision loss by limited handling of symbolic
values in the domain. Although this is an unsound design choice, we expect it should not
that harmful for calculating WCET. *)
let allocsite = SPath.deref ~deref_kind:Deref_CPointer path |> Allocsite.make_symbol in
let size = Itv.of_length_path ~is_void:false path in
{bot with arrayblk= ArrayBlk.make_c allocsite ~offset:Itv.zero ~size ~stride:Itv.one}
| Tptr (elt, _) ->
if is_java || SPath.is_this path then
let deref_kind =
@ -1365,20 +1371,13 @@ module AliasMap = struct
let add_iterator_next_object_alias ~ret_id ~iterator x =
let accum_next_object_alias rhs tgt acc =
match tgt with
| AliasTarget.IteratorSimple _ ->
add_alias ~lhs:(KeyLhs.of_id ret_id) ~rhs
(AliasTarget.IteratorNextObject {objc_tmp= None})
acc
| _ ->
acc
in
let open IOption.Let_syntax in
M.find_opt (KeyLhs.of_id iterator) x
>>= AliasTargets.find_simple_alias
>>= (fun rhs -> M.find_opt (KeyLhs.of_loc rhs) x)
>>| (fun tgts -> AliasTargets.fold accum_next_object_alias tgts x)
>>| (fun rhs ->
add_alias ~lhs:(KeyLhs.of_id ret_id) ~rhs
(AliasTarget.IteratorNextObject {objc_tmp= None})
x )
|> Option.value ~default:x
end
@ -2083,11 +2082,6 @@ module MemReach = struct
let add_iterator_alias id m = add_iterator_offset_alias id m |> add_iterator_simple_alias id
let add_iterator_alias_objc id m =
let array_loc = find_stack (Loc.of_id id) m |> Val.get_pow_loc in
{m with alias= Alias.add_iterator_simple_alias id array_loc m.alias}
let incr_iterator_offset_alias id m = {m with alias= Alias.incr_iterator_offset_alias id m.alias}
let add_iterator_has_next_alias ~ret_id ~iterator m =
@ -2464,10 +2458,6 @@ module Mem = struct
let add_iterator_alias : Ident.t -> t -> t = fun id -> map ~f:(MemReach.add_iterator_alias id)
let add_iterator_alias_objc : Ident.t -> t -> t =
fun id -> map ~f:(MemReach.add_iterator_alias_objc id)
let incr_iterator_offset_alias : Exp.t -> t -> t =
fun iterator m ->
match iterator with Exp.Var id -> map ~f:(MemReach.incr_iterator_offset_alias id) m | _ -> m
@ -2482,13 +2472,8 @@ module Mem = struct
m
let add_iterator_next_object_alias : Ident.t -> Exp.t -> t -> t =
fun ret_id iterator m ->
match iterator with
| Exp.Var iterator ->
map ~f:(MemReach.add_iterator_next_object_alias ~ret_id ~iterator) m
| _ ->
m
let add_iterator_next_object_alias : ret_id:Ident.t -> iterator:Ident.t -> t -> t =
fun ~ret_id ~iterator m -> map ~f:(MemReach.add_iterator_next_object_alias ~ret_id ~iterator) m
let incr_iterator_simple_alias_on_call eval_sym_trace ~callee_exit_mem m =

@ -227,10 +227,6 @@ module Val : sig
(** Pruning semantics for [Binop.Lt]. This prunes value of [x] when given [x < y], i.e.,
[prune_lt x y]. *)
val prune_le : t -> t -> t
(** Pruning semantics for [Binop.Lt]. This prunes value of [x] when given [x <= y], i.e.,
[prune_le x y]. *)
val prune_ne_zero : t -> t
(** Prune value of [x] when given [x != 0] *)
@ -592,7 +588,7 @@ module Mem : sig
val add_iterator_has_next_alias : Ident.t -> Exp.t -> t -> t
(** Add an [AliasTarget.IteratorHasNext] alias when [ident = iterator.hasNext()] is called *)
val add_iterator_next_object_alias : Ident.t -> Exp.t -> t -> t
val add_iterator_next_object_alias : ret_id:Ident.t -> iterator:Ident.t -> t -> t
(** Add an [AliasTarget.IteratorNextObject] alias when [ident = iterator.nextObject()] is called *)
val incr_iterator_simple_alias_on_call : eval_sym_trace -> callee_exit_mem:no_oenv_t -> t -> t
@ -602,8 +598,6 @@ module Mem : sig
(** Add [AliasTarget.IteratorSimple] and [AliasTarget.IteratorOffset] aliases when
[Iteratable.iterator()] is called *)
val add_iterator_alias_objc : Ident.t -> t -> t
val incr_iterator_offset_alias : Exp.t -> t -> t
(** Update iterator offset alias when [iterator.next()] is called *)

@ -1142,34 +1142,34 @@ module NSCollection = struct
let iterator coll_exp =
let exec {integer_type_widths; location} ~ret:(ret_id, _) mem =
let traces = Trace.(Set.singleton location ArrayDeclaration) in
let array_v = Sem.eval integer_type_widths coll_exp mem in
let array_loc = Dom.Val.get_all_locs array_v in
let offset_loc = PowLoc.append_field ~fn:BufferOverrunField.objc_iterator_offset array_loc in
let mem = Dom.Mem.add_heap_set offset_loc Dom.Val.Itv.zero mem in
model_by_value (Dom.Val.of_pow_loc ~traces array_loc) ret_id mem
|> Dom.Mem.add_heap_set array_loc array_v
|> Dom.Mem.add_iterator_alias_objc ret_id
let exec {integer_type_widths= _; location} ~ret:(id, _) mem =
let elements_locs = eval_collection_internal_array_locs coll_exp mem in
let v = Dom.Mem.find_set elements_locs mem |> Dom.Val.set_array_offset location Itv.zero in
model_by_value v id mem
in
{exec; check= no_check}
let next_object iterator =
let exec {integer_type_widths} ~ret:(id, _) mem =
let iterator_v = Sem.eval integer_type_widths iterator mem in
let traces = Dom.Val.get_traces iterator_v in
let offset_loc =
Dom.Val.get_pow_loc iterator_v
|> PowLoc.append_field ~fn:BufferOverrunField.objc_iterator_offset
let exec _ ~ret:(ret_id, _) mem =
let iterator_locs =
Dom.Mem.find_simple_alias iterator mem
|> List.filter_map ~f:(fun (l, i) -> if IntLit.iszero i then Some l else None)
|> PowLoc.of_list
in
let next_offset_v =
Dom.Mem.find_set offset_loc mem |> Dom.Val.get_itv |> Itv.incr |> Dom.Val.of_itv
let iterator_v = Dom.Mem.find_set iterator_locs mem in
let arrayblk = ArrayBlk.plus_offset (Dom.Val.get_array_blk iterator_v) Itv.one in
let iterator_v' = {iterator_v with arrayblk} in
let return_v =
(* NOTE: It joins zero to avoid unreachable nodes due to the following hack. The
[nextObject] returns the offset of the enumerator instead of an object elements,
which helps the cost checker select the offset as a control variable, for example,
[while(obj = [enumerator nextObject]) { ... }]. *)
ArrayBlk.get_offset arrayblk |> Itv.join Itv.zero |> Dom.Val.of_itv
in
let locs = eval_collection_internal_array_locs iterator mem in
model_by_value (Dom.Val.of_pow_loc ~traces locs) id mem
|> Dom.Mem.add_heap_set offset_loc next_offset_v
|> Dom.Mem.add_iterator_next_object_alias id iterator
model_by_value return_v ret_id mem
|> Dom.Mem.add_heap_set iterator_locs iterator_v'
|> Dom.Mem.add_iterator_next_object_alias ~ret_id ~iterator
in
{exec; check= no_check}
end
@ -1712,7 +1712,7 @@ module Call = struct
&:: "arrayByAddingObjectsFromArray:" <>$ capt_exp $+ capt_exp
$--> NSCollection.new_collection_by_add_all
; +PatternMatch.ObjectiveC.implements "NSEnumerator"
&:: "nextObject" <>$ capt_exp $--> NSCollection.next_object
&:: "nextObject" <>$ capt_var_exn $--> NSCollection.next_object
; +PatternMatch.ObjectiveC.implements "NSFileManager"
&:: "contentsOfDirectoryAtURL:includingPropertiesForKeys:options:error:"
&--> NSCollection.new_collection

@ -590,27 +590,18 @@ module Prune = struct
update_mem_in_prune lv_linked_list_index pruned_v acc ) )
let nscollection_length_of_iterator loc mem =
let arr_locs =
Mem.find loc mem |> Val.get_all_locs
|> PowLoc.append_field ~fn:BufferOverrunField.objc_collection_internal_array
in
eval_array_locs_length arr_locs mem
let prune_iterator_offset_objc next_object mem acc =
let tgts = Mem.find_alias_loc next_object mem in
AliasTargets.fold
(fun rhs tgt acc ->
(fun iterator tgt acc ->
match tgt with
| AliasTarget.IteratorNextObject _ ->
let array_length = nscollection_length_of_iterator rhs mem in
let iterator_offset_loc =
Loc.append_field rhs BufferOverrunField.objc_iterator_offset
let iterator_v = Mem.find iterator mem in
let iterator_v' =
{ iterator_v with
arrayblk= Val.get_array_blk iterator_v |> ArrayBlk.prune_offset_le_size }
in
let iterator_offset_v = Mem.find iterator_offset_loc mem in
let iterator_offset_v' = Val.prune_le iterator_offset_v array_length in
update_mem_in_prune iterator_offset_loc iterator_offset_v' acc
update_mem_in_prune iterator iterator_v' acc
| _ ->
acc )
tgts acc

@ -49,11 +49,17 @@ typedef BOOL (^Filter)(id);
}];
}
- (void)callMyEnumerator_linear_FN:(NSArray*)x {
// The cost analyzer cannot reason the amortized complexity.
- (void)callMyEnumerator_linear_FP:(NSArray*)x {
MyEnumerator* enumerator = [self makeMyEnumerator_zero:x];
id s;
while (s = [enumerator nextObject]) {
}
}
- (void)callMyEnumerator_nextObject_linear:(NSArray*)x {
MyEnumerator* enumerator = [self makeMyEnumerator_zero:x];
id s = [enumerator nextObject];
}
@end

@ -24,12 +24,13 @@ codetoanalyze/objc/autoreleasepool/arc_caller.m, ArcCaller.callGiveMeObject_line
codetoanalyze/objc/autoreleasepool/arc_caller.m, ArcCaller.callMutableCopyObject_zero:x:, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_caller.m, ArcCaller.callNewObject_zero:, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_caller.m, ArcCaller.dealloc, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, ArcEnumerator.callMyEnumerator_linear_FN:, 1, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, ArcEnumerator.callMyEnumerator_linear_FP:, (x->elements.length.ub + 1) × (x->elements.length.ub + 2), OnUIThread:false, [{x->elements.length.ub + 2},Loop,{x->elements.length.ub + 1},Call to MyEnumerator.nextObject,Loop]
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, ArcEnumerator.callMyEnumerator_nextObject_linear:, (x->elements.length.ub + 1), OnUIThread:false, [{x->elements.length.ub + 1},Call to MyEnumerator.nextObject,Loop]
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, ArcEnumerator.dealloc, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, ArcEnumerator.makeMyEnumerator_zero:, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, MyEnumerator.dealloc, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, MyEnumerator.initWithArray:filter:, 0, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, MyEnumerator.nextObject, |self->_filter|, OnUIThread:false, []
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, MyEnumerator.nextObject, (self->_enumerator.length + 1) × |self->_filter|, OnUIThread:false, [{self->_enumerator.length + 1},Loop]
codetoanalyze/objc/autoreleasepool/arc_enumerator.m, objc_blockArcEnumerator.makeMyEnumerator_zero:_1, 1, OnUIThread:false, [autorelease,Call to NoArcCallee.giveMeObject,Modeled call to NSObject.autorelease]
codetoanalyze/objc/autoreleasepool/arc_keyed_unarchiver.m, ArcKeyedUnarchiver.callInitForReadingFromData_constant:data:, 1, OnUIThread:false, [autorelease,Modeled call to NSKeyedUnarchiver.initForReadingFromData:error:]
codetoanalyze/objc/autoreleasepool/arc_keyed_unarchiver.m, ArcKeyedUnarchiver.callInitForReadingWithData_constant:data:, 1, OnUIThread:false, [autorelease,Modeled call to NSKeyedUnarchiver.initForReadingWithData:]

@ -51,7 +51,7 @@ NSArray* nsarray_init_with_objects_constant() {
}
}
NSArray* nsarray_array_with_objects_constant() {
NSArray* nsarray_array_with_objects_constant_FP() {
NSDate* aDate = [NSDate distantFuture];
NSValue* aValue = @(5);
NSString* aString = @"hello";
@ -166,13 +166,13 @@ void nsarray_enumerator_linear(NSArray* array) {
}
}
void nsarray_enumerator_param_linear_FN(NSEnumerator* enumerator) {
void nsarray_enumerator_param_linear(NSEnumerator* enumerator) {
id obj;
while (obj = [enumerator nextObject]) {
}
}
void call_nsarray_enumerator_param_linear_FN(NSArray* array) {
void call_nsarray_enumerator_param_linear(NSArray* array) {
NSEnumerator* enumerator = [array objectEnumerator];
nsarray_enumerator_param_linear_FN(enumerator);
}

@ -1,17 +1,17 @@
${XCODE_ISYSROOT}/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h, NSArray.indexOfObject:inSortedRange:options:usingComparator:[objc_blocknsarray_binary_search_log_FN_1], 0, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, call_nsarray_enumerator_param_linear_FN, 12, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, call_nsarray_enumerator_param_linear, 6, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_access_constant, 50, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_access_linear, 3 + 7 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_add_object_constant, 8, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_add_objects_from_array_linear, 9 + 3 ⋅ append_array->elements.length.ub + append_array->elements.length.ub + 3 ⋅ (append_array->elements.length.ub + 1), OnUIThread:false, [{append_array->elements.length.ub + 1},Loop,{append_array->elements.length.ub},Modeled call to NSArray.arrayByAddingObjectsFromArray:,{append_array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_array_with_objects_constant, 27, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_array_with_objects_constant_FP, , OnUIThread:false, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_binary_search_log_FN, 10, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_contains_object_linear, 3 + array->elements.length.ub, OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.containsObject:]
codetoanalyze/objc/performance/NSArray.m, nsarray_copy_linear, 6 + 3 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_count_bounded_linear, 3 + 3 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_empty_array_constant, 8, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_enumerator_linear, 6 + 4 ⋅ array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_enumerator_param_linear_FN, 7, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_enumerator_linear, 6 + 8 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_enumerator_param_linear, 2 + 5 ⋅ (enumerator.length + 1), OnUIThread:false, [{enumerator.length + 1},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_find_linear, 4 + 9 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_first_object_constant, 4, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_get_first_constant, 27, OnUIThread:false, []
@ -21,10 +21,10 @@ codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_copy_linear, 7
codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_array_linear, 6 + 3 ⋅ array->elements.length.ub + array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Modeled call to NSArray.initWithArray:,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_init_with_objects_constant, 39, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_is_equal_to_array_linear, 4 + array1->elements.length.ub, OnUIThread:false, [{array1->elements.length.ub},Modeled call to NSArray.isEqualToArray:]
codetoanalyze/objc/performance/NSArray.m, nsarray_iterate_linear, 6 + 4 ⋅ array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_iterate_linear, 6 + 8 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_last_object_constant, 4, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_constant, 25, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_linear, 5 + array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_constant, 26, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_next_object_linear, 5 + 5 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_object_at_indexed_constant, 34, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_constant, 39, OnUIThread:false, []
codetoanalyze/objc/performance/NSArray.m, nsarray_sort_using_descriptors_nlogn, 9 + array->elements.length.ub × log(array->elements.length.ub), OnUIThread:false, [{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:,{array->elements.length.ub},Modeled call to NSArray.sortedArrayUsingDescriptors:]
@ -36,9 +36,9 @@ codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_alloc_with_zone_init
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_dictionary_constant, 13, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_dictionary_with_objects_linear, 14 + 15 ⋅ n_entries + 3 ⋅ n_entries + 2 ⋅ (1+max(0, n_entries)) + 4 ⋅ (1+max(0, n_entries)), OnUIThread:false, [{1+max(0, n_entries)},Loop,{1+max(0, n_entries)},Loop,{n_entries},Loop,{n_entries},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_call_constant, 65, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_constant, 69, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerator_linear, 5 + dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_fast_enumerate_linear, 5 + dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_constant, 74, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerator_linear, 5 + 5 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_fast_enumerate_linear, 5 + 5 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_find_key_constant, 19, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_dictionary_constant, 3, OnUIThread:false, []
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_init_literal_constant, 45, OnUIThread:false, []
@ -60,19 +60,19 @@ codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_constant, 17,
codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant, 182, OnUIThread:false, []
codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_in_loop_constant, 51, OnUIThread:false, []
codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_linear, 3 + 11 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSMutableDictionary.m, nsmutabledictionary_set_element_in_loop_linear, 5 + 5 ⋅ dict->elements.length.ub + 4 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop,{dict->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSMutableDictionary.m, nsmutabledictionary_set_element_in_loop_linear, 5 + 9 ⋅ (dict->elements.length.ub + 1), OnUIThread:false, [{dict->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSMutableString.m, copy_string_constant_FP, 11 + 3 ⋅ str3.length.ub + str3.length.ub + 3 ⋅ (str3.length.ub + 1), OnUIThread:false, [{str3.length.ub + 1},Loop,{str3.length.ub},Modeled call to NSMutableString.appendString:,{str3.length.ub},Loop]
codetoanalyze/objc/performance/NSMutableString.m, nsmstring_append_string_constant, 14 + 3 ⋅ (str.length.ub + 5) + 3 ⋅ (str.length.ub + 6), OnUIThread:false, [{str.length.ub + 6},Loop,{str.length.ub + 5},Loop]
codetoanalyze/objc/performance/NSMutableString.m, nsmstring_append_string_linear, 5 + str2.length.ub + 3 ⋅ (str2.length.ub + str1.length.ub) + 3 ⋅ (str2.length.ub + str1.length.ub + 1), OnUIThread:false, [{str2.length.ub + str1.length.ub + 1},Loop,{str2.length.ub + str1.length.ub},Loop,{str2.length.ub},Modeled call to NSMutableString.appendString:]
codetoanalyze/objc/performance/NSOrderedSet.m, nsordered_set_empty_constant, 13, OnUIThread:false, []
codetoanalyze/objc/performance/NSOrderedSet.m, nsordered_set_iterate_linear, 5 + ordered_set->elements.length.ub + 4 ⋅ (ordered_set->elements.length.ub + 1), OnUIThread:false, [{ordered_set->elements.length.ub + 1},Loop,{ordered_set->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSOrderedSet.m, nsordered_set_with_array_linear, 10 + array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Call to nsordered_set_iterate_linear,Loop,{array->elements.length.ub},Call to nsordered_set_iterate_linear,Loop]
codetoanalyze/objc/performance/NSSet.m, nsset_enumerator_linear, 6 + 4 ⋅ set->elements.length.ub + 4 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop,{set->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSOrderedSet.m, nsordered_set_empty_constant, 14, OnUIThread:false, []
codetoanalyze/objc/performance/NSOrderedSet.m, nsordered_set_iterate_linear, 5 + 5 ⋅ (ordered_set->elements.length.ub + 1), OnUIThread:false, [{ordered_set->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSOrderedSet.m, nsordered_set_with_array_linear, 10 + 5 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Call to nsordered_set_iterate_linear,Loop]
codetoanalyze/objc/performance/NSSet.m, nsset_enumerator_linear, 6 + 8 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSSet.m, nsset_init_constant, 9, OnUIThread:false, []
codetoanalyze/objc/performance/NSSet.m, nsset_init_with_array_linear, 7 + 3 ⋅ array->elements.length.ub + 3 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSSet.m, nsset_init_with_set_constant, 6, OnUIThread:false, []
codetoanalyze/objc/performance/NSSet.m, nsset_iterate_linear, 6 + 4 ⋅ set->elements.length.ub + 4 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop,{set->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSSet.m, nsset_next_object_linear, 5 + set->elements.length.ub + 4 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop,{set->elements.length.ub},Loop]
codetoanalyze/objc/performance/NSSet.m, nsset_iterate_linear, 6 + 8 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSSet.m, nsset_next_object_linear, 5 + 5 ⋅ (set->elements.length.ub + 1), OnUIThread:false, [{set->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/NSString.m, call_component_separated_by_char_constant, 46, OnUIThread:false, []
codetoanalyze/objc/performance/NSString.m, call_init_with_string_constant, 15, OnUIThread:false, []
codetoanalyze/objc/performance/NSString.m, component_seperated_by_char_linear, 6 + m.length.ub + 3 ⋅ (-1+max(2, m.length.ub)) + 3 ⋅ (max(2, m.length.ub)), OnUIThread:false, [{max(2, m.length.ub)},Loop,{-1+max(2, m.length.ub)},Loop,{m.length.ub},Modeled call to NSString.componentsSeparatedByString:]
@ -100,12 +100,12 @@ codetoanalyze/objc/performance/araii.m, Araii.dealloc, 4, OnUIThread:false, []
codetoanalyze/objc/performance/araii.m, Araii.initWithBuffer, 15, OnUIThread:false, []
codetoanalyze/objc/performance/araii.m, Araii.setBuffer:, 4, OnUIThread:false, []
codetoanalyze/objc/performance/araii.m, memory_leak_raii_main, 18, OnUIThread:false, []
codetoanalyze/objc/performance/block.m, block_multiply_array_linear, 13 + 5 ⋅ array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Call to objc_blockblock_multiply_array_linear_1,Loop,{array->elements.length.ub},Call to objc_blockblock_multiply_array_linear_1,Loop]
codetoanalyze/objc/performance/block.m, block_multiply_array_linear, 13 + 9 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Call to objc_blockblock_multiply_array_linear_1,Loop]
codetoanalyze/objc/performance/block.m, call_wrapper_runBlockA_linear, 11 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, doBlockA_direct_block_linear, 10 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to runBlockA[objc_blockdoBlockA_direct_block_linear_3],Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop,{a},Call to runBlockA[objc_blockdoBlockA_direct_block_linear_3],Call to objc_blockdoBlockA_direct_block_linear_3,Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, doBlockA_linear, 12 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to runBlockA[objc_blockdoBlockA_linear_2],Call to objc_blockdoBlockA_linear_2,Call to loop_linear,Loop,{a},Call to runBlockA[objc_blockdoBlockA_linear_2],Call to objc_blockdoBlockA_linear_2,Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, loop_linear, 3 + 3 ⋅ x + 2 ⋅ (1+max(0, x)), OnUIThread:false, [{1+max(0, x)},Loop,{x},Loop]
codetoanalyze/objc/performance/block.m, objc_blockblock_multiply_array_linear_1, 8 + 5 ⋅ array->elements.length.ub + 4 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop,{array->elements.length.ub},Loop]
codetoanalyze/objc/performance/block.m, objc_blockblock_multiply_array_linear_1, 8 + 9 ⋅ (array->elements.length.ub + 1), OnUIThread:false, [{array->elements.length.ub + 1},Loop]
codetoanalyze/objc/performance/block.m, objc_blockcall_wrapper_runBlockA_linear_4, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, objc_blockdoBlockA_direct_block_linear_3, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop]
codetoanalyze/objc/performance/block.m, objc_blockdoBlockA_linear_2, 5 + 3 ⋅ a + 2 ⋅ (1+max(0, a)), OnUIThread:false, [{1+max(0, a)},Call to loop_linear,Loop,{a},Call to loop_linear,Loop]

@ -1,14 +1,21 @@
codetoanalyze/objc/performance/NSArray.m, nsarray_array_with_objects_constant_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSArray.m, nsarray_empty_array_constant, 3, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/NSArray.m, nsarray_enumerator_linear, 7, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,<RHS trace>,Assignment,Binary operation: ([0, +oo] + [1, array->elements.length.ub + 1]):signed64]
codetoanalyze/objc/performance/NSArray.m, nsarray_init_constant, 3, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/NSArray.m, nsarray_iterate_linear, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,<RHS trace>,Assignment,Binary operation: ([0, +oo] + [1, array->elements.length.ub + 1]):signed64]
codetoanalyze/objc/performance/NSDictionary.m, nsdictionary_enumerate_constant, 6, BUFFER_OVERRUN_L2, no_bucket, ERROR, [<Offset trace>,Assignment,<Length trace>,Array declaration,Array access: Offset: [1, 3] Size: 2]
codetoanalyze/objc/performance/NSFileManager.m, contents_of_directory_at_url_constant, 7, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/NSMutableArray.m, nsarray_new_constant, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_constant, 6, BUFFER_OVERRUN_L1, no_bucket, ERROR, [<Length trace>,Array declaration,Through,Through,Through,Through,Array access: Offset: 0 Size: 0]
codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_remove_in_loop_constant, 6, BUFFER_OVERRUN_L3, no_bucket, ERROR, [<Offset trace>,Set array size,<Length trace>,Assignment,Set array size,Array access: Offset: [0, 9] Size: [1, 10]]
codetoanalyze/objc/performance/NSMutableArray.m, nsmarray_set_linear, 2, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [<LHS trace>,Unknown value from: NSNumber.intValue,Binary operation: ([-oo, +oo] + 1):signed32]
codetoanalyze/objc/performance/NSSet.m, nsset_enumerator_linear, 7, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,<RHS trace>,Assignment,Binary operation: ([0, +oo] + [1, set->elements.length.ub + 1]):signed64]
codetoanalyze/objc/performance/NSSet.m, nsset_init_constant, 3, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/NSSet.m, nsset_iterate_linear, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,<RHS trace>,Assignment,Binary operation: ([0, +oo] + [1, set->elements.length.ub + 1]):signed64]
codetoanalyze/objc/performance/NSString.m, init_string_constant, 2, CONDITION_ALWAYS_FALSE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/NSString.m, replace_linear_FP, 0, INFINITE_EXECUTION_TIME, no_bucket, ERROR, [Unbounded loop,Loop]
codetoanalyze/objc/performance/NSString.m, replace_linear_FP, 2, INTEGER_OVERFLOW_U5, no_bucket, ERROR, [<LHS trace>,Unknown value from: NSString.stringByReplacingOccurrencesOfString:withString:,Binary operation: ([0, +oo] + 1):signed32]
codetoanalyze/objc/performance/block.m, objc_blockblock_multiply_array_linear_1, 3, INTEGER_OVERFLOW_L5, no_bucket, ERROR, [<LHS trace>,Assignment,<RHS trace>,Assignment,Binary operation: ([0, +oo] + [1, array->elements.length.ub + 1]):signed64]
codetoanalyze/objc/performance/compound_loop_guard.m, compound_while, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/compound_loop_guard.m, nested_while_and_or_constant, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]
codetoanalyze/objc/performance/compound_loop_guard.m, nested_while_and_or_constant, 3, CONDITION_ALWAYS_TRUE, no_bucket, WARNING, [Here]

Loading…
Cancel
Save