diff --git a/Makefile b/Makefile index bb374c7ba..a57a1abe0 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,7 @@ endif ifneq ($(XCODE_SELECT),no) BUILD_SYSTEMS_TESTS += xcodebuild_no_xcpretty objc_getters_setters objc_missing_fld DIRECT_TESTS += \ - objc_frontend objc_errors objc_linters objc_ioslints objcpp_errors \ + objc_frontend objc_errors objc_linters objc_ioslints objcpp_errors objcpp_nullable \ objcpp_frontend objcpp_linters objc_linters-for-test-only objcpp_linters-for-test-only \ objc_linters-def-folder objc_nullable objc_liveness objcpp_liveness objc_uninit ifneq ($(XCPRETTY),no) diff --git a/infer/src/checkers/NullabilityCheck.ml b/infer/src/checkers/NullabilityCheck.ml index 55534b433..a0fb59fda 100644 --- a/infer/src/checkers/NullabilityCheck.ml +++ b/infer/src/checkers/NullabilityCheck.ml @@ -59,22 +59,15 @@ module TransferFunctions (CFG : ProcCfg.S) = struct List.exists ~f:(String.equal simplified_callee_pname) blacklist - let is_objc_container_add_method : Typ.Procname.t -> bool = - let method_prefixes = - [ "addObject:" - ; "arrayByAddingObject:" - ; "arrayWithObjects:" - ; "dictionaryWithObjects:" - ; "dictionaryWithObjectsAndKeys:" - ; "initWithObjectsAndKeys:" - ; "insertObject:" - ; "setObject:" ] - in - fun proc_name -> - let simplified_callee_pname = Typ.Procname.to_simplified_string proc_name in - List.exists - ~f:(fun prefix -> String.is_prefix ~prefix simplified_callee_pname) - method_prefixes + let container_method_regex = + Str.regexp @@ "^\\(NS.*_\\(arrayByAddingObject\\|arrayWithObjects\\|" + ^ "dictionaryWithObjects\\|dictionaryWithObjectsAndKeys\\|initWithObjectsAndKeys\\|" + ^ "addObject\\|insertObject\\|setObject\\):\\|" ^ "std::basic_string\\).*" + + + let is_objc_container_add_method proc_name = + let callee_pname = Typ.Procname.to_string proc_name in + Str.string_match container_method_regex callee_pname 0 let is_conflicting_report summary report_location = @@ -273,11 +266,11 @@ module TransferFunctions (CFG : ProcCfg.S) = struct Annotations.ia_is_nullable -> let call_site = CallSite.make callee_pname loc in add_nullable_ap (ret_var, []) (CallSites.singleton call_site) astate + | Call (_, Direct callee_pname, args, _, loc) when is_objc_container_add_method callee_pname -> + check_nil_in_objc_container proc_data loc args astate | Call (_, Direct callee_pname, HilExp.AccessExpression receiver :: _, _, loc) when is_non_objc_instance_method callee_pname -> check_ap proc_data loc (AccessExpression.to_access_path receiver) astate - | Call (_, Direct callee_pname, args, _, loc) when is_objc_container_add_method callee_pname -> - check_nil_in_objc_container proc_data loc args astate | Call ( ((_, ret_typ) as ret_var) , Direct callee_pname diff --git a/infer/tests/codetoanalyze/objcpp/nullable/Examples.mm b/infer/tests/codetoanalyze/objcpp/nullable/Examples.mm new file mode 100644 index 000000000..8d3eb7500 --- /dev/null +++ b/infer/tests/codetoanalyze/objcpp/nullable/Examples.mm @@ -0,0 +1,22 @@ +/* + * 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 +#import + +std::string stdStringOK(NSString* s) { + const char* s1 = [s UTF8String]; + if (s1) { + std::string s2 = std::string([s UTF8String]); + return s2; + } else + return ""; +} + +std::string stdStringBad(NSString* s) { + std::string s2 = std::string([s UTF8String]); + return s2; +} diff --git a/infer/tests/codetoanalyze/objcpp/nullable/Makefile b/infer/tests/codetoanalyze/objcpp/nullable/Makefile new file mode 100644 index 000000000..5bd27238f --- /dev/null +++ b/infer/tests/codetoanalyze/objcpp/nullable/Makefile @@ -0,0 +1,17 @@ +# Copyright (c) 2017-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. + +TESTS_DIR = ../../.. + +ANALYZER = checkers +CLANG_OPTIONS = -c +INFER_OPTIONS = --debug-exceptions --no-default-checkers --suggest-nullable --check-nullable --project-root $(TESTS_DIR) +INFERPRINT_OPTIONS = --issues-tests + +SOURCES = $(wildcard *.mm) + +include $(TESTS_DIR)/clang.make + +infer-out/report.json: $(MAKEFILE_LIST) diff --git a/infer/tests/codetoanalyze/objcpp/nullable/issues.exp b/infer/tests/codetoanalyze/objcpp/nullable/issues.exp new file mode 100644 index 000000000..f46767d0f --- /dev/null +++ b/infer/tests/codetoanalyze/objcpp/nullable/issues.exp @@ -0,0 +1 @@ +codetoanalyze/objcpp/nullable/Examples.mm, stdStringBad, 1, NULLABLE_DEREFERENCE, no_bucket, ERROR, [dereferencing the return of UTF8String,assignment of the nullable value,definition of UTF8String]