diff --git a/infer/src/checkers/NullabilityCheck.ml b/infer/src/checkers/NullabilityCheck.ml index e27db7a7e..5b8b383c7 100644 --- a/infer/src/checkers/NullabilityCheck.ml +++ b/infer/src/checkers/NullabilityCheck.ml @@ -37,12 +37,18 @@ module TransferFunctions (CFG : ProcCfg.S) = struct let is_objc_container_add_method : Typ.Procname.t -> bool = - let add_methods = - ["arrayWithObjects:"; "arrayWithObjects:count:"; "dictionaryWithObjectsAndKeys:"] + let method_prefixes = + [ "arrayWithObjects:" + ; "arrayWithObjects:count:" + ; "dictionaryWithObjectsAndKeys:" + ; "initWithObjectsAndKeys:" + ; "dictionaryWithObjects:" ] 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 + List.exists + ~f:(fun prefix -> String.is_prefix ~prefix simplified_callee_pname) + method_prefixes let report_nullable_dereference ap call_sites {ProcData.pdesc; extras} loc = diff --git a/infer/tests/codetoanalyze/objc/checkers/Nullable.m b/infer/tests/codetoanalyze/objc/checkers/Nullable.m index 31ccf2f9c..e8427aaf7 100644 --- a/infer/tests/codetoanalyze/objc/checkers/Nullable.m +++ b/infer/tests/codetoanalyze/objc/checkers/Nullable.m @@ -145,18 +145,44 @@ int* __nullable returnsNull(); NSArray* array = @[ url ]; // reports here } -- (NSDictionary*)nullableValueInNSDictionary { +- (NSDictionary*)nullableValueInNSDictionaryBad { NSObject* nullableValue = [self nullableMethod]; NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"key", nullableValue, nil]; // reports here return dict; } -- (NSDictionary*)nullableKeyInNSDictionary { +- (NSDictionary*)nullableKeyInNSDictionaryBad { NSObject* nullableKey = [self nullableMethod]; NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:nullableKey, @"value", nil]; // reports here return dict; } +- (NSDictionary*)nullableKeyInNSDictionaryInitBad { + NSObject* nullableKey = [self nullableMethod]; + NSDictionary* dict = [[NSDictionary alloc] + initWithObjectsAndKeys:nullableKey, @"value", nil]; // reports here + return dict; +} + +- (NSDictionary*)nullableValueInNSDictionaryInitBad { + NSObject* nullableValue = [self nullableMethod]; + NSDictionary* dict = [[NSDictionary alloc] + initWithObjectsAndKeys:@"key", nullableValue, nil]; // reports here + return dict; +} + +- (NSDictionary*)nullableKeyInNSDictionaryInitLiteralBad { + NSObject* nullableKey = [self nullableMethod]; + NSDictionary* dict = @{nullableKey : @"value"}; // reports here + return dict; +} + +- (NSDictionary*)nullableValueInNSDictionaryInitLiteralBad { + NSObject* nullableValue = [self nullableMethod]; + NSDictionary* dict = @{@"key" : nullableValue}; // reports here + return dict; +} + @end diff --git a/infer/tests/codetoanalyze/objc/checkers/issues.exp b/infer/tests/codetoanalyze/objc/checkers/issues.exp index ae0a051fd..3e2d41cfd 100644 --- a/infer/tests/codetoanalyze/objc/checkers/issues.exp +++ b/infer/tests/codetoanalyze/objc/checkers/issues.exp @@ -9,12 +9,20 @@ 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_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_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_nullableKeyInNSDictionaryBad, 2, NULLABLE_DEREFERENCE, [dereference of &nullableKey,assignment of the nullable value,definition of nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableKeyInNSDictionaryBad, 2, PREMATURE_NIL_TERMINATION_ARGUMENT, [start of procedure nullableKeyInNSDictionaryBad,start of procedure nullableMethod,return from a call to T_nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableKeyInNSDictionaryInitBad, 2, NULLABLE_DEREFERENCE, [dereference of &nullableKey,assignment of the nullable value,definition of nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableKeyInNSDictionaryInitBad, 2, PREMATURE_NIL_TERMINATION_ARGUMENT, [start of procedure nullableKeyInNSDictionaryInitBad,start of procedure nullableMethod,return from a call to T_nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableKeyInNSDictionaryInitLiteralBad, 2, NULLABLE_DEREFERENCE, [dereference of &nullableKey,assignment of the nullable value,definition of nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableKeyInNSDictionaryInitLiteralBad, 2, NULL_DEREFERENCE, [start of procedure nullableKeyInNSDictionaryInitLiteralBad,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, 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_nullableValueInNSDictionaryBad, 2, NULLABLE_DEREFERENCE, [dereference of &nullableValue,assignment of the nullable value,definition of nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableValueInNSDictionaryBad, 2, PREMATURE_NIL_TERMINATION_ARGUMENT, [start of procedure nullableValueInNSDictionaryBad,start of procedure nullableMethod,return from a call to T_nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableValueInNSDictionaryInitBad, 2, NULLABLE_DEREFERENCE, [dereference of &nullableValue,assignment of the nullable value,definition of nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableValueInNSDictionaryInitBad, 2, PREMATURE_NIL_TERMINATION_ARGUMENT, [start of procedure nullableValueInNSDictionaryInitBad,start of procedure nullableMethod,return from a call to T_nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableValueInNSDictionaryInitLiteralBad, 2, NULLABLE_DEREFERENCE, [dereference of &nullableValue,assignment of the nullable value,definition of nullableMethod] +codetoanalyze/objc/checkers/Nullable.m, T_nullableValueInNSDictionaryInitLiteralBad, 2, NULL_DEREFERENCE, [start of procedure nullableValueInNSDictionaryInitLiteralBad,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_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]