diff --git a/infer/models/objc/src/CoreFoundation.c b/infer/models/objc/src/CoreFoundation.c index 693e50c4a..f45fb1829 100644 --- a/infer/models/objc/src/CoreFoundation.c +++ b/infer/models/objc/src/CoreFoundation.c @@ -7,3 +7,18 @@ #import void CFRelease(CFTypeRef item) { __free_cf(item); } + +CFRunLoopObserverRef CFRunLoopObserverCreateWithHandler( + CFAllocatorRef allocator, + CFOptionFlags activities, + Boolean repeats, + CFIndex order, + void (^block)(CFRunLoopObserverRef observer, CFRunLoopActivity activity)) { + // We need to skip allocation for this function since we currently don't + // handle object finalizers in objc. This is to avoid false positive memory + // leaks when the 'observer' is correctly freed in the block argument. + + // undefined function will get skipped and thus make + // CFRunLoopObserverCreateWithHandler return an angelic object + return getAngelicObject(); +} diff --git a/infer/tests/codetoanalyze/objc/errors/Makefile b/infer/tests/codetoanalyze/objc/errors/Makefile index 32ab04499..9276073ea 100644 --- a/infer/tests/codetoanalyze/objc/errors/Makefile +++ b/infer/tests/codetoanalyze/objc/errors/Makefile @@ -27,6 +27,7 @@ SOURCES_DEFAULT = \ memory_leaks_benchmark/RetainReleaseExampleBucketing.m \ memory_leaks_benchmark/CoreVideoExample.m \ memory_leaks_benchmark/RetainCycleLength3.m \ + memory_leaks_benchmark/ReleasedInBlock.m \ npe/dynamic_dispatch.m \ npe/Fraction.m \ npe/NPD_core_foundation.m \ diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/ReleasedInBlock.m b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/ReleasedInBlock.m new file mode 100644 index 000000000..b64996da5 --- /dev/null +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/ReleasedInBlock.m @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +void allocAndReleaseInBlock() { + void (^callback)(CFRunLoopObserverRef obs, CFRunLoopActivity activity) = + ^(CFRunLoopObserverRef obs, CFRunLoopActivity activity) { + // We should check if the object is released properly, see + // infer/models/objc/src/CoreFoundation.c + CFRelease(obs); + }; + + CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler( + NULL, kCFRunLoopBeforeWaiting, NO, UINT_MAX, callback); + CFRunLoopAddObserver(CFRunLoopGetMain(), observer, kCFRunLoopCommonModes); +}