Author: Artem Dergachev
Date: 2019-12-18T14:19:17-08:00
New Revision: bce1cce6bf1286541c57690ab1129fbc02c60f93

URL: 
https://github.com/llvm/llvm-project/commit/bce1cce6bf1286541c57690ab1129fbc02c60f93
DIFF: 
https://github.com/llvm/llvm-project/commit/bce1cce6bf1286541c57690ab1129fbc02c60f93.diff

LOG: [analyzer] Teach MismatchedDealloc about initWithBytesNoCopy with 
deallocator.

MallocChecker warns when memory is passed into -[NSData initWithBytesNoCopy]
but isn't allocated by malloc(), because it will be deallocated by free().
However, initWithBytesNoCopy has an overload that takes an arbitrary block
for deallocating the object. If such overload is used, it is no longer
necessary to make sure that the memory is allocated by malloc().

Added: 
    

Modified: 
    clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    clang/test/Analysis/Inputs/system-header-simulator-objc.h
    clang/test/Analysis/malloc.mm

Removed: 
    


################################################################################
diff  --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 01c7afe52041..09306383d53f 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 df751d03e642..0dc6b369b015 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 e84644b9dd73..1b7dd2756e1b 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}}


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to