[analyzer] Check for NULL passed to CFAutorelease.

Patch by Sean McBride, tests adjusted by me.

llvm-svn: 211453
This commit is contained in:
Jordan Rose 2014-06-21 23:50:40 +00:00
parent 002c25602c
commit e3f310f3bd
5 changed files with 105 additions and 52 deletions

View File

@ -523,16 +523,17 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
}
//===----------------------------------------------------------------------===//
// CFRetain/CFRelease/CFMakeCollectable checking for null arguments.
// CFRetain/CFRelease/CFMakeCollectable/CFAutorelease checking for null arguments.
//===----------------------------------------------------------------------===//
namespace {
class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable std::unique_ptr<APIMisuse> BT;
mutable IdentifierInfo *Retain, *Release, *MakeCollectable;
mutable IdentifierInfo *Retain, *Release, *MakeCollectable, *Autorelease;
public:
CFRetainReleaseChecker()
: Retain(nullptr), Release(nullptr), MakeCollectable(nullptr) {}
: Retain(nullptr), Release(nullptr), MakeCollectable(nullptr),
Autorelease(nullptr) {}
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
} // end anonymous namespace
@ -554,13 +555,15 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
Retain = &Ctx.Idents.get("CFRetain");
Release = &Ctx.Idents.get("CFRelease");
MakeCollectable = &Ctx.Idents.get("CFMakeCollectable");
Autorelease = &Ctx.Idents.get("CFAutorelease");
BT.reset(new APIMisuse(
this, "null passed to CFRetain/CFRelease/CFMakeCollectable"));
this, "null passed to CF memory management function"));
}
// Check if we called CFRetain/CFRelease/CFMakeCollectable.
// Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
const IdentifierInfo *FuncII = FD->getIdentifier();
if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable))
if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable ||
FuncII == Autorelease))
return;
// FIXME: The rest of this just checks that the argument is non-null.
@ -597,6 +600,8 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
description = "Null pointer argument in call to CFRelease";
else if (FuncII == MakeCollectable)
description = "Null pointer argument in call to CFMakeCollectable";
else if (FuncII == Autorelease)
description = "Null pointer argument in call to CFAutorelease";
else
llvm_unreachable("impossible case");

View File

