diff --git a/infer/models/objc/src/NSArray.m b/infer/models/objc/src/NSArray.m index 2b157ec36..b900151d0 100644 --- a/infer/models/objc/src/NSArray.m +++ b/infer/models/objc/src/NSArray.m @@ -9,7 +9,13 @@ #import "NSArray.h" -@implementation NSArray +void __infer_assume(bool cond); + +@implementation NSArray { + + @private + id elementData[10]; +} - (NSArray*)arrayByAddingObject:(id)anObject { id a = ((NSObject*)anObject)->isa; @@ -25,4 +31,18 @@ return [NSArray alloc]; } +- (id)objectAtIndexedSubscript:(NSUInteger)idx { + id obj = elementData[idx]; + __infer_assume(obj != nil); + return obj; +} + +- (int)count { + if (self == nil) { + return 0; + } else { + sizeof(elementData); + } +} + @end diff --git a/infer/src/clang/cField_decl.ml b/infer/src/clang/cField_decl.ml index 137a85b8d..7aac306b7 100644 --- a/infer/src/clang/cField_decl.ml +++ b/infer/src/clang/cField_decl.ml @@ -88,7 +88,9 @@ let add_missing_fields tenv class_name ck missing_fields = Logging.out_debug " Updating info for class '%s' in tenv\n" class_name | _ -> () -let modelled_fields_in_classes = [("NSData", "_bytes", Typ.Tptr (Typ.Tvoid, Typ.Pk_pointer))] +let modelled_fields_in_classes = + [("NSData", "_bytes", Typ.Tptr (Typ.Tvoid, Typ.Pk_pointer)); + ("NSArray", "elementData", Typ.Tint Typ.IInt)] let modelled_field class_name_info = let modelled_field_in_class res (class_name, field_name, typ) = diff --git a/infer/tests/codetoanalyze/objc/errors/Makefile b/infer/tests/codetoanalyze/objc/errors/Makefile index 2a5bc920d..a61b21356 100644 --- a/infer/tests/codetoanalyze/objc/errors/Makefile +++ b/infer/tests/codetoanalyze/objc/errors/Makefile @@ -33,6 +33,7 @@ SOURCES_DEFAULT = \ npe/block.m \ npe/skip_method_with_nil_object.m \ npe/Nsstring_length_no_npe.m \ + npe/No_null_from_array.m \ procdescs/MethodCall.m \ property/main.c \ resource_leaks/ResourceLeakExample.m \ diff --git a/infer/tests/codetoanalyze/objc/errors/issues.exp b/infer/tests/codetoanalyze/objc/errors/issues.exp index 4b938543e..58e0536b5 100644 --- a/infer/tests/codetoanalyze/objc/errors/issues.exp +++ b/infer/tests/codetoanalyze/objc/errors/issues.exp @@ -4,6 +4,7 @@ codetoanalyze/objc/errors/initialization/compound_literal.c, init_with_compound_ codetoanalyze/objc/errors/memory_leaks_benchmark/CADisplayLinkRetainCycle.m, testCycle, 3, RETAIN_CYCLE, [start of procedure testCycle(),start of procedure init,return from a call to CADisplay_init] codetoanalyze/objc/errors/memory_leaks_benchmark/RetainCycleStaticVar.m, RetainCSVycleStaticVar, 2, RETAIN_CYCLE, [start of procedure RetainCSVycleStaticVar(),start of procedure init,return from a call to RetainCSV_init,start of procedure foo,start of procedure block,start of procedure init,return from a call to RetainCSV_init,return from a call to __objc_anonymous_block_RetainCSV_foo______3,start of procedure block,start of procedure init,return from a call to RetainCSV_init,return from a call to __objc_anonymous_block_RetainCSV_foo______2,return from a call to RetainCSV_foo] codetoanalyze/objc/errors/npe/blockenum.m, BlockEnumA_allResultsList:, 1, MEMORY_LEAK, [start of procedure allResultsList:] +codetoanalyze/objc/errors/npe/blockenum.m, BlockEnumA_allResultsList:, 2, RETURN_VALUE_IGNORED, [start of procedure allResultsList:,Condition is true] codetoanalyze/objc/errors/npe/blockenum.m, BlockEnumA_foo1:, 2, MEMORY_LEAK, [start of procedure foo1:] codetoanalyze/objc/errors/npe/nil_param.m, NilParamMain, 4, MEMORY_LEAK, [start of procedure NilParamMain(),start of procedure test1:,Message test2 with receiver nil returns nil.,return from a call to NilParamA_test1:] codetoanalyze/objc/errors/npe/null_returned_by_method.m, NullReturnedByMethodA_test1, 1, NULL_DEREFERENCE, [start of procedure test1,start of procedure test,return from a call to NullReturnedByMethodA_test] @@ -95,6 +96,7 @@ codetoanalyze/objc/errors/npe/Fraction.m, test_virtual_call, 7, NULL_DEREFERENCE codetoanalyze/objc/errors/npe/NPD_core_foundation.m, NullDeref_createCloseCrossGlyphNoLeak:, 5, Assert_failure, [start of procedure createCloseCrossGlyphNoLeak:] codetoanalyze/objc/errors/npe/NPD_core_foundation.m, NullDeref_layoutSubviews, 4, Assert_failure, [start of procedure layoutSubviews] codetoanalyze/objc/errors/npe/NPD_core_foundation.m, NullDeref_measureFrameSizeForTextNoLeak, 4, Assert_failure, [start of procedure measureFrameSizeForTextNoLeak,Condition is true] +codetoanalyze/objc/errors/npe/No_null_from_array.m, No_null_from_array_collectAvailableMaps, 5, RETURN_VALUE_IGNORED, [start of procedure collectAvailableMaps] codetoanalyze/objc/errors/npe/Npe_with_equal_names.m, EqualNamesTest, 3, NULL_DEREFERENCE, [start of procedure EqualNamesTest(),start of procedure meth,return from a call to EqualNamesA_meth] codetoanalyze/objc/errors/npe/Npe_with_equal_names.m, EqualNamesTest2, 2, UNINITIALIZED_VALUE, [start of procedure EqualNamesTest2(),start of procedure meth,return from a call to EqualNamesA_meth] codetoanalyze/objc/errors/npe/block.m, BlockA_doSomethingThenCallback:, 2, PARAMETER_NOT_NULL_CHECKED, [start of procedure doSomethingThenCallback:] @@ -109,6 +111,7 @@ codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie2, 5, TAINTED_VALUE_R codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie3, 5, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure testNSHTTPCookie3()] codetoanalyze/objc/errors/taint/sources.m, testNSHTTPCookie4, 5, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure testNSHTTPCookie4()] codetoanalyze/objc/errors/taint/viewController.m, ExampleDelegate_application:openURL:sourceApplication:annotation:, 7, TAINTED_VALUE_REACHING_SENSITIVE_FUNCTION, [start of procedure application:openURL:sourceApplication:annotation:,start of procedure init,return from a call to VCA_init,start of procedure ExampleSanitizer(),Condition is false,return from a call to ExampleSanitizer,Condition is false,Condition is true] +codetoanalyze/objc/shared/block/block-it.m, MyBlock_array, 3, RETURN_VALUE_IGNORED, [start of procedure array,Condition is true] codetoanalyze/objc/shared/block/block-it.m, __objc_anonymous_block_MyBlock_array______1, 5, UNINITIALIZED_VALUE, [start of procedure block,Condition is false] codetoanalyze/objc/shared/block/block-it.m, __objc_anonymous_block_MyBlock_array_trans______2, 4, UNINITIALIZED_VALUE, [start of procedure block,Condition is false] codetoanalyze/objc/shared/block/dispatch.m, DispatchA_dispatch_a_block_variable_from_macro_delivers_initialised_object, 3, DIVIDE_BY_ZERO, [start of procedure dispatch_a_block_variable_from_macro_delivers_initialised_object,start of procedure dispatch_a_block_variable_from_macro,start of procedure block,start of procedure init,return from a call to DispatchA_init,return from a call to __objc_anonymous_block_DispatchA_dispatch_a_block_variable_from_macro______4,return from a call to DispatchA_dispatch_a_block_variable_from_macro] diff --git a/infer/tests/codetoanalyze/objc/errors/npe/No_null_from_array.m b/infer/tests/codetoanalyze/objc/errors/npe/No_null_from_array.m new file mode 100644 index 000000000..26cbb38d1 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/errors/npe/No_null_from_array.m @@ -0,0 +1,19 @@ +#import + +@interface No_null_from_array : NSObject +@end + +@implementation No_null_from_array { + NSDictionary* _maps; +} + +- (void)collectAvailableMaps { + NSMutableDictionary* maps = [NSMutableDictionary dictionaryWithCapacity:100]; + NSString* filename = @""; + NSArray* components = [filename componentsSeparatedByString:@"-"]; + NSString* locale = components[0]; + NSMutableDictionary* mapsForLocale = maps[locale]; + maps[locale] = @""; +} + +@end