diff --git a/facebook-clang-plugins b/facebook-clang-plugins index da6b966a3..025a3740a 160000 --- a/facebook-clang-plugins +++ b/facebook-clang-plugins @@ -1 +1 @@ -Subproject commit da6b966a35b1183387d51d1f1a87a16200069595 +Subproject commit 025a3740a6956e112ed0dbc0f87d3f5500d9c52b diff --git a/infer/lib/linter_rules/linters.al b/infer/lib/linter_rules/linters.al index 0b168dc7a..2cbe88070 100644 --- a/infer/lib/linter_rules/linters.al +++ b/infer/lib/linter_rules/linters.al @@ -222,3 +222,11 @@ DEFINE-CHECKER CXX_REFERENCE_CAPTURED_IN_OBJC_BLOCK = { SET suggestion = "This could cause a crash."; SET severity = "ERROR"; }; + + +DEFINE-CHECKER POINTER_TO_INTEGRAL_IMPLICIT_CAST = { + SET report_when = + WHEN has_cast_kind("PointerToIntegral") + HOLDS-IN-NODE ImplicitCastExpr; + SET message = "Implicit conversion from %child_type% to %type% in usage of %eventual_child_name%"; +}; diff --git a/infer/src/clang/cFrontend_checkers.ml b/infer/src/clang/cFrontend_checkers.ml index ace99cbe3..dec7a112a 100644 --- a/infer/src/clang/cFrontend_checkers.ml +++ b/infer/src/clang/cFrontend_checkers.ml @@ -9,17 +9,6 @@ open! IStd -(* To create a new checker you should: *) -(* 1. Define a checker function, say my_checker, in this module. *) -(* my_checker should define: *) -(* -a) a condition that determine if the checker fires *) -(* -b) a issue_desc that describes the warning (see warning_desc definition) *) -(* 2. Add your checker to the CFrontend_checkers interface *) -(* 3. Decide in which element of the AST my_checker should be evaluated. *) -(* - If it is a statement then you need to invoke my_checker from *) -(* run_frontend_checkers_on_stmt in CFrontend_error module.*) -(* - If it is a declaration invoke it from run_frontend_checkers_on_decl *) - (* Helper functions *) let location_from_stmt lctx stmt = let info, _ = Clang_ast_proj.get_stmt_tuple stmt in diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index 2f83cb565..3e3969c02 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -94,6 +94,9 @@ let evaluate_place_holder ph an = | "%iphoneos_target_sdk_version%" -> MF.monospaced_to_string (CFrontend_checkers.iphoneos_target_sdk_version an) | "%available_ios_sdk%" -> MF.monospaced_to_string (CFrontend_checkers.available_ios_sdk an) + | "%type%" -> MF.monospaced_to_string (Ctl_parser_types.ast_node_type an) + | "%child_type%" -> MF.monospaced_to_string (Ctl_parser_types.stmt_node_child_type an) + | "%eventual_child_name%" -> MF.monospaced_to_string (Ctl_parser_types.eventual_child_name an) | _ -> (Logging.out "ERROR: helper function %s is unknown. Stop.\n" ph; assert false) diff --git a/infer/src/clang/cPredicates.ml b/infer/src/clang/cPredicates.ml index faf7b0135..d4dc2e975 100644 --- a/infer/src/clang/cPredicates.ml +++ b/infer/src/clang/cPredicates.ml @@ -267,6 +267,17 @@ let is_unop_with_kind an alexp_kind = ALVar.compare_str_with_alexp (Clang_ast_proj.string_of_unop_kind uoi.uoi_kind) alexp_kind | _ -> false +let has_cast_kind an alexp_kind = + match an with + | Ctl_parser_types.Decl _ -> false + | Ctl_parser_types.Stmt stmt -> + let str_kind = ALVar.alexp_to_string alexp_kind in + match Clang_ast_proj.get_cast_kind stmt with + | Some cast_kind -> + let cast_kind_str = Clang_ast_proj.string_of_cast_kind cast_kind in + String.equal cast_kind_str str_kind + | None -> false + let is_node an nodename = let nodename_str = ALVar.alexp_to_string nodename in if not (Clang_ast_proj.is_valid_astnode_kind nodename_str) then diff --git a/infer/src/clang/cPredicates.mli b/infer/src/clang/cPredicates.mli index d4ed0e508..64c4cc981 100644 --- a/infer/src/clang/cPredicates.mli +++ b/infer/src/clang/cPredicates.mli @@ -52,6 +52,8 @@ val is_binop_with_kind : Ctl_parser_types.ast_node -> ALVar.alexp -> bool val is_unop_with_kind : Ctl_parser_types.ast_node -> ALVar.alexp -> bool +val has_cast_kind : Ctl_parser_types.ast_node -> ALVar.alexp -> bool + val isa : Ctl_parser_types.ast_node -> ALVar.alexp -> bool val is_node : Ctl_parser_types.ast_node -> ALVar.alexp -> bool diff --git a/infer/src/clang/cTL.ml b/infer/src/clang/cTL.ml index c0311ae87..5722bc5f3 100644 --- a/infer/src/clang/cTL.ml +++ b/infer/src/clang/cTL.ml @@ -158,7 +158,8 @@ module Debug = struct let pp_node_info fmt an = let name = Ctl_parser_types.ast_node_name an in let typ = Ctl_parser_types.ast_node_type an in - Format.fprintf fmt " %s %s" name typ in + let cast_kind = Ctl_parser_types.ast_node_cast_kind an in + Format.fprintf fmt " %s %s %s" name typ cast_kind in let rec pp_children pp_node wrapper fmt level nodes = match nodes with | [] -> () @@ -619,6 +620,7 @@ let rec eval_Atomic _pred_name args an lcxt = | "declaration_ref_name", [decl_name], an -> CPredicates.declaration_ref_name an decl_name | "decl_unavailable_in_supported_ios_sdk", [], an -> CPredicates.decl_unavailable_in_supported_ios_sdk lcxt an + | "has_cast_kind", [name], an -> CPredicates.has_cast_kind an name | "has_type", [typ], an -> CPredicates.has_type an typ | "isa", [classname], an -> CPredicates.isa an classname | "is_assign_property", [], an -> CPredicates.is_assign_property an diff --git a/infer/src/clang/ctl_parser_types.ml b/infer/src/clang/ctl_parser_types.ml index 0d7ec3ee0..15ea0c666 100644 --- a/infer/src/clang/ctl_parser_types.ml +++ b/infer/src/clang/ctl_parser_types.ml @@ -37,6 +37,19 @@ let ast_node_name an = omei_selector | _ -> "" +let rec eventual_child_name an = + match an with + | Stmt stmt -> + (let _, stmts = Clang_ast_proj.get_stmt_tuple stmt in + match stmts with + | [stmt] -> + let name = ast_node_name (Stmt stmt) in + if String.length name > 0 then + name + else eventual_child_name (Stmt stmt) + | _ -> "") + | _ -> "" + let infer_prefix = "__infer_ctl_" exception ALParsingException of string @@ -160,6 +173,14 @@ let builtin_equal bi abi = | _, _ -> display_equality_warning (); false +let typename_to_string pointer = + match CAst_utils.get_decl pointer with + | Some decl -> + (match Clang_ast_proj.get_named_decl_tuple decl with + | Some (_, name_decl) -> Some name_decl.ni_name + | None -> None) + | _ -> None + let rec pointer_type_equal p ap = let open Clang_ast_t in match p, ap with @@ -173,13 +194,10 @@ let rec pointer_type_equal p ap = false and typename_equal pointer typename = - match CAst_utils.get_decl pointer with - | Some decl -> - (match Clang_ast_proj.get_named_decl_tuple decl with - | Some (_, name_decl) -> ALVar.compare_str_with_alexp name_decl.ni_name typename - | None -> false) - | _ -> false - + match typename_to_string pointer with + | Some name -> + ALVar.compare_str_with_alexp name typename + | None -> false (* Temporary, partial equality function. Cover only what's covered by the types_parser. It needs to be replaced by a real @@ -205,10 +223,18 @@ and c_type_equal c_type abs_ctype = false (* to be extended with more types *) -let typ_string_of_type_ptr type_ptr = +let rec typ_string_of_type_ptr type_ptr = + let open Clang_ast_t in match CAst_utils.get_type type_ptr with - | Some Clang_ast_t.BuiltinType (_, bt) -> + | Some BuiltinType (_, bt) -> Clang_ast_j.string_of_builtin_type_kind bt + | Some PointerType (_, qt) + | Some ObjCObjectPointerType (_, qt) -> + (typ_string_of_type_ptr qt.qt_type_ptr) ^ "*" + | Some ObjCInterfaceType (_, pointer) -> + Option.value ~default:"" (typename_to_string pointer) + | Some TypedefType (_, tdi) -> + Option.value ~default:"" (typename_to_string tdi.tti_decl_ptr) | _ -> "" let ast_node_type an = @@ -223,3 +249,20 @@ let ast_node_type an = | Some type_ptr -> typ_string_of_type_ptr type_ptr | _ -> "") + +let stmt_node_child_type an = + match an with + | Stmt stmt -> + (let _, stmts = Clang_ast_proj.get_stmt_tuple stmt in + match stmts with + | [stmt] -> ast_node_type (Stmt stmt) + | _ -> "") + | _ -> "" + +let ast_node_cast_kind an = + match an with + | Decl _ -> "" + | Stmt stmt -> + match Clang_ast_proj.get_cast_kind stmt with + | Some cast_kind -> Clang_ast_proj.string_of_cast_kind cast_kind + | None -> "" diff --git a/infer/src/clang/ctl_parser_types.mli b/infer/src/clang/ctl_parser_types.mli index 114608a61..68ac935aa 100644 --- a/infer/src/clang/ctl_parser_types.mli +++ b/infer/src/clang/ctl_parser_types.mli @@ -16,8 +16,14 @@ type ast_node = val ast_node_name : ast_node -> string +val eventual_child_name : ast_node -> string + val ast_node_type : ast_node -> string +val stmt_node_child_type : ast_node -> string + +val ast_node_cast_kind : ast_node -> string + exception ALParsingException of string val infer_prefix : string diff --git a/infer/tests/codetoanalyze/objc/linters/implicit_cast.m b/infer/tests/codetoanalyze/objc/linters/implicit_cast.m new file mode 100644 index 000000000..5212f298f --- /dev/null +++ b/infer/tests/codetoanalyze/objc/linters/implicit_cast.m @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017 - 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 + +int func_with_uinteger_param(NSUInteger n) { return 0; } + +int func_with_integer_param(NSInteger n) { return 0; } + +void calling_funct_with_pointer() { + NSString* s = @"Dulma"; + func_with_uinteger_param(s); +} + +void calling_funct_with_pointer1() { + NSString* s = @"Dulma"; + func_with_integer_param(s); +} diff --git a/infer/tests/codetoanalyze/objc/linters/issues.exp b/infer/tests/codetoanalyze/objc/linters/issues.exp index 8444af331..708049141 100644 --- a/infer/tests/codetoanalyze/objc/linters/issues.exp +++ b/infer/tests/codetoanalyze/objc/linters/issues.exp @@ -5,7 +5,10 @@ codetoanalyze/objc/linters/assign_pointer.m, Linters_dummy_method, 38, ASSIGN_PO codetoanalyze/objc/linters/atomic_prop.m, A_bla, 98, DIRECT_ATOMIC_PROPERTY_ACCESS, [] codetoanalyze/objc/linters/atomic_prop.m, A_bla, 99, DIRECT_ATOMIC_PROPERTY_ACCESS, [] codetoanalyze/objc/linters/atomic_prop.m, A_readP, 77, DIRECT_ATOMIC_PROPERTY_ACCESS, [] +codetoanalyze/objc/linters/atomic_prop.m, A_readP, 77, POINTER_TO_INTEGRAL_IMPLICIT_CAST, [] +codetoanalyze/objc/linters/atomic_prop.m, A_readP, 78, POINTER_TO_INTEGRAL_IMPLICIT_CAST, [] codetoanalyze/objc/linters/atomic_prop.m, A_readQ, 86, DIRECT_ATOMIC_PROPERTY_ACCESS, [] +codetoanalyze/objc/linters/atomic_prop.m, A_readQ, 86, POINTER_TO_INTEGRAL_IMPLICIT_CAST, [] codetoanalyze/objc/linters/atomic_prop.m, A_writeQ:, 82, DIRECT_ATOMIC_PROPERTY_ACCESS, [] codetoanalyze/objc/linters/atomic_prop.m, __objc_anonymous_block_______1, 114, DIRECT_ATOMIC_PROPERTY_ACCESS, [] codetoanalyze/objc/linters/badpointer.m, bad1, 17, BAD_POINTER_COMPARISON, [] @@ -20,6 +23,8 @@ codetoanalyze/objc/linters/badpointer.m, bad6, 106, BAD_POINTER_COMPARISON, [] codetoanalyze/objc/linters/badpointer.m, bad7, 121, BAD_POINTER_COMPARISON, [] codetoanalyze/objc/linters/badpointer.m, bad8, 128, BAD_POINTER_COMPARISON, [] codetoanalyze/objc/linters/badpointer.m, bad9, 135, BAD_POINTER_COMPARISON, [] +codetoanalyze/objc/linters/implicit_cast.m, calling_funct_with_pointer, 17, POINTER_TO_INTEGRAL_IMPLICIT_CAST, [] +codetoanalyze/objc/linters/implicit_cast.m, calling_funct_with_pointer1, 22, POINTER_TO_INTEGRAL_IMPLICIT_CAST, [] codetoanalyze/objc/linters/nsnumber.m, bad1, 13, BAD_POINTER_COMPARISON, [] codetoanalyze/objc/linters/nsnumber.m, bad2, 18, BAD_POINTER_COMPARISON, [] codetoanalyze/objc/linters/nsnumber.m, bad3, 23, BAD_POINTER_COMPARISON, []