diff --git a/infer/tests/codetoanalyze/objc/pulse/NPENilBlocks.m b/infer/tests/codetoanalyze/objc/pulse/NPENilBlocks.m new file mode 100644 index 000000000..8368d441c --- /dev/null +++ b/infer/tests/codetoanalyze/objc/pulse/NPENilBlocks.m @@ -0,0 +1,101 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@interface BlockA : NSObject +@end + +@implementation BlockA { + + void (^_block_field)(void); +} + +- (void)doSomethingThenCallback:(void (^)(void))my_block { + // null dereference, segfault if my_block is nil + my_block(); +} + +- (void)FN_assignNilBad { + + void (^my_block)(void) = ^() { + }; + my_block = NULL; + my_block(); // Null deref +} + +- (void)checkNotNilOk:(void (^)(void))my_block { + // ok to call this block! + if (my_block != nil) { + my_block(); + } +} + +- (void)FN_paramAssignNilBad:(void (^)(void))my_block { + + my_block = NULL; + my_block(); // Null deref +} + +- (void)FN_paramReassignNilBad:(void (^)(void))my_block_param { + + void (^my_block)(void) = ^() { + }; + my_block = NULL; + my_block_param = my_block; + my_block_param(); // Null deref +} + +- (void)assignEmptyBlockOk:(void (^)(void))my_block_param { + + void (^my_block)(void) = ^() { + }; + my_block_param = my_block; + my_block_param(); // No error here +} + +- (void)checkNotNilBlockAsArgOk:(BOOL)a + block_param:(void (^)(void))block_param { + + void (^my_block)(void) = ^() { + if (block_param) + block_param(); // No error here + }; + + if (a) { + [self checkNotNilOk:^() { + my_block(); // No error here + }]; + } +} + +- (void)FN_ivarNilBlockBad { + _block_field(); // Ivar not nullable +} + +- (int)check_nullifyOk { + int i = 7; + int* x = &i; + int (^my_block)(void) = ^() { + return *x; // we'll get a false NPE here if we nullify x too early. + }; + return my_block(); +} + +@end + +void calldoSomethingThenCallbackOk() { + BlockA* blockA = [BlockA alloc]; + void (^my_block)(void) = ^() { + }; + [blockA doSomethingThenCallback:my_block]; +} + +void FN_calldoSomethingThenCallbackWithNilBad() { + BlockA* blockA = [BlockA alloc]; + [blockA doSomethingThenCallback:nil]; +}