]> granicus.if.org Git - clang/commitdiff
[analyzer] Buffers passed to CGBitmapContextCreate can escape.
authorJordan Rose <jordan_rose@apple.com>
Sat, 16 Jun 2012 00:09:20 +0000 (00:09 +0000)
committerJordan Rose <jordan_rose@apple.com>
Sat, 16 Jun 2012 00:09:20 +0000 (00:09 +0000)
Specifically, although the bitmap context does not take ownership of the
buffer (unlike CGBitmapContextCreateWithData), the data buffer can be extracted
out of the created CGContextRef. Thus the buffer is not leaked even if its
original pointer goes out of scope, as long as
- the context escapes, or
- it is retrieved via CGBitmapContextGetData and freed.

Actually implementing that logic is beyond the current scope of MallocChecker,
so for now CGBitmapContextCreate goes on our system function exception list.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@158579 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/MallocChecker.cpp
test/Analysis/malloc.c
test/Analysis/system-header-simulator.h

index c22c6a26879ef0a080f6e82551b8aa9b96d49c44..1adcca03fdcf91b8873258a8050f89c7fcf2789e 100644 (file)
@@ -1334,12 +1334,14 @@ bool MallocChecker::doesNotFreeMemory(const CallOrObjCMessage *Call,
                 return false;
     }
 
-    // A bunch of other functions, which take ownership of a pointer (See retain
-    // release checker). Not all the parameters here are invalidated, but the
-    // Malloc checker cannot differentiate between them. The right way of doing
-    // this would be to implement a pointer escapes callback.
-    if (FName == "CVPixelBufferCreateWithBytes" ||
+    // A bunch of other functions which either take ownership of a pointer or
+    // wrap the result up in a struct or object, meaning it can be freed later.
+    // (See RetainCountChecker.) Not all the parameters here are invalidated,
+    // but the Malloc checker cannot differentiate between them. The right way
+    // of doing this would be to implement a pointer escapes callback.
+    if (FName == "CGBitmapContextCreate" ||
         FName == "CGBitmapContextCreateWithData" ||
+        FName == "CVPixelBufferCreateWithBytes" ||
         FName == "CVPixelBufferCreateWithPlanarBytes" ||
         FName == "OSAtomicEnqueue") {
       return false;
index 7c2196ac9e53c28e8ab1d477aeeee508459ce154..c532d6813f4e0f9c6df51e24c4d176adb5fbb445 100644 (file)
@@ -955,3 +955,22 @@ void test_double_assign_ints_positive()
   (void*)(long)(unsigned long)ptr; // expected-warning {{unused}} expected-warning {{leak}}
 }
 
+
+void testCGContextNoLeak()
+{
+  void *ptr = malloc(16);
+  CGContextRef context = CGBitmapContextCreate(ptr);
+
+  // Because you can get the data back out like this, even much later,
+  // CGBitmapContextCreate is one of our "stop-tracking" exceptions.
+  free(CGBitmapContextGetData(context));
+}
+
+void testCGContextLeak()
+{
+  void *ptr = malloc(16);
+  CGContextRef context = CGBitmapContextCreate(ptr);
+  // However, this time we're just leaking the data, because the context
+  // object doesn't escape and it hasn't been freed in this function.
+}
+
index a8cba9ce5b252cb9e5905a1f8d5b6f6f6f254549..d2fb2e8684b2da902ca13162d7c7730c0a6717f9 100644 (file)
@@ -46,3 +46,10 @@ typedef struct {
 
 int dealocateMemWhenDoneByVal(void*, StWithCallback);
 int dealocateMemWhenDoneByRef(StWithCallback*, const void*);
+
+typedef struct CGContext *CGContextRef;
+CGContextRef CGBitmapContextCreate(void *data/*, size_t width, size_t height,
+                                   size_t bitsPerComponent, size_t bytesPerRow,
+                                   CGColorSpaceRef space,
+                                   CGBitmapInfo bitmapInfo*/);
+void *CGBitmapContextGetData(CGContextRef context);