[pulse][objc][nullptr] Model NSMutableDictionary.setObject:forKeyedSubscript:

Summary:
`mutableDictionary[key] = value`, crashes if key is nil, however, if value is nil, any object corresponding to a key will be removed from the dictionary.
Under the hood, `NSMutableDictionary.setObject:forKeyedSubscript:` is called by `mutableDictionary[key] = value`.

Reviewed By: ezgicicek

Differential Revision: D28288789

fbshipit-source-id: e4e1c4288
master
Daiva Naudziuniene 4 years ago committed by Facebook GitHub Bot
parent e2cc723074
commit 483d0b54ee

@ -261,7 +261,7 @@ module ObjC = struct
location callee_proc_name ~ret ~actuals:[] ~formals_opt:None astate )
let insertion_into_dictionary (value, value_hist) (key, key_hist) ~desc : model =
let insertion_into_collection_key_and_value (value, value_hist) (key, key_hist) ~desc : model =
fun {location} astate ->
let event = ValueHistory.Call {f= Model desc; location; in_call= []} in
let<*> astate, _ =
@ -277,7 +277,7 @@ module ObjC = struct
astate
let insertion_into_array (value, value_hist) ~desc : model =
let insertion_into_collection_key_or_value (value, value_hist) ~desc : model =
fun {location} astate ->
let event = ValueHistory.Call {f= Model desc; location; in_call= []} in
let<+> astate, _ =
@ -1746,16 +1746,23 @@ module ProcNameDispatcher = struct
; -"NSObject" &:: "init" <>$ capt_arg_payload $--> Misc.id_first_arg ~desc:"NSObject.init"
; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSMutableDictionary")
&:: "setObject:forKey:" <>$ any_arg $+ capt_arg_payload $+ capt_arg_payload
$--> ObjC.insertion_into_dictionary ~desc:"NSMutableDictionary.setObject:forKey:"
$--> ObjC.insertion_into_collection_key_and_value
~desc:"NSMutableDictionary.setObject:forKey:"
; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSMutableDictionary")
&:: "setObject:forKeyedSubscript:" <>$ any_arg $+ any_arg $+ capt_arg_payload
$--> ObjC.insertion_into_collection_key_or_value
~desc:"mutableDictionary[someKey] = value"
; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSMutableArray")
&:: "addObject:" <>$ any_arg $+ capt_arg_payload
$--> ObjC.insertion_into_array ~desc:"NSMutableArray.addObject:"
$--> ObjC.insertion_into_collection_key_or_value ~desc:"NSMutableArray.addObject:"
; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSMutableArray")
&:: "insertObject:atIndex:" <>$ any_arg $+ capt_arg_payload $+ any_arg
$--> ObjC.insertion_into_array ~desc:"NSMutableArray.insertObject:atIndex:"
$--> ObjC.insertion_into_collection_key_or_value
~desc:"NSMutableArray.insertObject:atIndex:"
; +map_context_tenv (PatternMatch.ObjectiveC.implements "NSMutableArray")
&:: "replaceObjectAtIndex:withObject:" <>$ any_arg $+ any_arg $+ capt_arg_payload
$--> ObjC.insertion_into_array ~desc:"NSMutableArray.replaceObjectAtIndex:withObject:"
$--> ObjC.insertion_into_collection_key_or_value
~desc:"NSMutableArray.replaceObjectAtIndex:withObject:"
; +match_regexp_opt Config.pulse_model_return_nonnull
&::.*--> Misc.return_positive
~desc:"modelled as returning not null due to configuration option"

@ -193,6 +193,20 @@ void addObjectInDict(NSMutableDictionary* mDict, id value) {
[mDict setObject:value forKey:@"somestring"];
}
void addNilInDictBracketsOk(NSMutableDictionary* mDict) {
mDict[@"key2"] = nil; // Passing nil will cause any object corresponding
// to a key to be removed from the dictionary.
}
void addNilKeyInDictBracketsBad(NSMutableDictionary* mDict) {
id key = nil;
mDict[key] = @"somestring";
}
void addInDictBracketsOk(NSMutableDictionary* mDict) {
mDict[@"key"] = @"somestring";
}
void testNilMessagingForModelNilNilOK_FP() { addObjectInDict(nil, nil); }
void testNilMessagingForModelNilStringOK() {
@ -224,3 +238,15 @@ void replaceNilInArrayBad(NSMutableArray* mArray) {
void replaceObjectInArrayOk(NSMutableArray* mArray) {
[mArray replaceObjectAtIndex:0 withObject:[SomeObject new]];
}
void addInDictBracketsDefault(NSMutableDictionary<NSString*, NSString*>* mDict,
NSString* key) {
mDict[key] = @"default";
}
void accessZeroElementOk_FP(NSMutableDictionary<NSString*, NSString*>* mDict) {
NSArray<NSString*>* array =
[[NSUserDefaults standardUserDefaults] arrayForKey:@"key"];
NSString* key = array[0];
addInDictBracketsDefault(mDict, key);
}

@ -1,6 +1,8 @@
codetoanalyze/objcpp/pulse/AllocPatternMemLeak.mm, A.create_no_release_leak_bad, 2, MEMORY_LEAK, no_bucket, ERROR, [allocation part of the trace starts here,allocated by call to `ABFDataCreate` (modelled),allocation part of the trace ends here,memory becomes unreachable here]
codetoanalyze/objcpp/pulse/NPEBasic.mm, accessZeroElementOk_FP, 4, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [source of the null value part of the trace starts here,assigned,is the null pointer,null pointer dereference part of the trace starts here,assigned,passed as argument to `NSArray.objectAtIndexedSubscript:`,return from call to `NSArray.objectAtIndexedSubscript:`,assigned,when calling `addInDictBracketsDefault` here,parameter `key` of addInDictBracketsDefault,passed as argument to `mutableDictionary[someKey] = value` (modelled),return from call to `mutableDictionary[someKey] = value` (modelled),invalid access occurs here]
codetoanalyze/objcpp/pulse/NPEBasic.mm, addNilInArrayBad, 0, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,passed as argument to `NSMutableArray.addObject:` (modelled),return from call to `NSMutableArray.addObject:` (modelled),invalid access occurs here]
codetoanalyze/objcpp/pulse/NPEBasic.mm, addNilInDictBad, 2, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,assigned,passed as argument to `NSMutableDictionary.setObject:forKey:` (modelled),return from call to `NSMutableDictionary.setObject:forKey:` (modelled),invalid access occurs here]
codetoanalyze/objcpp/pulse/NPEBasic.mm, addNilKeyInDictBracketsBad, 2, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,assigned,passed as argument to `mutableDictionary[someKey] = value` (modelled),return from call to `mutableDictionary[someKey] = value` (modelled),invalid access occurs here]
codetoanalyze/objcpp/pulse/NPEBasic.mm, addObjectKeyNilInDictBad, 2, NIL_INSERTION_INTO_COLLECTION, no_bucket, ERROR, [is the null pointer,passed as argument to `NSMutableDictionary.setObject:forKey:` (modelled),return from call to `NSMutableDictionary.setObject:forKey:` (modelled),invalid access occurs here]
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, 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]

Loading…
Cancel
Save