diff --git a/infer/src/pulse/PulseModels.ml b/infer/src/pulse/PulseModels.ml index 177a31436..1bd2761b5 100644 --- a/infer/src/pulse/PulseModels.ml +++ b/infer/src/pulse/PulseModels.ml @@ -1777,6 +1777,15 @@ module ProcNameDispatcher = struct ; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSMutableSet") &:: "removeObject:" <>$ any_arg $+ capt_arg_payload $--> ObjC.insertion_into_collection_key_or_value ~desc:"NSMutableSet.removeObject:" + ; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSMutableArray") + &:: "removeObjectsAtIndexes:" <>$ any_arg $+ capt_arg_payload + $--> ObjC.insertion_into_collection_key_or_value + ~desc:"NSMutableArray.removeObjectsAtIndexes:" + ; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSMutableArray") + &:: "replaceObjectsAtIndexes:withObjects:" <>$ any_arg $+ capt_arg_payload + $+ capt_arg_payload + $--> ObjC.insertion_into_collection_key_and_value + ~desc:"NSMutableArray.replaceObjectsAtIndexes:withObjects:" ; +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 edd608c7d..cd08ba049 100644 --- a/infer/tests/codetoanalyze/objcpp/pulse/NPEBasic.mm +++ b/infer/tests/codetoanalyze/objcpp/pulse/NPEBasic.mm @@ -262,6 +262,40 @@ void replaceObjectInArrayOk(NSMutableArray* mArray) { [mArray replaceObjectAtIndex:0 withObject:[SomeObject new]]; } +void removeObjectsAtIndexesFromArray(NSMutableArray* mArray, id indexset) { + [mArray removeObjectsAtIndexes:indexset]; +} + +void removeObjectsAtIndexesFromArrayOK(NSMutableArray* mArray) { + NSIndexSet* indexset = [NSIndexSet indexSetWithIndex:1]; + removeObjectsAtIndexesFromArray(mArray, indexset); +} + +void removeObjectsAtIndexesFromArrayBad(NSMutableArray* mArray) { + removeObjectsAtIndexesFromArray(mArray, nil); +} + +void replaceObjectsAtIndexesWithObjectsInArray(NSMutableArray* mArray, + id indexset, + id objects) { + [mArray replaceObjectsAtIndexes:indexset withObjects:objects]; +} + +void replaceObjectsAtIndexesWithObjectsInArrayOk(NSMutableArray* mArray) { + NSIndexSet* indexset = [NSIndexSet indexSetWithIndex:0]; + replaceObjectsAtIndexesWithObjectsInArray( + mArray, indexset, @[ [SomeObject new] ]); +} + +void replaceObjectsAtNilIndexesWithObjectsInArrayBad(NSMutableArray* mArray) { + replaceObjectsAtIndexesWithObjectsInArray(mArray, nil, @[ [SomeObject new] ]); +} + +void replaceObjectsAtIndexesWithNilObjectsInArrayBad(NSMutableArray* mArray) { + NSIndexSet* indexset = [NSIndexSet indexSetWithIndex:0]; + replaceObjectsAtIndexesWithObjectsInArray(mArray, indexset, nil); +} + void addInDictBracketsDefault(NSMutableDictionary* mDict, NSString* key) { mDict[key] = @"default"; diff --git a/infer/tests/codetoanalyze/objcpp/pulse/issues.exp b/infer/tests/codetoanalyze/objcpp/pulse/issues.exp index 0b4541fd0..7d26e4768 100644 --- a/infer/tests/codetoanalyze/objcpp/pulse/issues.exp +++ b/infer/tests/codetoanalyze/objcpp/pulse/issues.exp @@ -12,7 +12,10 @@ codetoanalyze/objcpp/pulse/NPEBasic.mm, dictionaryWithSharedKeySetBad, 2, NIL_IN codetoanalyze/objcpp/pulse/NPEBasic.mm, insertNilInArrayBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,passed as argument to `NSMutableArray.insertObject:atIndex:` (modelled),return from 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,passed as argument to `NSMutableDictionary.removeObjectForKey` (modelled),return from 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,passed as argument to `NSMutableSet.removeObject:` (modelled),return from call to `NSMutableSet.removeObject:` (modelled),invalid access occurs here] +codetoanalyze/objcpp/pulse/NPEBasic.mm, removeObjectsAtIndexesFromArrayBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,when calling `removeObjectsAtIndexesFromArray` here,parameter `indexset` of removeObjectsAtIndexesFromArray,passed as argument to `NSMutableArray.removeObjectsAtIndexes:` (modelled),return from call to `NSMutableArray.removeObjectsAtIndexes:` (modelled),invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, replaceNilInArrayBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,passed as argument to `NSMutableArray.replaceObjectAtIndex:withObject:` (modelled),return from call to `NSMutableArray.replaceObjectAtIndex:withObject:` (modelled),invalid access occurs here] +codetoanalyze/objcpp/pulse/NPEBasic.mm, replaceObjectsAtIndexesWithNilObjectsInArrayBad, 2, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,when calling `replaceObjectsAtIndexesWithObjectsInArray` here,parameter `objects` of replaceObjectsAtIndexesWithObjectsInArray,passed as argument to `NSMutableArray.replaceObjectsAtIndexes:withObjects:` (modelled),return from call to `NSMutableArray.replaceObjectsAtIndexes:withObjects:` (modelled),invalid access occurs here] +codetoanalyze/objcpp/pulse/NPEBasic.mm, replaceObjectsAtNilIndexesWithObjectsInArrayBad, 1, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,when calling `replaceObjectsAtIndexesWithObjectsInArray` here,parameter `indexset` of replaceObjectsAtIndexesWithObjectsInArray,passed as argument to `NSMutableArray.replaceObjectsAtIndexes:withObjects:` (modelled),return from call to `NSMutableArray.replaceObjectsAtIndexes:withObjects:` (modelled),invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, testAccessPropertyAccessorBad, 2, NIL_MESSAGING_TO_NON_POD, no_bucket, ERROR, [is the null pointer,assigned,when calling `SomeObject.ptr` here,parameter `self` of SomeObject.ptr,invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, testCallMethodReturnsnonPODBad, 2, NIL_MESSAGING_TO_NON_POD, no_bucket, ERROR, [is the null pointer,assigned,when calling `SomeObject.returnsnonPOD` here,parameter `self` of SomeObject.returnsnonPOD,invalid access occurs here] codetoanalyze/objcpp/pulse/NPEBasic.mm, testCallMethodReturnsnonPODLatent, 7, NIL_MESSAGING_TO_NON_POD, no_bucket, ERROR, [*** LATENT ***,is the null pointer,assigned,when calling `SomeObject.returnsnonPOD` here,parameter `self` of SomeObject.returnsnonPOD,invalid access occurs here]