[retain cycles] Define custom compare function that is more suited to dedup cycles

Reviewed By: mbouaziz

Differential Revision: D7517385

fbshipit-source-id: 00e0433
master
Dulma Churchill 7 years ago committed by Facebook Github Bot
parent 6cf7417e56
commit 74e16bdb58

@ -8,24 +8,48 @@
*)
open! IStd
type retain_cycle_node = {rc_node_exp: Exp.t; rc_node_typ: Typ.t} [@@deriving compare]
type retain_cycle_node = {rc_node_exp: Exp.t; rc_node_typ: Typ.t}
type retain_cycle_field_objc =
{rc_field_name: Typ.Fieldname.t; rc_field_inst: Sil.inst}
[@@deriving compare]
type retain_cycle_field = {rc_field_name: Typ.Fieldname.t; rc_field_inst: Sil.inst}
type retain_cycle_edge_objc =
{rc_from: retain_cycle_node; rc_field: retain_cycle_field_objc}
[@@deriving compare]
type retain_cycle_edge_obj = {rc_from: retain_cycle_node; rc_field: retain_cycle_field}
type retain_cycle_edge =
| Object of retain_cycle_edge_objc
| Block of Typ.Procname.t * Pvar.t
[@@deriving compare]
type retain_cycle_edge = Object of retain_cycle_edge_obj | Block of Typ.Procname.t * Pvar.t
let retain_cycle_edge_equal = [%compare.equal : retain_cycle_edge]
type t = {rc_head: retain_cycle_edge; rc_elements: retain_cycle_edge list}
let compare_retain_cycle_node (node1: retain_cycle_node) (node2: retain_cycle_node) =
Typ.compare node1.rc_node_typ node2.rc_node_typ
let compare_retain_cycle_field (node1: retain_cycle_field) (node2: retain_cycle_field) =
Typ.Fieldname.compare node1.rc_field_name node2.rc_field_name
let compare_retain_cycle_edge_obj (obj1: retain_cycle_edge_obj) (obj2: retain_cycle_edge_obj) =
let obj1_pair = Tuple.T2.create obj1.rc_from obj1.rc_field in
let obj2_pair = Tuple.T2.create obj2.rc_from obj2.rc_field in
Tuple.T2.compare ~cmp1:compare_retain_cycle_node ~cmp2:compare_retain_cycle_field obj1_pair
obj2_pair
let compare_retain_cycle_edge (edge1: retain_cycle_edge) (edge2: retain_cycle_edge) =
match (edge1, edge2) with
| Object edge_obj1, Object edge_obj2 ->
compare_retain_cycle_edge_obj edge_obj1 edge_obj2
| Block (procname1, _), Block (procname2, _) ->
Typ.Procname.compare procname1 procname2
| Object _, Block _ ->
1
| Block _, Object _ ->
-1
let equal_retain_cycle_edge = [%compare.equal : retain_cycle_edge]
let compare (rc1: t) (rc2: t) =
List.compare compare_retain_cycle_edge rc1.rc_elements rc2.rc_elements
type t = {rc_head: retain_cycle_edge; rc_elements: retain_cycle_edge list} [@@deriving compare]
module Set = Caml.Set.Make (struct
type nonrec t = t
@ -45,7 +69,7 @@ let _retain_cycle_node_to_string (node: retain_cycle_node) =
Format.sprintf "%s : %s" (Exp.to_string node.rc_node_exp) (Typ.to_string node.rc_node_typ)
let retain_cycle_field_to_string (field: retain_cycle_field_objc) =
let retain_cycle_field_to_string (field: retain_cycle_field) =
Format.sprintf "%s[%s]"
(Typ.Fieldname.to_string field.rc_field_name)
(Sil.inst_to_string field.rc_field_inst)
@ -76,7 +100,7 @@ let find_minimum_element cycle =
let shift cycle head : t =
let rec shift_elements rev_tail elements =
match elements with
| hd :: rest when not (retain_cycle_edge_equal hd head) ->
| hd :: rest when not (equal_retain_cycle_edge hd head) ->
shift_elements (hd :: rev_tail) rest
| _ ->
elements @ List.rev rev_tail

@ -11,11 +11,11 @@ open! IStd
type retain_cycle_node = {rc_node_exp: Exp.t; rc_node_typ: Typ.t}
type retain_cycle_field_objc = {rc_field_name: Typ.Fieldname.t; rc_field_inst: Sil.inst}
type retain_cycle_field = {rc_field_name: Typ.Fieldname.t; rc_field_inst: Sil.inst}
type retain_cycle_edge_objc = {rc_from: retain_cycle_node; rc_field: retain_cycle_field_objc}
type retain_cycle_edge_obj = {rc_from: retain_cycle_node; rc_field: retain_cycle_field}
type retain_cycle_edge = Object of retain_cycle_edge_objc | Block of Typ.Procname.t * Pvar.t
type retain_cycle_edge = Object of retain_cycle_edge_obj | Block of Typ.Procname.t * Pvar.t
(** A retain cycle is a non-empty list of paths. It also contains a pointer to the head of the list
to model the cycle structure. The next element from the end of the list is the head. *)

@ -96,6 +96,7 @@ SOURCES_ARC = \
memory_leaks_benchmark/RetainCycleBlocks.m \
memory_leaks_benchmark/RetainCyclePropertyInProtocol.m \
memory_leaks_benchmark/RetainCycleBlockCapturedVar.m \
memory_leaks_benchmark/RetainCycleDeduplication.m \
npe/BoxedNumberExample.m \
npe/ObjCMethodCallInCondition.m \
npe/UpdateDict.m \

@ -33,6 +33,7 @@ codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleBlockCapturedVar.m,
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleBlocks.m, RCBlock_retain_self_in_block, 1, RETAIN_CYCLE, ERROR, [start of procedure retain_self_in_block,Executing synthesized setter setHandler:]
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleBlocks.m, objc_blockretain_a_in_block_cycle_3, 1, RETAIN_CYCLE, ERROR, [start of procedure block,Executing synthesized setter setChild:]
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleBlocks.m, retain_a_in_block_cycle, 4, RETAIN_CYCLE, ERROR, [start of procedure retain_a_in_block_cycle(),Executing synthesized setter setB:,Executing synthesized setter setA:]
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleDeduplication.m, CViewController_setCaptureInteractionController:, 4, RETAIN_CYCLE, ERROR, [start of procedure setCaptureInteractionController:,Condition is true,Executing synthesized setter setDelegate:,Executing synthesized setter setDelegate:]
codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCyclePropertyInProtocol.m, MyCustomViewController_loadViewBad, 3, RETAIN_CYCLE, ERROR, [start of procedure loadViewBad,Executing synthesized setter setView:,Executing synthesized setter setStrong_delegate:]
codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle.m, strongcycle, 6, RETAIN_CYCLE, ERROR, [start of procedure strongcycle(),Executing synthesized setter setB:,Executing synthesized setter setA:]
codetoanalyze/objc/errors/memory_leaks_benchmark/retain_cycle2.m, strongcycle2, 4, RETAIN_CYCLE, ERROR, [start of procedure strongcycle2(),start of procedure init,return from a call to Parent_init,start of procedure init,return from a call to Child_init,start of procedure setChild:,return from a call to Parent_setChild:,start of procedure setParent:,return from a call to Child_setParent:]

@ -0,0 +1,37 @@
/*
* Copyright (c) 2018 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <Foundation/NSObject.h>
@interface CaptureController : NSObject
@property(nonatomic, strong, readwrite) id delegate;
@end
@implementation CaptureController
@end
@interface CViewController : NSObject
@property(nonatomic, strong) CaptureController* captureController;
@end
@implementation CViewController
- (void)setCaptureInteractionController:(CaptureController*)captureController {
if (_captureController != captureController) {
_captureController.delegate = nil;
_captureController = captureController;
_captureController.delegate = self;
}
}
@end
Loading…
Cancel
Save