[Infer] Dedup the reporting of Captured StrongSelf

Summary: For each variable that we identify as a captured strong self, we want to report only the first occurrence.

Reviewed By: skcho

Differential Revision: D19940031

fbshipit-source-id: f38f642c9
master
Dulma Churchill 5 years ago committed by Facebook Github Bot
parent f6341977fb
commit 00c52a52c2

@ -318,3 +318,11 @@ let is_objc_static_local_of_proc_name pname pvar =
let is_block_pvar pvar = Typ.has_block_prefix (Mangled.to_string (get_name pvar)) let is_block_pvar pvar = Typ.has_block_prefix (Mangled.to_string (get_name pvar))
module Set = PrettyPrintable.MakePPSet (struct
type nonrec t = t
let compare = compare
let pp = pp Pp.text
end)

@ -168,3 +168,6 @@ val get_name_of_local_with_procname : t -> Mangled.t
val materialized_cpp_temporary : string val materialized_cpp_temporary : string
val rename : f:(string -> string) -> t -> t val rename : f:(string -> string) -> t -> t
module Set : PrettyPrintable.PPSet with type elt = t
(** Sets of pvars. *)

@ -133,6 +133,11 @@ module Domain = struct
&& StrongEqualToWeakCapturedVars.leq ~lhs:lhs.strongVars ~rhs:rhs.strongVars && StrongEqualToWeakCapturedVars.leq ~lhs:lhs.strongVars ~rhs:rhs.strongVars
end end
type report_issues_result =
{ weakSelfList: DomainData.t list
; selfList: DomainData.t list
; reported_captured_strong_self: Pvar.Set.t }
module TransferFunctions = struct module TransferFunctions = struct
module Domain = Domain module Domain = Domain
module CFG = ProcCfg.Normal module CFG = ProcCfg.Normal
@ -458,52 +463,66 @@ let report_weakself_multiple_issue summary domain (weakSelf1 : DomainData.t)
Reporting.log_error summary ~ltr ~loc:weakSelf1.loc IssueType.multiple_weakself message Reporting.log_error summary ~ltr ~loc:weakSelf1.loc IssueType.multiple_weakself message
let report_captured_strongself_issue domain summary (capturedStrongSelf : DomainData.t) = let report_captured_strongself_issue domain summary (capturedStrongSelf : DomainData.t)
report_captured_strongself =
if not (Pvar.Set.mem capturedStrongSelf.pvar report_captured_strongself) then (
let report_captured_strongself =
Pvar.Set.add capturedStrongSelf.pvar report_captured_strongself
in
let message = let message =
F.asprintf F.asprintf
"The variable `%a`, used at `%a`, is a strong pointer to `self` captured in this block. This \ "The variable `%a`, used at `%a`, is a strong pointer to `self` captured in this block. \
could lead to retain cycles or unexpected behavior since to avoid retain cycles one usually \ This could lead to retain cycles or unexpected behavior since to avoid retain cycles one \
uses a local strong pointer or a captured weak pointer instead." usually uses a local strong pointer or a captured weak pointer instead."
(Pvar.pp Pp.text) capturedStrongSelf.pvar Location.pp capturedStrongSelf.loc (Pvar.pp Pp.text) capturedStrongSelf.pvar Location.pp capturedStrongSelf.loc
in in
let ltr = make_trace_captured_strong_self domain in let ltr = make_trace_captured_strong_self domain in
Reporting.log_error summary ~ltr ~loc:capturedStrongSelf.loc IssueType.captured_strong_self Reporting.log_error summary ~ltr ~loc:capturedStrongSelf.loc IssueType.captured_strong_self
message message ;
report_captured_strongself )
else report_captured_strongself
let report_issues summary domain attributes = let report_issues summary domain attributes =
let process_domain_item _ (domain_data : DomainData.t) (weakSelfList, selfList) = let process_domain_item (result : report_issues_result) (_, (domain_data : DomainData.t)) =
match domain_data.kind with match domain_data.kind with
| DomainData.CAPTURED_STRONG_SELF -> | DomainData.CAPTURED_STRONG_SELF ->
report_captured_strongself_issue domain summary domain_data ; let reported_captured_strong_self =
(weakSelfList, selfList) report_captured_strongself_issue domain summary domain_data
result.reported_captured_strong_self
in
{result with reported_captured_strong_self}
| DomainData.WEAK_SELF -> | DomainData.WEAK_SELF ->
( match attributes.ProcAttributes.passed_as_noescape_block_to with ( match attributes.ProcAttributes.passed_as_noescape_block_to with
| Some procname -> | Some procname ->
report_weakself_in_no_escape_block_issues summary domain domain_data procname report_weakself_in_no_escape_block_issues summary domain domain_data procname
| None -> | None ->
() ) ; () ) ;
(domain_data :: weakSelfList, selfList) {result with weakSelfList= domain_data :: result.weakSelfList}
| DomainData.SELF -> | DomainData.SELF ->
(weakSelfList, domain_data :: selfList) {result with selfList= domain_data :: result.selfList}
| _ -> | _ ->
(weakSelfList, selfList) result
in in
let weakSelfList, selfList = Vars.fold process_domain_item domain ([], []) in let report_issues_result_empty =
let sorted_WeakSelfList = {weakSelfList= []; selfList= []; reported_captured_strong_self= Pvar.Set.empty}
List.sort weakSelfList ~compare:(fun {DomainData.loc= loc1} {DomainData.loc= loc2} ->
Location.compare loc1 loc2 )
in in
let sorted_selfList = let domain_bindings =
List.sort selfList ~compare:(fun {DomainData.loc= loc1} {DomainData.loc= loc2} -> Vars.bindings domain
|> List.sort ~compare:(fun (_, {DomainData.loc= loc1}) (_, {DomainData.loc= loc2}) ->
Location.compare loc1 loc2 ) Location.compare loc1 loc2 )
in in
( match (sorted_WeakSelfList, sorted_selfList) with let {weakSelfList; selfList} =
List.fold_left ~f:process_domain_item ~init:report_issues_result_empty domain_bindings
in
let weakSelfList = List.rev weakSelfList in
let selfList = List.rev selfList in
( match (weakSelfList, selfList) with
| weakSelf :: _, self :: _ -> | weakSelf :: _, self :: _ ->
report_mix_self_weakself_issues summary domain weakSelf self report_mix_self_weakself_issues summary domain weakSelf self
| _ -> | _ ->
() ) ; () ) ;
match sorted_WeakSelfList with match weakSelfList with
| weakSelf1 :: weakSelf2 :: _ -> | weakSelf1 :: weakSelf2 :: _ ->
report_weakself_multiple_issue summary domain weakSelf1 weakSelf2 report_weakself_multiple_issue summary domain weakSelf1 weakSelf2
| _ -> | _ ->

