diff --git a/Makefile b/Makefile index 749db0eef..5a8482b9b 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 \ + objc_frontend objc_errors objc_linters objc_ioslints objcpp_errors \ 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/models/Makefile b/infer/models/Makefile index ceb03ffa3..df011e1c8 100644 --- a/infer/models/Makefile +++ b/infer/models/Makefile @@ -10,6 +10,7 @@ C_MODELS_DIR = c/src CPP_MODELS_DIR = cpp/src JAVA_MODELS_DIR = java OBJC_MODELS_DIR = objc/src +OBJCPP_MODELS_DIR = objcpp/src MODELS_INFER_OUT = infer-out MODELS_INFER_OPTIONS = --biabduction-only --results-dir $(MODELS_INFER_OUT) --models-mode @@ -33,12 +34,15 @@ ifeq ($(BUILD_C_ANALYZERS),yes) $(QUIET)$(MAKE) -C $(CPP_MODELS_DIR) clean ifneq (no, $(XCODE_SELECT)) $(QUIET)$(MAKE) -C $(OBJC_MODELS_DIR) clean + $(QUIET)$(MAKE) -C $(OBJCPP_MODELS_DIR) clean endif $(QUIET)$(call silent_on_success,Capturing C models,\ $(INFER_BIN) capture $(MODELS_INFER_OPTIONS) --continue -- $(MAKE) -C $(C_MODELS_DIR) all) $(QUIET)$(call silent_on_success,Capturing C++ models,\ $(INFER_BIN) capture $(MODELS_INFER_OPTIONS) --continue -- $(MAKE) -C $(CPP_MODELS_DIR) all) ifneq (no, $(XCODE_SELECT)) + $(QUIET)$(call silent_on_success,Capturing ObjCPP models,\ + $(INFER_BIN) capture $(MODELS_INFER_OPTIONS) --continue -- $(MAKE) -C $(OBJCPP_MODELS_DIR) all) $(QUIET)$(call silent_on_success,Capturing ObjC models,\ $(INFER_BIN) capture $(MODELS_INFER_OPTIONS) --continue -- $(MAKE) -C $(OBJC_MODELS_DIR) all) endif @@ -66,4 +70,5 @@ clean: clean_specs $(QUIET)$(MAKE) -C $(CPP_MODELS_DIR) clean ifneq (no, $(XCODE_SELECT)) $(QUIET)$(MAKE) -C $(OBJC_MODELS_DIR) clean + $(QUIET)$(MAKE) -C $(OBJCPP_MODELS_DIR) clean endif diff --git a/infer/models/objc/src/CoreFoundation.c b/infer/models/objc/src/CoreFoundation.c index f45fb1829..b4062bf7b 100644 --- a/infer/models/objc/src/CoreFoundation.c +++ b/infer/models/objc/src/CoreFoundation.c @@ -6,8 +6,12 @@ */ #import +void __free_cf(CFTypeRef item); + void CFRelease(CFTypeRef item) { __free_cf(item); } +CFRunLoopObserverRef getAngelicObject(); + CFRunLoopObserverRef CFRunLoopObserverCreateWithHandler( CFAllocatorRef allocator, CFOptionFlags activities, diff --git a/infer/models/objc/src/CoreVideo.c b/infer/models/objc/src/CoreVideo.c index cf877b890..29b8f498c 100644 --- a/infer/models/objc/src/CoreVideo.c +++ b/infer/models/objc/src/CoreVideo.c @@ -7,4 +7,6 @@ #import #import +void __free_cf(CVPixelBufferRef item); + void CVPixelBufferRelease(CVPixelBufferRef pxbuffer) { __free_cf(pxbuffer); } diff --git a/infer/models/objc/src/Dispatch.m b/infer/models/objc/src/Dispatch.m index 163999993..ac7f5fd5a 100644 --- a/infer/models/objc/src/Dispatch.m +++ b/infer/models/objc/src/Dispatch.m @@ -21,24 +21,10 @@ void dispatch_group_async(dispatch_group_t group, block(); } -long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout) { - block(); -} - void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block) { block(); } -void dispatch_source_set_cancel_handler(dispatch_source_t source, - dispatch_block_t handler) { - block(); -} - -void dispatch_source_set_event_handler(dispatch_source_t source, - dispatch_block_t handler) { - block(); -} - void dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block) { diff --git a/infer/models/objc/src/Makefile b/infer/models/objc/src/Makefile index 542b88ee7..5f70aa26b 100644 --- a/infer/models/objc/src/Makefile +++ b/infer/models/objc/src/Makefile @@ -13,7 +13,7 @@ OBJECTS=$(M_SOURCES:.m=.o) $(C_SOURCES:.c=.o) CC=clang XCODE_PATH=$(shell $(XCODE_SELECT) -p) IPHONE_SIMULATOR_PATH=$(XCODE_PATH)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk -CFLAGS += --target=x86_64-apple-darwin14 -x objective-c -c -mios-simulator-version-min=8.2 -isysroot $(IPHONE_SIMULATOR_PATH) +CFLAGS += -Wno-deprecated-objc-isa-usage --target=x86_64-apple-darwin14 -x objective-c -c -mios-simulator-version-min=8.2 -isysroot $(IPHONE_SIMULATOR_PATH) all: $(OBJECTS) diff --git a/infer/models/objc/src/NSData.m b/infer/models/objc/src/NSData.m index c97e601db..65c9add29 100644 --- a/infer/models/objc/src/NSData.m +++ b/infer/models/objc/src/NSData.m @@ -51,6 +51,6 @@ NSData* __objc_alloc(NSData*); - (void)dealloc { if (self) - free(self->_bytes); + free((void*)self->_bytes); } @end diff --git a/infer/models/objc/src/NSString.m b/infer/models/objc/src/NSString.m index 34adf7e96..3b0b0dcea 100644 --- a/infer/models/objc/src/NSString.m +++ b/infer/models/objc/src/NSString.m @@ -7,6 +7,7 @@ #import "NSString.h" #import +#import size_t __get_array_length(const void* arr); @@ -25,7 +26,7 @@ typedef NSUInteger NSStringEncoding; s->value = (const char*)malloc(len); // The newly allocated string will be autoreleased by the runtime __set_wont_leak_attribute(s->value); - memcpy(s->value, bytes, len); + memcpy((void*)s->value, bytes, len); return s; } @@ -36,7 +37,7 @@ typedef NSUInteger NSStringEncoding; s->value = (const char*)malloc(len); // The newly allocated string will be autoreleased by the runtime __set_wont_leak_attribute(s->value); - memcpy(s->value, aString->value, len); + memcpy((void*)s->value, aString->value, len); return s; } @@ -83,7 +84,7 @@ typedef NSUInteger NSStringEncoding; - (void)dealloc { if (self != nil && self->value != 0) { - free(self->value); + free((void*)self->value); } [super dealloc]; } diff --git a/infer/models/objcpp/src/Makefile b/infer/models/objcpp/src/Makefile new file mode 100644 index 000000000..fefb9a171 --- /dev/null +++ b/infer/models/objcpp/src/Makefile @@ -0,0 +1,33 @@ +# 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. + +MODELS_DIR = ../.. +include $(MODELS_DIR)/models-config.make + +MM_SOURCES=$(wildcard *.mm) +M_SOURCES=$(shell find -L . -name "*.m") +C_SOURCES=$(shell find -L . -name "*.c") +OBJECTS=$(patsubst %.m,%_cxx.o, $(M_SOURCES)) $(patsubst %.c,%_cxx.o, $(C_SOURCES)) $(patsubst %.mm,%.o, $(MM_SOURCES)) +# let infer override CC by letting the shell resolve its location according to PATH +CXX=clang++ +XCODE_PATH=$(shell $(XCODE_SELECT) -p) +IPHONE_SIMULATOR_PATH=$(XCODE_PATH)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk +CXXFLAGS += -Wno-deprecated-objc-isa-usage --target=x86_64-apple-darwin14 -x objective-c++ -c -mios-simulator-version-min=8.2 -isysroot $(IPHONE_SIMULATOR_PATH) + +all: $(OBJECTS) + +clean: + $(QUIET)rm -rf $(OBJECTS) + +%.o: %.mm + $(CXX) $(CXXFLAGS) $< -o $@ + +%_cxx.o: %.m + $(CXX) $(CXXFLAGS) $< -o $@ + +%_cxx.o: %.c + $(CXX) $(CXXFLAGS) $< -o $@ + +.PHONY: all clean diff --git a/infer/models/objcpp/src/objc_src b/infer/models/objcpp/src/objc_src new file mode 120000 index 000000000..3a162c128 --- /dev/null +++ b/infer/models/objcpp/src/objc_src @@ -0,0 +1 @@ +../../objc/src \ No newline at end of file diff --git a/infer/src/IR/Pvar.ml b/infer/src/IR/Pvar.ml index 63ab99412..30902d3dc 100644 --- a/infer/src/IR/Pvar.ml +++ b/infer/src/IR/Pvar.ml @@ -189,7 +189,9 @@ let to_callee pname pvar = {pvar with pv_kind= Callee_var pname} | Global_var _ -> pvar - | Callee_var _ | Abduced_retvar _ | Abduced_ref_param _ | Seed_var -> + | Callee_var _ -> + pvar + | Abduced_retvar _ | Abduced_ref_param _ | Seed_var -> L.d_str "Cannot convert pvar to callee: " ; d pvar ; L.d_ln () ; diff --git a/infer/src/biabduction/Tabulation.ml b/infer/src/biabduction/Tabulation.ml index 260bfd7fc..ebbf7a16c 100644 --- a/infer/src/biabduction/Tabulation.ml +++ b/infer/src/biabduction/Tabulation.ml @@ -160,7 +160,7 @@ let spec_find_rename trace_call summary let proc_name = Summary.get_proc_name summary in try let count = ref 0 in - let f spec = incr count ; (!count, spec_rename_vars proc_name spec) in + let rename_vars spec = incr count ; (!count, spec_rename_vars proc_name spec) in let specs = get_specs_from_payload summary in let formals = Summary.get_formals summary in if List.is_empty specs then ( @@ -169,7 +169,7 @@ let spec_find_rename trace_call summary (Exceptions.Precondition_not_found (Localise.verbatim_desc (Typ.Procname.to_string proc_name), __POS__)) ) ; let formal_parameters = List.map ~f:(fun (x, _) -> Pvar.mk_callee x proc_name) formals in - (List.map ~f specs, formal_parameters) + (List.map ~f:rename_vars specs, formal_parameters) with Caml.Not_found -> L.d_strln ("ERROR: found no entry for procedure " ^ Typ.Procname.to_string proc_name ^ ". Give up...") ; diff --git a/infer/tests/codetoanalyze/objc/errors/issues.exp b/infer/tests/codetoanalyze/objc/errors/issues.exp index b4f16f86c..ce034ab65 100644 --- a/infer/tests/codetoanalyze/objc/errors/issues.exp +++ b/infer/tests/codetoanalyze/objc/errors/issues.exp @@ -88,7 +88,7 @@ codetoanalyze/objc/errors/npe/dynamic_dispatch.m, objc_blockDynamicDispatchMain_ codetoanalyze/objc/errors/npe/ivar_blocks.m, MyClass_ivar_npe, 1, IVAR_NOT_NULL_CHECKED, B1, WARNING, [start of procedure ivar_npe] codetoanalyze/objc/errors/npe/skip_method_with_nil_object.m, SkipMethodNilA_testBug:, 6, PARAMETER_NOT_NULL_CHECKED, B2, WARNING, [start of procedure testBug:,Message get_a with receiver nil returns nil.,Message skip_method with receiver nil returns nil.,Taking false branch] codetoanalyze/objc/errors/property/main.c, property_main, 3, MEMORY_LEAK, no_bucket, ERROR, [start of procedure property_main(),Skipping aProperty: method has no implementation] -codetoanalyze/objc/errors/resource_leaks/Dispatch_sources.m, ProcessContentsOfFile, 35, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure ProcessContentsOfFile(),Taking false branch,Skipping dispatch_get_global_queue(): method has no implementation,Skipping dispatch_source_create(): method has no implementation,Taking false branch] +codetoanalyze/objc/errors/resource_leaks/Dispatch_sources.m, ProcessContentsOfFile, 35, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure ProcessContentsOfFile(),Taking false branch,Skipping dispatch_get_global_queue(): method has no implementation,Skipping dispatch_source_create(): method has no implementation,Taking false branch,Skipping dispatch_source_set_event_handler(): method has no implementation,Skipping dispatch_source_set_cancel_handler(): method has no implementation] codetoanalyze/objc/errors/resource_leaks/Dispatch_sources.m, objc_blockProcessContentsOfFile_2, 6, MEMORY_LEAK, no_bucket, ERROR, [start of procedure block,Skipping dispatch_source_get_data(): method has no implementation,Taking true branch,Skipping MyProcessFileData(): method has no implementation] codetoanalyze/objc/errors/resource_leaks/ResourceLeakExample.m, NSFileHandle_fileHandleForLoggingAtPath:mode:, 9, RESOURCE_LEAK, no_bucket, ERROR, [start of procedure fileHandleForLoggingAtPath:mode:,Taking true branch,Skipping fileSystemRepresentation: method has no implementation,Taking false branch,Taking true branch,Skipping autorelease: no implementation found for method declared in Objective-C protocol] codetoanalyze/objc/shared/annotations/nonnull_annotations.m, A_test1:, 2, PARAMETER_NOT_NULL_CHECKED, B2, WARNING, [start of procedure test1:,Message child with receiver nil returns nil.] diff --git a/infer/tests/codetoanalyze/objcpp/errors/Makefile b/infer/tests/codetoanalyze/objcpp/errors/Makefile index bcb5de791..5fee7141b 100644 --- a/infer/tests/codetoanalyze/objcpp/errors/Makefile +++ b/infer/tests/codetoanalyze/objcpp/errors/Makefile @@ -7,10 +7,9 @@ TESTS_DIR = ../../.. ANALYZER = checkers CLANG_OPTIONS = -x objective-c++ -std=c++11 -fobjc-arc -c -INFER_OPTIONS = --biabduction-only --no-filtering --debug-exceptions --project-root $(TESTS_DIR) +INFER_OPTIONS = --biabduction-only --no-filtering --debug-exceptions --project-root $(TESTS_DIR) INFERPRINT_OPTIONS = --issues-tests -SOURCES = \ - $(wildcard */*.mm) \ +SOURCES = $(wildcard *.mm) $(wildcard */*.mm) include $(TESTS_DIR)/clang.make diff --git a/infer/tests/codetoanalyze/objcpp/errors/c_functions.mm b/infer/tests/codetoanalyze/objcpp/errors/c_functions.mm new file mode 100644 index 000000000..8383ce361 --- /dev/null +++ b/infer/tests/codetoanalyze/objcpp/errors/c_functions.mm @@ -0,0 +1,45 @@ +/* + * 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 +@property(strong) void (^block)(void); +@end + +@implementation A + ++ (instancetype)autoUpdating { + static A* a; + dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + a = [self alloc]; + a.block = ^{ + }; + }); + return a; +} + +static void dispatch_once2(dispatch_once_t* predicate, dispatch_block_t block); ++ (instancetype)autoUpdating2 { + static A* a; + dispatch_once_t onceToken; + dispatch_once2(&onceToken, ^{ + a = [self alloc]; + a.block = ^{ + }; + }); + return a; +} + +@end + +int main() { + A* a = [A autoUpdating]; + A* a2 = [A autoUpdating2]; + a.block(); + a2.block(); // NPE here since dispatch_once2 is skipped +} diff --git a/infer/tests/codetoanalyze/objcpp/errors/issues.exp b/infer/tests/codetoanalyze/objcpp/errors/issues.exp index 888a96021..a20f8522f 100644 --- a/infer/tests/codetoanalyze/objcpp/errors/issues.exp +++ b/infer/tests/codetoanalyze/objcpp/errors/issues.exp @@ -1 +1,2 @@ -codetoanalyze/objcpp/errors/retain_cycles/RetainCycleWithStruct.mm, main_bad, 2, RETAIN_CYCLE, [start of procedure main_bad(),start of procedure tracer,start of procedure _State,return from a call to _State__State,start of procedure initWithAnimation:,Condition is true,return from a call to Tracer_initWithAnimation:,return from a call to Animation_tracer] +codetoanalyze/objcpp/errors/c_functions.mm, main, 4, NULL_DEREFERENCE, B5, ERROR, [start of procedure main(),start of procedure autoUpdating,return from a call to A_autoUpdating,start of procedure autoUpdating2,Skipping dispatch_once2(): method has no implementation,return from a call to A_autoUpdating2,Executing synthesized getter block,start of procedure block,return from a call to objc_blockobjc_blockA_autoUpdating_1_2,Message block with receiver nil returns nil.] +codetoanalyze/objcpp/errors/retain_cycles/RetainCycleWithStruct.mm, Animation_tracer, 2, RETAIN_CYCLE, no_bucket, ERROR, [start of procedure tracer,start of procedure _State,return from a call to _State__State,start of procedure initWithAnimation:,Taking true branch,return from a call to Tracer_initWithAnimation:]