@ -528,38 +528,54 @@ void f15() {
CFRelease(*B); // no-warning
}
// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable.
// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
void f16(int x, CFTypeRef p) {
if (p)
return;
if (x > 0) {
CFRelease(p); // expected-warning{{Null pointer argument in call to CFRelease}}
}
else if (x < 0) {
CFRetain(p); // expected-warning{{Null pointer argument in call to CFRetain}}
}
else {
CFMakeCollectable(p); // expected-warning{{Null pointer argument in call to CFMakeCollectable}}
switch (x) {
case 0:
CFRelease(p);
break;
case 1:
CFRetain(p);
break;
case 2:
CFMakeCollectable(p);
break;
case 3:
CFAutorelease(p);
break;
default:
break;
}
}
// Test that an object is non-null after being CFRetained/CFReleased.
// Test that an object is non-null after CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
void f17(int x, CFTypeRef p) {
if (x > 0) {
switch (x) {
case 0:
CFRelease(p);
if (!p)
CFRelease(0); // no-warning
}
else if (x < 0) {
break;
case 1:
CFRetain(p);
if (!p)
CFRetain(0); // no-warning
}
else {
break;
case 2:
CFMakeCollectable(p);
if (!p)
CFMakeCollectable(0); // no-warning
break;
case 3:
CFAutorelease(p);
if (!p)
CFAutorelease(0); // no-warning
break;
default:
break;
}
}

View File

@ -570,38 +570,54 @@ void f15() {
CFRelease(*B); // no-warning
}
// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable.
// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
void f16(int x, CFTypeRef p) {
if (p)
return;
if (x > 0) {
CFRelease(p); // expected-warning{{Null pointer argument in call to CFRelease}}
}
else if (x < 0) {
CFRetain(p); // expected-warning{{Null pointer argument in call to CFRetain}}
}
else {
CFMakeCollectable(p); // expected-warning{{Null pointer argument in call to CFMakeCollectable}}
switch (x) {
case 0:
CFRelease(p);
break;
case 1:
CFRetain(p);
break;
case 2:
CFMakeCollectable(p);
break;
case 3:
CFAutorelease(p);
break;
default:
break;
}
}
// Test that an object is non-null after being CFRetained/CFReleased.
// Test that an object is non-null after CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
void f17(int x, CFTypeRef p) {
if (x > 0) {
switch (x) {
case 0:
CFRelease(p);
if (!p)
CFRelease(0); // no-warning
}
else if (x < 0) {
break;
case 1:
CFRetain(p);
if (!p)
CFRetain(0); // no-warning
}
else {
break;
case 2:
CFMakeCollectable(p);
if (!p)
CFMakeCollectable(0); // no-warning
break;
case 3:
CFAutorelease(p);
if (!p)
CFAutorelease(0); // no-warning
break;
default:
break;
}
}

View File

@ -542,7 +542,7 @@ static void CreateRefUndef(SCDynamicStoreRef *storeRef, unsigned x) {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRelease</string>
// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
// CHECK-NEXT: <key>type</key><string>null passed to CF memory management function</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
// CHECK-NEXT: <key>issue_context</key><string>test</string>
// CHECK-NEXT: <key>issue_hash</key><string>5</string>

View File

@ -523,38 +523,54 @@ void f15() {
CFRelease(*B); // no-warning
}
// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable.
// Test when we pass NULL to CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
void f16(int x, CFTypeRef p) {
if (p)
return;
if (x > 0) {
switch (x) {
case 0:
CFRelease(p); // expected-warning{{Null pointer argument in call to CFRelease}}
}
else if (x < 0) {
break;
case 1:
CFRetain(p); // expected-warning{{Null pointer argument in call to CFRetain}}
}
else {
break;
case 2:
CFMakeCollectable(p); // expected-warning{{Null pointer argument in call to CFMakeCollectable}}
break;
case 3:
CFAutorelease(p); // expected-warning{{Null pointer argument in call to CFAutorelease}}
break;
default:
break;
}
}
// Test that an object is non-null after being CFRetained/CFReleased.
// Test that an object is non-null after CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
void f17(int x, CFTypeRef p) {
if (x > 0) {
switch (x) {
case 0:
CFRelease(p);
if (!p)
CFRelease(0); // no-warning
}
else if (x < 0) {
break;
case 1:
CFRetain(p);
if (!p)
CFRetain(0); // no-warning
}
else {
break;
case 2:
CFMakeCollectable(p);
if (!p)
CFMakeCollectable(0); // no-warning
break;
case 3:
CFAutorelease(p);
if (!p)
CFAutorelease(0); // no-warning
break;
default:
break;
}
}
@ -9501,7 +9517,7 @@ id returnNSNull() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRelease</string>
// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
// CHECK-NEXT: <key>type</key><string>null passed to CF memory management function</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f16</string>
// CHECK-NEXT: <key>issue_hash</key><string>5</string>
@ -9838,7 +9854,7 @@ id returnNSNull() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFRetain</string>
// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
// CHECK-NEXT: <key>type</key><string>null passed to CF memory management function</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f16</string>
// CHECK-NEXT: <key>issue_hash</key><string>8</string>
@ -10175,7 +10191,7 @@ id returnNSNull() {
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Null pointer argument in call to CFMakeCollectable</string>
// CHECK-NEXT: <key>category</key><string>API Misuse (Apple)</string>
// CHECK-NEXT: <key>type</key><string>null passed to CFRetain/CFRelease/CFMakeCollectable</string>
// CHECK-NEXT: <key>type</key><string>null passed to CF memory management function</string>
// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
// CHECK-NEXT: <key>issue_context</key><string>f16</string>
// CHECK-NEXT: <key>issue_hash</key><string>11</string>