@ -209,6 +209,7 @@ void m2(_Nullable SelfInBlockTest* obj) {}
if (strongSelf) { if (strongSelf) {
int (^my_block)() = ^() { int (^my_block)() = ^() {
int x = strongSelf->x; // bug here int x = strongSelf->x; // bug here
x = strongSelf->x; // no bug here because of dedup
return 0; return 0;
}; };
int x = strongSelf->x; int x = strongSelf->x;

@ -6,4 +6,4 @@ codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strong
codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strongSelfCheckOnce_bad_5, 6, STRONG_SELF_NOT_CHECKED, no_bucket, ERROR, [&strongSelf assigned here,Using &strongSelf not checked for null,Using &strongSelf not checked for null] codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strongSelfCheckOnce_bad_5, 6, STRONG_SELF_NOT_CHECKED, no_bucket, ERROR, [&strongSelf assigned here,Using &strongSelf not checked for null,Using &strongSelf not checked for null]
codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strongSelfNoCheckNotWeakSelf_good_2, 1, CAPTURED_STRONG_SELF, no_bucket, ERROR, [Using captured &weakSelf] codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strongSelfNoCheckNotWeakSelf_good_2, 1, CAPTURED_STRONG_SELF, no_bucket, ERROR, [Using captured &weakSelf]
codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::weakSelfMultiple_bad_14, 1, MULTIPLE_WEAKSELF, no_bucket, ERROR, [Using &weakSelf,Using &weakSelf] codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::weakSelfMultiple_bad_14, 1, MULTIPLE_WEAKSELF, no_bucket, ERROR, [Using &weakSelf,Using &weakSelf]
codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockobjc_blockSelfInBlockTest::capturedStrongSelf_bad_15_16, 1, CAPTURED_STRONG_SELF, no_bucket, ERROR, [Using captured &strongSelf] codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockobjc_blockSelfInBlockTest::capturedStrongSelf_bad_15_16, 1, CAPTURED_STRONG_SELF, no_bucket, ERROR, [Using captured &strongSelf,Using captured &strongSelf]

Loading…
Cancel
Save