From 6278dc72008e911dd4facf35440480bf2ea4b0f6 Mon Sep 17 00:00:00 2001 From: Josh Berdine Date: Thu, 7 Apr 2016 09:59:04 -0700 Subject: [PATCH] Additional modeling of NS collections Summary:public Add modeling of methods that can raise exceptions when parameters are nil, and that return nil when passed nil. Reviewed By: dulmarod Differential Revision: D3101739 fb-gh-sync-id: 76af5a2 fbshipit-source-id: 76af5a2 --- infer/models/objc/src/NSArray.h | 2 + infer/models/objc/src/NSArray.m | 7 ++- infer/models/objc/src/NSDictionary.h | 6 +++ infer/models/objc/src/NSDictionary.m | 18 +++++++ infer/models/objc/src/NSMapTable.h | 16 ++++++ infer/models/objc/src/NSMapTable.m | 20 ++++++++ infer/models/objc/src/NSMutableArray.h | 7 +++ infer/models/objc/src/NSMutableArray.m | 23 ++++++--- infer/models/objc/src/NSMutableDictionary.h | 3 ++ infer/models/objc/src/NSMutableDictionary.m | 17 ++++--- .../objc/errors/npe/UpdateDict.m | 49 +++++++++++++++++++ .../endtoend/objc/UpdateDictNPETest.java | 5 +- 12 files changed, 159 insertions(+), 14 deletions(-) create mode 100644 infer/models/objc/src/NSMapTable.h create mode 100644 infer/models/objc/src/NSMapTable.m diff --git a/infer/models/objc/src/NSArray.h b/infer/models/objc/src/NSArray.h index af8038fe8..895b52c68 100644 --- a/infer/models/objc/src/NSArray.h +++ b/infer/models/objc/src/NSArray.h @@ -11,4 +11,6 @@ @interface NSArray : NSObject +- (NSArray*)arrayByAddingObject:(id)anObject; + @end diff --git a/infer/models/objc/src/NSArray.m b/infer/models/objc/src/NSArray.m index b36f3a03a..2b157ec36 100644 --- a/infer/models/objc/src/NSArray.m +++ b/infer/models/objc/src/NSArray.m @@ -11,12 +11,17 @@ @implementation NSArray +- (NSArray*)arrayByAddingObject:(id)anObject { + id a = ((NSObject*)anObject)->isa; + return [NSArray alloc]; +} + + (instancetype)array { return [NSArray alloc]; } + (instancetype)arrayWithObject:(char*)anObject { - char _ = *anObject; + id a = ((NSObject*)anObject)->isa; return [NSArray alloc]; } diff --git a/infer/models/objc/src/NSDictionary.h b/infer/models/objc/src/NSDictionary.h index ce82c7377..5a80b04d7 100644 --- a/infer/models/objc/src/NSDictionary.h +++ b/infer/models/objc/src/NSDictionary.h @@ -11,4 +11,10 @@ @interface NSDictionary : NSObject +- (id)objectForKey:(id)aKey; +- (id)objectForKeyedSubscript:(id)key; + ++ (instancetype)dictionary; ++ (instancetype)dictionaryWithObject:(id)object forKey:(id)key; + @end diff --git a/infer/models/objc/src/NSDictionary.m b/infer/models/objc/src/NSDictionary.m index f98cb5f61..8f310a44a 100644 --- a/infer/models/objc/src/NSDictionary.m +++ b/infer/models/objc/src/NSDictionary.m @@ -15,8 +15,26 @@ @implementation NSDictionary +- (id)objectForKey:(id)aKey { + if (aKey == NULL) + return NULL; + return [NSObject alloc]; +} + +- (id)objectForKeyedSubscript:(id)aKey { + if (aKey == NULL) + return NULL; + return [NSObject alloc]; +} + + (instancetype)dictionary { return [NSDictionary alloc]; } ++ (instancetype)dictionaryWithObject:(id)object forKey:(id)key { + id a = ((NSObject*)object)->isa; + id b = ((NSObject*)key)->isa; + return [NSDictionary alloc]; +} + @end diff --git a/infer/models/objc/src/NSMapTable.h b/infer/models/objc/src/NSMapTable.h new file mode 100644 index 000000000..48f2a5766 --- /dev/null +++ b/infer/models/objc/src/NSMapTable.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2016 - 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 + +@interface NSMapTable : NSObject + +- (id)objectForKey:(id)aKey; + +@end diff --git a/infer/models/objc/src/NSMapTable.m b/infer/models/objc/src/NSMapTable.m new file mode 100644 index 000000000..a0ba1a499 --- /dev/null +++ b/infer/models/objc/src/NSMapTable.m @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2016 - 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 "NSMapTable.h" + +@implementation NSMapTable + +- (id)objectForKey:(id)aKey { + if (aKey == NULL) + return NULL; + return [NSObject alloc]; +} + +@end diff --git a/infer/models/objc/src/NSMutableArray.h b/infer/models/objc/src/NSMutableArray.h index 2353aec26..cc3543aec 100644 --- a/infer/models/objc/src/NSMutableArray.h +++ b/infer/models/objc/src/NSMutableArray.h @@ -9,6 +9,13 @@ #import +@class NSIndexSet; + @interface NSMutableArray : NSObject +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject; +- (void)removeObjectsAtIndexes:(NSIndexSet*)indexes; +- (void)replaceObjectsAtIndexes:(NSIndexSet*)indexes + withObjects:(NSArray*)objects; + @end diff --git a/infer/models/objc/src/NSMutableArray.m b/infer/models/objc/src/NSMutableArray.m index 11c8c880d..91ecea75a 100644 --- a/infer/models/objc/src/NSMutableArray.m +++ b/infer/models/objc/src/NSMutableArray.m @@ -15,19 +15,30 @@ @implementation NSMutableArray +- (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject { + id a = ((NSObject*)anObject)->isa; +} + +- (void)removeObjectsAtIndexes:(NSIndexSet*)indexes { + id a = ((NSObject*)indexes)->isa; +} + +- (void)replaceObjectsAtIndexes:(NSIndexSet*)indexes + withObjects:(NSArray*)objects { + id a = ((NSObject*)indexes)->isa; + id b = ((NSObject*)objects)->isa; +} + - (void)setObject:(id)anObject atIndexedSubscript:(NSUInteger)index { - NSObject* obj = (NSObject*)anObject; - id isa = obj->isa; + id a = ((NSObject*)anObject)->isa; } - (void)addObject:(id)anObject { - NSObject* obj = (NSObject*)anObject; - id isa = obj->isa; + id a = ((NSObject*)anObject)->isa; } - (void)insertObject:(id)anObject atIndex:(NSUInteger)index { - NSObject* obj = (NSObject*)anObject; - id isa = obj->isa; + id a = ((NSObject*)anObject)->isa; } + (instancetype)array { diff --git a/infer/models/objc/src/NSMutableDictionary.h b/infer/models/objc/src/NSMutableDictionary.h index 009e3523a..fe8b81343 100644 --- a/infer/models/objc/src/NSMutableDictionary.h +++ b/infer/models/objc/src/NSMutableDictionary.h @@ -11,4 +11,7 @@ @interface NSMutableDictionary : NSObject +- (void)removeObjectForKey:(id)aKey; ++ (NSMutableDictionary*)dictionaryWithSharedKeySet:(id)keyset; + @end diff --git a/infer/models/objc/src/NSMutableDictionary.m b/infer/models/objc/src/NSMutableDictionary.m index ac08b1e1d..537ca36b9 100644 --- a/infer/models/objc/src/NSMutableDictionary.m +++ b/infer/models/objc/src/NSMutableDictionary.m @@ -15,20 +15,25 @@ @implementation NSMutableDictionary +- (void)removeObjectForKey:(id)aKey { + id a = ((NSObject*)aKey)->isa; +} + - (void)setObject:(id)object forKeyedSubscript:(id)aKey { - NSObject* key = (NSObject*)aKey; - id isa2 = key->isa; + id a = ((NSObject*)aKey)->isa; } - (void)setObject:(id)anObject forKey:(id)aKey { - NSObject* obj = (NSObject*)anObject; - id isa = obj->isa; - NSObject* key = (NSObject*)aKey; - id isa2 = key->isa; + id a = ((NSObject*)anObject)->isa; + id b = ((NSObject*)aKey)->isa; } + (instancetype)dictionary { return [NSMutableDictionary alloc]; } ++ (NSMutableDictionary*)dictionaryWithSharedKeySet:(id)keyset { + id a = ((NSObject*)keyset)->isa; +} + @end diff --git a/infer/tests/codetoanalyze/objc/errors/npe/UpdateDict.m b/infer/tests/codetoanalyze/objc/errors/npe/UpdateDict.m index 2a0b51972..ef455d921 100644 --- a/infer/tests/codetoanalyze/objc/errors/npe/UpdateDict.m +++ b/infer/tests/codetoanalyze/objc/errors/npe/UpdateDict.m @@ -95,3 +95,52 @@ void no_npe_for_undef_values(NSDictionary* response) { NSMutableDictionary* d = [NSMutableDictionary dictionary]; d[@"fds"] = fileInfo; } + +void nullable_NSDictionary_objectForKey(NSDictionary* dict, NSObject* key) { + if (key != nil) { + // check objectForKey may return nil for non-nil key + if ([dict objectForKey:key] == nil) { + char _ = *(char*)nil; + } // report + } +} + +void strict_NSDictionary_objectForKey(NSDictionary* dict) { + // check objectForKey returns nil for nil key + if ([dict objectForKey:nil] != nil) { + char _ = *(char*)nil; + } // no report +} + +void nullable_NSDictionary_objectForKeyedSubscript(NSDictionary* dict, + NSObject* key) { + if (key != nil) { + // check objectForKey may return nil for non-nil key + if (dict[key] == nil) { + char _ = *(char*)nil; + } // report + } +} + +void strict_NSDictionary_objectForKeyedSubscript(NSDictionary* dict) { + // check objectForKey returns nil for nil key + if (dict[nil] != nil) { + char _ = *(char*)nil; + } // no report +} + +void nullable_NSMapTable_objectForKey(NSMapTable* map, NSObject* key) { + if (key != nil) { + // check objectForKey may return nil for non-nil key + if ([map objectForKey:key] == nil) { + char _ = *(char*)nil; + } // report + } +} + +void strict_NSMapTable_objectForKey(NSMapTable* map) { + // check objectForKey returns nil for nil key + if ([map objectForKey:nil] != nil) { + char _ = *(char*)nil; + } // no report +} diff --git a/infer/tests/endtoend/objc/UpdateDictNPETest.java b/infer/tests/endtoend/objc/UpdateDictNPETest.java index 436c3837b..69dc7514f 100644 --- a/infer/tests/endtoend/objc/UpdateDictNPETest.java +++ b/infer/tests/endtoend/objc/UpdateDictNPETest.java @@ -56,7 +56,10 @@ public class UpdateDictNPETest { "update_array_with_null", "add_nil_to_array", "insert_nil_in_array", - "add_nil_in_dict" + "add_nil_in_dict", + "nullable_NSDictionary_objectForKey", + "nullable_NSDictionary_objectForKeyedSubscript", + "nullable_NSMapTable_objectForKey" }; assertThat( "Results should contain null pointer dereference error",