[self-in-block] Add new issue type MULTIPLE_WEAKSELF

Summary: Raises an error when weakSelf is used multiple times in a block. The issue is that there could be unexpected behaviour. Even if `weakSelf` is not nil in the first use, it could be nil in the following uses since the object that `weakSelf` points to could be freed anytime.

Reviewed By: skcho

Differential Revision: D18765493

fbshipit-source-id: 37fc652e3
master
Dulma Churchill 5 years ago committed by Facebook Github Bot
parent 431a9beaf0
commit f69d0992bc

@ -449,6 +449,7 @@ OPTIONS
MEMORY_LEAK (enabled by default), MEMORY_LEAK (enabled by default),
MISSING_REQUIRED_PROP (enabled by default), MISSING_REQUIRED_PROP (enabled by default),
MIXED_SELF_WEAKSELF (enabled by default), MIXED_SELF_WEAKSELF (enabled by default),
MULTIPLE_WEAKSELF (enabled by default),
MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default), MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default),
Missing_fld (enabled by default), Missing_fld (enabled by default),
NULLPTR_DEREFERENCE (disabled by default), NULLPTR_DEREFERENCE (disabled by default),

@ -191,6 +191,7 @@ OPTIONS
MEMORY_LEAK (enabled by default), MEMORY_LEAK (enabled by default),
MISSING_REQUIRED_PROP (enabled by default), MISSING_REQUIRED_PROP (enabled by default),
MIXED_SELF_WEAKSELF (enabled by default), MIXED_SELF_WEAKSELF (enabled by default),
MULTIPLE_WEAKSELF (enabled by default),
MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default), MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default),
Missing_fld (enabled by default), Missing_fld (enabled by default),
NULLPTR_DEREFERENCE (disabled by default), NULLPTR_DEREFERENCE (disabled by default),

@ -449,6 +449,7 @@ OPTIONS
MEMORY_LEAK (enabled by default), MEMORY_LEAK (enabled by default),
MISSING_REQUIRED_PROP (enabled by default), MISSING_REQUIRED_PROP (enabled by default),
MIXED_SELF_WEAKSELF (enabled by default), MIXED_SELF_WEAKSELF (enabled by default),
MULTIPLE_WEAKSELF (enabled by default),
MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default), MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE (enabled by default),
Missing_fld (enabled by default), Missing_fld (enabled by default),
NULLPTR_DEREFERENCE (disabled by default), NULLPTR_DEREFERENCE (disabled by default),

@ -362,6 +362,8 @@ let missing_required_prop = register_from_string "MISSING_REQUIRED_PROP"
let mixed_self_weakself = register_from_string "MIXED_SELF_WEAKSELF" ~hum:"Mixed Self WeakSelf" let mixed_self_weakself = register_from_string "MIXED_SELF_WEAKSELF" ~hum:"Mixed Self WeakSelf"
let multiple_weakself = register_from_string "MULTIPLE_WEAKSELF" ~hum:"Multiple WeakSelf Use"
let mutable_local_variable_in_component_file = let mutable_local_variable_in_component_file =
register_from_string "MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE" register_from_string "MUTABLE_LOCAL_VARIABLE_IN_COMPONENT_FILE"

@ -235,6 +235,8 @@ val missing_required_prop : t
val mixed_self_weakself : t val mixed_self_weakself : t
val multiple_weakself : t
val mutable_local_variable_in_component_file : t val mutable_local_variable_in_component_file : t
val null_dereference : t val null_dereference : t

