diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index 01c7afe520410..09306383d53f5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1469,6 +1469,9 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call, if (!*FreeWhenDone) return; + if (Call.hasNonZeroCallbackArg()) + return; + bool IsKnownToBeAllocatedMemory; ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0), Call.getOriginExpr(), C.getState(), diff --git a/clang/test/Analysis/Inputs/system-header-simulator-objc.h b/clang/test/Analysis/Inputs/system-header-simulator-objc.h index df751d03e642a..0dc6b369b0151 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator-objc.h +++ b/clang/test/Analysis/Inputs/system-header-simulator-objc.h @@ -117,7 +117,10 @@ typedef double NSTimeInterval; + (id)dataWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; - (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length; - (id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b; -- (id)initWithBytes:(void *)bytes length:(NSUInteger) length; +- (id)initWithBytesNoCopy:(void *)bytes + length:(NSUInteger)length + deallocator:(void (^)(void *bytes, NSUInteger length))deallocator; +- (id)initWithBytes:(void *)bytes length:(NSUInteger)length; @end typedef struct { diff --git a/clang/test/Analysis/malloc.mm b/clang/test/Analysis/malloc.mm index e84644b9dd732..1b7dd2756e1bb 100644 --- a/clang/test/Analysis/malloc.mm +++ b/clang/test/Analysis/malloc.mm @@ -1,4 +1,8 @@ -// RUN: %clang_analyze_cc1 -std=c++14 -analyzer-checker=core,unix.Malloc -analyzer-store=region -verify -fblocks %s +// RUN: %clang_analyze_cc1 -std=c++14 \ +// RUN: -analyzer-checker=core,unix.Malloc,cplusplus.NewDelete \ +// RUN: -analyzer-checker=unix.MismatchedDeallocator \ +// RUN: -verify -fblocks %s + #import "Inputs/system-header-simulator-objc.h" #import "Inputs/system-header-simulator-for-malloc.h" @@ -61,6 +65,23 @@ void testNSStringFreeWhenDoneNO(NSUInteger dataLength) { NSString *nsstr = [[NSString alloc] initWithBytesNoCopy:data length:dataLength encoding:NSUTF8StringEncoding freeWhenDone:0]; // expected-warning{{leak}} } +void testNSStringFreeWhenDoneNewDelete(NSUInteger dataLength) { + unsigned char *data = new unsigned char(42); + NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data + length:dataLength freeWhenDone:1]; + // expected-warning@-2{{-initWithBytesNoCopy:length:freeWhenDone: cannot take ownership of memory allocated by 'new'}} +} + +void testNSStringFreeWhenDoneNewDelete2(NSUInteger dataLength) { + unsigned char *data = new unsigned char(42); + NSData *nsdata = [[NSData alloc] initWithBytesNoCopy:data + length:dataLength + deallocator:^(void *bytes, + NSUInteger length) { + delete (unsigned char *)bytes; + }]; // no-warning +} + void testNSStringFreeWhenDoneNO2(NSUInteger dataLength) { unichar *data = (unichar*)malloc(42); NSString *nsstr = [[NSString alloc] initWithCharactersNoCopy:data length:dataLength freeWhenDone:0]; // expected-warning{{leak}}