diff --git a/infer/lib/linter_rules/linters.al b/infer/lib/linter_rules/linters.al index 3944372c5..bd4308af9 100644 --- a/infer/lib/linter_rules/linters.al +++ b/infer/lib/linter_rules/linters.al @@ -267,3 +267,16 @@ DEFINE-CHECKER DISCOURAGED_WEAK_PROPERTY_CUSTOM_SETTER = { SET severity = "WARNING"; SET mode = "OFF"; }; + +DEFINE-CHECKER WRONG_SCOPE_FOR_DISPATCH_ONCE_T = { + + SET report_when = + WHEN + NOT (is_global_var() OR is_static_local_var()) AND + has_type("dispatch_once_t") + HOLDS-IN-NODE VarDecl; + + SET message = "Variables of type dispatch_once_t must have global or static scope. The result of using this type with automatic or dynamic allocation is undefined."; + SET severity = "WARNING"; + SET mode = "OFF"; +}; diff --git a/infer/tests/codetoanalyze/objc/linters/dispatch.m b/infer/tests/codetoanalyze/objc/linters/dispatch.m new file mode 100644 index 000000000..fede51c0c --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters/dispatch.m @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#import + +@interface A : NSObject +@end + +@implementation A + ++ (instancetype)sharedInstanceOK { + static id _sharedInstance = nil; + static dispatch_once_t onceTokenA; + dispatch_once(&onceTokenA, ^{ + _sharedInstance = [[self alloc] init]; + }); + + return _sharedInstance; +} + +@end + +@interface B : NSObject +@end + +@implementation B + ++ (instancetype)sharedInstanceBAD { + static id _sharedInstance = nil; + dispatch_once_t onceTokenB; + dispatch_once(&onceTokenB, ^{ + _sharedInstance = [[self alloc] init]; + }); + + return _sharedInstance; +} + +@end diff --git a/infer/tests/codetoanalyze/objc/linters/issues.exp b/infer/tests/codetoanalyze/objc/linters/issues.exp index b2489f80f..e88c4474f 100644 --- a/infer/tests/codetoanalyze/objc/linters/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters/issues.exp @@ -30,6 +30,7 @@ codetoanalyze/objc/linters/badpointer.m, bad5, 97, BAD_POINTER_COMPARISON, no_bu codetoanalyze/objc/linters/badpointer.m, bad6, 104, BAD_POINTER_COMPARISON, no_bucket, WARNING, [] codetoanalyze/objc/linters/badpointer.m, bad8, 119, BAD_POINTER_COMPARISON, no_bucket, WARNING, [] codetoanalyze/objc/linters/badpointer.m, bad9, 126, BAD_POINTER_COMPARISON, no_bucket, WARNING, [] +codetoanalyze/objc/linters/dispatch.m, B_sharedInstanceBAD, 33, WRONG_SCOPE_FOR_DISPATCH_ONCE_T, no_bucket, WARNING, [] codetoanalyze/objc/linters/implicit_cast.m, Implicit_cast_call_with_boxed_int, 67, POINTER_TO_INTEGRAL_IMPLICIT_CAST, no_bucket, WARNING, [] codetoanalyze/objc/linters/implicit_cast.m, Implicit_cast_call_with_string, 60, POINTER_TO_INTEGRAL_IMPLICIT_CAST, no_bucket, WARNING, [] codetoanalyze/objc/linters/implicit_cast.m, Implicit_cast_ivar_dictionary_item_call_funct_with_int, 45, POINTER_TO_INTEGRAL_IMPLICIT_CAST, no_bucket, WARNING, []