From 86140581d5e8690ac8ba82965aaa9d970acbb78e Mon Sep 17 00:00:00 2001 From: Dulma Churchill Date: Wed, 11 Sep 2019 07:03:40 -0700 Subject: [PATCH] [AL] Adding predicate for AL rule to check that a variable of a specific type is being captured in a block Reviewed By: ddino Differential Revision: D17261362 fbshipit-source-id: 81f2e4bdb --- infer/src/al/cPredicates.ml | 17 +++++++++++ infer/src/al/cPredicates.mli | 3 ++ infer/src/al/cTL.ml | 2 ++ .../al_definitions/linters_example.al | 11 +++++++ .../objc/linters-for-test-only/issues.exp | 1 + .../variables_captured_in_block.m | 30 +++++++++++++++++++ 6 files changed, 64 insertions(+) create mode 100644 infer/tests/codetoanalyze/objc/linters-for-test-only/variables_captured_in_block.m diff --git a/infer/src/al/cPredicates.ml b/infer/src/al/cPredicates.ml index 8e5fcc3bd..f4782c24b 100644 --- a/infer/src/al/cPredicates.ml +++ b/infer/src/al/cPredicates.ml @@ -1592,3 +1592,20 @@ let is_in_source_file an path_re = let is_referencing_decl_from_source_file an path_re = source_file_matches (Ctl_parser_types.get_referenced_decl_source_file an) path_re + + +let captured_var_of_type typ captured_var = + match captured_var.Clang_ast_t.bcv_variable with + | Some dr -> + let _, _, qt = CAst_utils.get_info_from_decl_ref dr in + type_ptr_equal_type qt.Clang_ast_t.qt_type_ptr (ALVar.alexp_to_string typ) + | _ -> + false + + +let objc_block_is_capturing_var_of_type an typ = + match an with + | Ctl_parser_types.Decl (Clang_ast_t.BlockDecl (_, bdi)) -> + List.exists ~f:(captured_var_of_type typ) bdi.bdi_captured_variables + | _ -> + false diff --git a/infer/src/al/cPredicates.mli b/infer/src/al/cPredicates.mli index be812798d..cfc814aea 100644 --- a/infer/src/al/cPredicates.mli +++ b/infer/src/al/cPredicates.mli @@ -14,6 +14,9 @@ type t = ALVar.formula_id * ALVar.alexp list [@@deriving compare] val captured_variables_cxx_ref : Ctl_parser_types.ast_node -> Clang_ast_t.named_decl_info list (** list of cxx references captured by an ObjC Block *) +val objc_block_is_capturing_var_of_type : Ctl_parser_types.ast_node -> ALVar.t -> bool +(** true if the ObjC Block captures a variable of a given type *) + val objc_block_is_capturing_values : Ctl_parser_types.ast_node -> bool (** true if the ObjC Block captures any variables *) diff --git a/infer/src/al/cTL.ml b/infer/src/al/cTL.ml index 702d9d107..d54997c4c 100644 --- a/infer/src/al/cTL.ml +++ b/infer/src/al/cTL.ml @@ -1222,6 +1222,8 @@ let rec eval_Atomic pred_name_ args an lcxt = CPredicates.is_in_source_file an path_re | "is_referencing_decl_from_source_file", [path_re], an -> CPredicates.is_referencing_decl_from_source_file an path_re + | "objc_block_is_capturing_var_of_type", [typ], an -> + CPredicates.objc_block_is_capturing_var_of_type an typ | _ -> L.(die ExternalError) "Undefined Predicate or wrong set of arguments: '%s'" pred_name diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al b/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al index aea52e6d2..bd7cf7ebb 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/al_definitions/linters_example.al @@ -877,3 +877,14 @@ DEFINE-CHECKER TEST_IS_OPTIONAL_METHOD = { SET message = "This is an optional method"; }; + +DEFINE-CHECKER IVAR_CAPTURED_IN_OBJC_BLOCK = { + SET report_when = + WHEN + objc_block_is_capturing_var_of_type("Ivars*") + HOLDS-IN-NODE BlockDecl; + + SET message = "Found ivar of a given type captured in block"; + SET severity = "ERROR"; + SET mode = "ON"; + }; diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp index 8563b68c5..673c2c5ad 100644 --- a/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/issues.exp @@ -329,6 +329,7 @@ codetoanalyze/objc/linters-for-test-only/unavailable.m, FooClass::new, 12, TEST_ codetoanalyze/objc/linters-for-test-only/unavailable.m, FooClass::new, 12, TEST_IS_OVERRIDING_METHOD, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/unavailable.m, FooClass::new, 12, TEST_UNAVAILABLE_ATTR, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/unavailable.m, FooClass::newWithFoo, 13, TEST_INSTANCE_TYPE, no_bucket, WARNING, [] +codetoanalyze/objc/linters-for-test-only/variables_captured_in_block.m, objc_block, 26, IVAR_CAPTURED_IN_OBJC_BLOCK, no_bucket, ERROR, [] codetoanalyze/objc/linters-for-test-only/visibility.c, bar, 29, TEST_DEFAULT_VISIBILITY, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/visibility.c, bar, 30, TEST_DEFAULT_VISIBILITY, no_bucket, WARNING, [] codetoanalyze/objc/linters-for-test-only/visibility.c, bar, 31, TEST_HIDDEN_VISIBILITY, no_bucket, WARNING, [] diff --git a/infer/tests/codetoanalyze/objc/linters-for-test-only/variables_captured_in_block.m b/infer/tests/codetoanalyze/objc/linters-for-test-only/variables_captured_in_block.m new file mode 100644 index 000000000..a53ea95c0 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters-for-test-only/variables_captured_in_block.m @@ -0,0 +1,30 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +#import + +typedef struct LSIvarsContext { + void* ivars; +} LSIvarsContext; + +typedef struct Ivars { + void (*dealloc)(struct Ivars*); + NSString* str; +} Ivars; + +@interface T : NSObject +@end +@implementation T + +- (void)m { + LSIvarsContext __blablaContext; + Ivars* blabla = (Ivars*)__blablaContext.ivars; + + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + blabla->str = @"str"; + }); +} +@end