[infer][nullable checker] also report a null dereference error when adding nil key or value to NSDictionary

Summary: Adding a null key or a null value will cause a runtime exception.

Reviewed By: sblackshear

Differential Revision: D6378618

fbshipit-source-id: 8bd27c6
master
Jeremy Dubreil 7 years ago committed by Facebook Github Bot
parent ceb0062cdd
commit a991b98d02

@ -29,10 +29,20 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
(Specs.proc_resolve_attributes callee_pname) (Specs.proc_resolve_attributes callee_pname)
let is_blacklisted callee_pname = let is_blacklisted_method : Typ.Procname.t -> bool =
let blacklist = ["URLWithString:"] let blacklist = ["URLWithString:"] in
and simplified_callee_pname = Typ.Procname.to_simplified_string callee_pname in fun proc_name ->
List.exists ~f:(String.equal simplified_callee_pname) blacklist let simplified_callee_pname = Typ.Procname.to_simplified_string proc_name in
List.exists ~f:(String.equal simplified_callee_pname) blacklist
let is_objc_container_add_method : Typ.Procname.t -> bool =
let add_methods =
["arrayWithObjects:"; "arrayWithObjects:count:"; "dictionaryWithObjectsAndKeys:"]
in
fun proc_name ->
let simplified_callee_pname = Typ.Procname.to_simplified_string proc_name in
List.exists ~f:(String.equal simplified_callee_pname) add_methods
let report_nullable_dereference ap call_sites {ProcData.pdesc; extras} loc = let report_nullable_dereference ap call_sites {ProcData.pdesc; extras} loc =
@ -168,7 +178,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Direct callee_pname, (HilExp.AccessPath receiver) :: _, _, _) | Call (_, Direct callee_pname, (HilExp.AccessPath receiver) :: _, _, _)
when Models.is_check_not_null callee_pname -> when Models.is_check_not_null callee_pname ->
assume_pnames_notnull receiver astate assume_pnames_notnull receiver astate
| Call (_, Direct callee_pname, _, _, _) when is_blacklisted callee_pname -> | Call (_, Direct callee_pname, _, _, _) when is_blacklisted_method callee_pname ->
astate astate
| Call (Some ret_var, Direct callee_pname, _, _, loc) | Call (Some ret_var, Direct callee_pname, _, _, loc)
when Annotations.pname_has_return_annot callee_pname when Annotations.pname_has_return_annot callee_pname
@ -178,8 +188,7 @@ module TransferFunctions (CFG : ProcCfg.S) = struct
| Call (_, Direct callee_pname, (HilExp.AccessPath receiver) :: _, _, loc) | Call (_, Direct callee_pname, (HilExp.AccessPath receiver) :: _, _, loc)
when is_instance_method callee_pname -> when is_instance_method callee_pname ->
check_ap proc_data loc receiver astate check_ap proc_data loc receiver astate
| Call (_, Direct callee_pname, args, _, loc) | Call (_, Direct callee_pname, args, _, loc) when is_objc_container_add_method callee_pname ->
when Typ.Procname.equal callee_pname BuiltinDecl.nsArray_arrayWithObjectsCount ->
check_nil_in_nsarray proc_data loc args astate check_nil_in_nsarray proc_data loc args astate
| Call (Some ret_var, _, _, _, _) -> | Call (Some ret_var, _, _, _, _) ->
remove_nullable_ap (ret_var, []) astate remove_nullable_ap (ret_var, []) astate

@ -118,14 +118,14 @@ int* __nullable returnsNull();
- (NSArray*)nullableObjectInNSArrayBad { - (NSArray*)nullableObjectInNSArrayBad {
NSObject* nullableObject = [self nullableMethod]; NSObject* nullableObject = [self nullableMethod];
NSArray* array = @[ nullableObject ]; NSArray* array = @[ nullableObject ]; // reports here
return array; return array;
} }
- (NSArray*)secondElementNullableObjectInNSArrayBad { - (NSArray*)secondElementNullableObjectInNSArrayBad {
NSObject* allocatedObject = [NSObject alloc]; NSObject* allocatedObject = [NSObject alloc];
NSObject* nullableObject = [self nullableMethod]; NSObject* nullableObject = [self nullableMethod];
NSArray* array = @[ allocatedObject, nullableObject ]; NSArray* array = @[ allocatedObject, nullableObject ]; // reports here
return array; return array;
} }
@ -133,7 +133,7 @@ int* __nullable returnsNull();
NSObject* nullableObject = [self nullableMethod]; NSObject* nullableObject = [self nullableMethod];
NSArray* array; NSArray* array;
if (nullableObject) { if (nullableObject) {
array = @[ nullableObject ]; array = @[ nullableObject ]; // reports here
} else { } else {
array = @[ @"String" ]; array = @[ @"String" ];
} }
@ -142,7 +142,21 @@ int* __nullable returnsNull();
- (NSArray*)URLWithStringOkay { - (NSArray*)URLWithStringOkay {
NSURL* url = [NSURL URLWithString:@"some/url/string"]; NSURL* url = [NSURL URLWithString:@"some/url/string"];
NSArray* array = @[ url ]; NSArray* array = @[ url ]; // reports here
}
- (NSDictionary*)nullableValueInNSDictionary {
NSObject* nullableValue = [self nullableMethod];
NSMutableDictionary* dict = [NSMutableDictionary
dictionaryWithObjectsAndKeys:@"key", nullableValue, nil]; // reports here
return dict;
}
- (NSDictionary*)nullableKeyInNSDictionary {
NSObject* nullableKey = [self nullableMethod];
NSMutableDictionary* dict = [NSMutableDictionary
dictionaryWithObjectsAndKeys:nullableKey, @"value", nil]; // reports here
return dict;
} }
@end @end