@ -210,7 +210,7 @@ module TransferFunctions = struct
astate astate
end end
let make_trace_mixed_self_weakself domain = let make_trace_use_self_weakself domain =
let trace_elems = let trace_elems =
Vars.fold Vars.fold
(fun _ {pvar; loc; kind} trace_elems -> (fun _ {pvar; loc; kind} trace_elems ->
@ -240,12 +240,38 @@ let report_mix_self_weakself_issues summary domain =
unexpected behavior." unexpected behavior."
(Pvar.pp Pp.text) weakSelf Location.pp weakLoc (Pvar.pp Pp.text) self Location.pp selfLoc (Pvar.pp Pp.text) weakSelf Location.pp weakLoc (Pvar.pp Pp.text) self Location.pp selfLoc
in in
let ltr = make_trace_mixed_self_weakself domain in let ltr = make_trace_use_self_weakself domain in
Reporting.log_error summary ~ltr ~loc:selfLoc IssueType.mixed_self_weakself message Reporting.log_error summary ~ltr ~loc:selfLoc IssueType.mixed_self_weakself message
| _ -> | _ ->
() ()
let report_weakself_multiple_issues summary domain =
let weakSelfs =
Vars.filter (fun _ {kind} -> DomainData.is_weak_self kind) domain
|> Vars.bindings |> List.map ~f:snd
in
let sorted_WeakSelfs =
List.sort weakSelfs ~compare:(fun {DomainData.loc= loc1} {DomainData.loc= loc2} ->
Location.compare loc1 loc2 )
in
match sorted_WeakSelfs with
| {pvar= weakSelf; loc= weakLoc1} :: {loc= weakLoc2} :: _ ->
let message =
F.asprintf
"This block uses the weak pointer `%a` more than once (%a) and (%a). This could lead to \
unexpected behavior. Even if `%a` is not nil in the first use, it could be nil in the \
following uses since the object that `%a` points to could be freed anytime; assign it \
to a strong variable first."
(Pvar.pp Pp.text) weakSelf Location.pp weakLoc1 Location.pp weakLoc2 (Pvar.pp Pp.text)
weakSelf (Pvar.pp Pp.text) weakSelf
in
let ltr = make_trace_use_self_weakself domain in
Reporting.log_error summary ~ltr ~loc:weakLoc1 IssueType.multiple_weakself message
| _ ->
()
let make_trace_unchecked_strongself (domain : Domain.t) = let make_trace_unchecked_strongself (domain : Domain.t) =
let trace_elems_strongVars = let trace_elems_strongVars =
StrongEqualToWeakCapturedVars.fold StrongEqualToWeakCapturedVars.fold
@ -304,7 +330,8 @@ let checker {Callbacks.exe_env; summary} =
match Analyzer.compute_post proc_data ~initial with match Analyzer.compute_post proc_data ~initial with
| Some domain -> | Some domain ->
report_mix_self_weakself_issues summary domain.vars ; report_mix_self_weakself_issues summary domain.vars ;
report_unchecked_strongself_issues summary domain report_unchecked_strongself_issues summary domain ;
report_weakself_multiple_issues summary domain.vars
| None -> | None ->
() ) ; () ) ;
summary summary

@ -11,6 +11,8 @@
- (void)foo; - (void)foo;
- (void)bar;
@end @end
@implementation SelfInBlockTest { @implementation SelfInBlockTest {
@ -20,6 +22,9 @@
- (void)foo { - (void)foo {
} }
- (void)bar {
}
- (void)mixSelfWeakSelf_bad { - (void)mixSelfWeakSelf_bad {
__weak __typeof(self) weakSelf = self; __weak __typeof(self) weakSelf = self;
int (^my_block)() = ^() { int (^my_block)() = ^() {
@ -116,4 +121,12 @@
}; };
} }
- (void)wekSelfMultiple_bad {
__weak __typeof(self) weakSelf = self;
int (^my_block)(BOOL) = ^(BOOL isTapped) {
[weakSelf foo];
[weakSelf bar];
return 0;
};
}
@end @end

@ -3,3 +3,4 @@ codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strong
codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strongSelfCheckOnce_bad_5, 8, 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, 8, 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::strongSelfNoCheck2_bad_4, 2, STRONG_SELF_NOT_CHECKED, no_bucket, ERROR, [&strongSelf assigned here,Using &strongSelf not checked for null] codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strongSelfNoCheck2_bad_4, 2, STRONG_SELF_NOT_CHECKED, no_bucket, ERROR, [&strongSelf assigned here,Using &strongSelf not checked for null]
codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strongSelfNoCheck_bad_3, 2, STRONG_SELF_NOT_CHECKED, no_bucket, ERROR, [&strongSelf assigned here,Using &strongSelf not checked for null] codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::strongSelfNoCheck_bad_3, 2, STRONG_SELF_NOT_CHECKED, no_bucket, ERROR, [&strongSelf assigned here,Using &strongSelf not checked for null]
codetoanalyze/objc/self-in-block/StrongSelf.m, objc_blockSelfInBlockTest::wekSelfMultiple_bad_9, 1, MULTIPLE_WEAKSELF, no_bucket, ERROR, [Using &weakSelf,Using &weakSelf]

Loading…
Cancel
Save