From 6bcf4203c3c9740a3df02e974b51f0a97ea68ecf Mon Sep 17 00:00:00 2001 From: Daiva Naudziuniene Date: Fri, 14 May 2021 04:53:24 -0700 Subject: [PATCH] [pulse][objc][nullptr] Model NSDictionary methods to catch nil insertion issues Summary: `dictionaryWithObjectsForKeysCount` is a bit more complicated as we need to know if an element of an array is nil. Leaving it for later. Reviewed By: skcho Differential Revision: D28413859 fbshipit-source-id: 7b5116de8 --- infer/src/pulse/PulseModels.ml | 7 +++ .../codetoanalyze/objcpp/pulse/NPEBasic.mm | 52 +++++++++++++++++++ .../codetoanalyze/objcpp/pulse/issues.exp | 3 ++ 3 files changed, 62 insertions(+) diff --git a/infer/src/pulse/PulseModels.ml b/infer/src/pulse/PulseModels.ml index ba4785a6b..686586e6c 100644 --- a/infer/src/pulse/PulseModels.ml +++ b/infer/src/pulse/PulseModels.ml @@ -1791,6 +1791,13 @@ module ProcNameDispatcher = struct $+ capt_arg_payload $--> ObjC.insertion_into_collection_key_and_value ~desc:"NSMutableArray.replaceObjectsAtIndexes:withObjects:" + ; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSDictionary") + &:: "dictionaryWithObject:forKey:" <>$ capt_arg_payload $+ capt_arg_payload + $--> ObjC.insertion_into_collection_key_and_value + ~desc:"NSDictionary.dictionaryWithObject:forKey:" + ; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSDictionary") + &:: "sharedKeySetForKeys:" <>$ capt_arg_payload + $--> ObjC.insertion_into_collection_key_or_value ~desc:"NSDictionary.sharedKeySetForKeys" ; +match_regexp_opt Config.pulse_model_return_nonnull &::.*--> Misc.return_positive ~desc:"modelled as returning not null due to configuration option" diff --git a/infer/tests/codetoanalyze/objcpp/pulse/NPEBasic.mm b/infer/tests/codetoanalyze/objcpp/pulse/NPEBasic.mm index cd08ba049..41b3b3658 100644 --- a/infer/tests/codetoanalyze/objcpp/pulse/NPEBasic.mm +++ b/infer/tests/codetoanalyze/objcpp/pulse/NPEBasic.mm @@ -337,3 +337,55 @@ void dictionaryLiteralOk() { dictionaryLiteral(@"key", @"obj"); } void dictionaryLiteralKeyNilBad() { dictionaryLiteral(nil, @"obj"); } void dictionaryLiteralObjectNilBad() { dictionaryLiteral(@"key", nil); } + +void dictionaryWithObjectsForKeysCount(id key, id object) { + NSString* values[1]; + values[0] = object; + + NSString* keys[1]; + keys[0] = key; + + NSDictionary* dict = [NSDictionary dictionaryWithObjects:values + forKeys:keys + count:1]; +} + +void dictionaryWithObjectsForKeysCountOk() { + dictionaryWithObjectsForKeysCount(@"key", @"somestring"); +} + +void FN_dictionaryWithObjectsForKeysCountKeyNilBad() { + dictionaryWithObjectsForKeysCount(nil, @"somestring"); +} + +void FN_dictionaryWithObjectsForKeysCountObjectNilBad() { + dictionaryWithObjectsForKeysCount(@"key", nil); +} + +void dictionaryWithObjectForKey(id key, id object) { + NSDictionary* dict = [NSDictionary dictionaryWithObject:object forKey:key]; +} + +void dictionaryWithObjectForKeyOk() { + dictionaryWithObjectForKey(@"key", @"somestring"); +} + +void dictionaryWithObjectForKeyNilBad() { + dictionaryWithObjectForKey(nil, @"somestring"); +} + +void dictionaryWithNilObjectForKeyBad() { + dictionaryWithObjectForKey(@"key", nil); +} + +void dictionaryWithSharedKeySetForKeys(id keys) { + id sharedKeySet = [NSDictionary sharedKeySetForKeys:keys]; +} + +void dictionaryWithSharedKeySetForKeysOk() { + dictionaryWithSharedKeySetForKeys(@[ @"key1", @"key2" ]); +} + +void dictionaryWithSharedKeySetForKeysBad() { + dictionaryWithSharedKeySetForKeys(nil); +} diff --git a/infer/tests/codetoanalyze/objcpp/pulse/issues.exp b/infer/tests/codetoanalyze/objcpp/pulse/issues.exp index cc8fa0f38..6fcacb602 100644 --- a/infer/tests/codetoanalyze/objcpp/pulse/issues.exp +++ b/infer/tests/codetoanalyze/objcpp/pulse/issues.exp @@ -8,7 +8,10 @@ codetoanalyze/objcpp/pulse/NPEBasic.mm, addObjectKeyNilInDictBad, 2, NIL_INSERTI codetoanalyze/objcpp/pulse/NPEBasic.mm, dereferenceNilBad, 2, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,assigned,invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, dictionaryLiteralKeyNilBad, 0, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,when calling `dictionaryLiteral` here,parameter `key` of dictionaryLiteral,invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, dictionaryLiteralObjectNilBad, 0, NULLPTR_DEREFERENCE, no_bucket, ERROR, [is the null pointer,when calling `dictionaryLiteral` here,parameter `object` of dictionaryLiteral,invalid access occurs here] +codetoanalyze/objcpp/pulse/NPEBasic.mm, dictionaryWithNilObjectForKeyBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,when calling `dictionaryWithObjectForKey` here,parameter `object` of dictionaryWithObjectForKey,in call to `NSDictionary.dictionaryWithObject:forKey:` (modelled),invalid access occurs here] +codetoanalyze/objcpp/pulse/NPEBasic.mm, dictionaryWithObjectForKeyNilBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,when calling `dictionaryWithObjectForKey` here,parameter `key` of dictionaryWithObjectForKey,in call to `NSDictionary.dictionaryWithObject:forKey:` (modelled),invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, dictionaryWithSharedKeySetBad, 2, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,in call to `NSMutableDictionary.dictionaryWithSharedKeySet` (modelled),invalid access occurs here] +codetoanalyze/objcpp/pulse/NPEBasic.mm, dictionaryWithSharedKeySetForKeysBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,when calling `dictionaryWithSharedKeySetForKeys` here,parameter `keys` of dictionaryWithSharedKeySetForKeys,in call to `NSDictionary.sharedKeySetForKeys` (modelled),invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, insertNilInArrayBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,in call to `NSMutableArray.insertObject:atIndex:` (modelled),invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, removeObjectFromDictKeyNilBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,when calling `removeObjectFromDict` here,parameter `key` of removeObjectFromDict,in call to `NSMutableDictionary.removeObjectForKey` (modelled),invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, removeObjectFromMSetBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,when calling `removeObjectFromMSet` here,parameter `object` of removeObjectFromMSet,in call to `NSMutableSet.removeObject:` (modelled),invalid access occurs here]