@ -9,8 +9,12 @@ codetoanalyze/objc/checkers/Nullable.m, T_dereferenceNullableFunctionBad, 2, NUL
codetoanalyze/objc/checkers/Nullable.m, T_dereferenceNullableFunctionBad, 2, NULL_DEREFERENCE, [start of procedure dereferenceNullableFunctionBad,Skipping returnsNull(): function or method not found] codetoanalyze/objc/checkers/Nullable.m, T_dereferenceNullableFunctionBad, 2, NULL_DEREFERENCE, [start of procedure dereferenceNullableFunctionBad,Skipping returnsNull(): function or method not found]
codetoanalyze/objc/checkers/Nullable.m, T_dereferenceUnnanotatedFieldAfterTestForNullBad, 1, FIELD_SHOULD_BE_NULLABLE, [Field unnanotatedField is compared to null here] codetoanalyze/objc/checkers/Nullable.m, T_dereferenceUnnanotatedFieldAfterTestForNullBad, 1, FIELD_SHOULD_BE_NULLABLE, [Field unnanotatedField is compared to null here]
codetoanalyze/objc/checkers/Nullable.m, T_dereferenceUnnanotatedFieldAfterTestForNullBad, 2, NULL_DEREFERENCE, [start of procedure dereferenceUnnanotatedFieldAfterTestForNullBad,Condition is true] codetoanalyze/objc/checkers/Nullable.m, T_dereferenceUnnanotatedFieldAfterTestForNullBad, 2, NULL_DEREFERENCE, [start of procedure dereferenceUnnanotatedFieldAfterTestForNullBad,Condition is true]
codetoanalyze/objc/checkers/Nullable.m, T_nullableKeyInNSDictionary, 2, NULLABLE_DEREFERENCE, [dereference of &nullableKey,assignment of the nullable value,definition of nullableMethod]
codetoanalyze/objc/checkers/Nullable.m, T_nullableKeyInNSDictionary, 2, PREMATURE_NIL_TERMINATION_ARGUMENT, [start of procedure nullableKeyInNSDictionary,start of procedure nullableMethod,return from a call to T_nullableMethod]
codetoanalyze/objc/checkers/Nullable.m, T_nullableObjectInNSArrayBad, 2, NULLABLE_DEREFERENCE, [dereference of &nullableObject,assignment of the nullable value,definition of nullableMethod] codetoanalyze/objc/checkers/Nullable.m, T_nullableObjectInNSArrayBad, 2, NULLABLE_DEREFERENCE, [dereference of &nullableObject,assignment of the nullable value,definition of nullableMethod]
codetoanalyze/objc/checkers/Nullable.m, T_nullableObjectInNSArrayBad, 2, NULL_DEREFERENCE, [start of procedure nullableObjectInNSArrayBad,start of procedure nullableMethod,return from a call to T_nullableMethod] codetoanalyze/objc/checkers/Nullable.m, T_nullableObjectInNSArrayBad, 2, NULL_DEREFERENCE, [start of procedure nullableObjectInNSArrayBad,start of procedure nullableMethod,return from a call to T_nullableMethod]
codetoanalyze/objc/checkers/Nullable.m, T_nullableValueInNSDictionary, 2, NULLABLE_DEREFERENCE, [dereference of &nullableValue,assignment of the nullable value,definition of nullableMethod]
codetoanalyze/objc/checkers/Nullable.m, T_nullableValueInNSDictionary, 2, PREMATURE_NIL_TERMINATION_ARGUMENT, [start of procedure nullableValueInNSDictionary,start of procedure nullableMethod,return from a call to T_nullableMethod]
codetoanalyze/objc/checkers/Nullable.m, T_reassigningNullableObjectOkay, 1, DEAD_STORE, [Write of unused value] codetoanalyze/objc/checkers/Nullable.m, T_reassigningNullableObjectOkay, 1, DEAD_STORE, [Write of unused value]
codetoanalyze/objc/checkers/Nullable.m, T_secondElementNullableObjectInNSArrayBad, 3, NULLABLE_DEREFERENCE, [dereference of &nullableObject,assignment of the nullable value,definition of nullableMethod] codetoanalyze/objc/checkers/Nullable.m, T_secondElementNullableObjectInNSArrayBad, 3, NULLABLE_DEREFERENCE, [dereference of &nullableObject,assignment of the nullable value,definition of nullableMethod]
codetoanalyze/objc/checkers/Nullable.m, T_secondElementNullableObjectInNSArrayBad, 3, NULL_DEREFERENCE, [start of procedure secondElementNullableObjectInNSArrayBad,start of procedure nullableMethod,return from a call to T_nullableMethod] codetoanalyze/objc/checkers/Nullable.m, T_secondElementNullableObjectInNSArrayBad, 3, NULL_DEREFERENCE, [start of procedure secondElementNullableObjectInNSArrayBad,start of procedure nullableMethod,return from a call to T_nullableMethod]

Loading…
Cancel
Save