[clang] bce1cce - [analyzer] Teach MismatchedDealloc about initWithBytesNoCopy with deallocator.

Artem Dergachev via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 18 14:19:25 PST 2019


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 at -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}}


        


More information about the cfe-commits mailing list