diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index d36679d706c8..3fd55760bc5f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -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 > { mutable std::unique_ptr 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"); diff --git a/clang/test/ARCMT/objcmt-arc-cf-annotations.m b/clang/test/ARCMT/objcmt-arc-cf-annotations.m index 1e063f6e7368..c9a5b8215d10 100644 --- a/clang/test/ARCMT/objcmt-arc-cf-annotations.m +++ b/clang/test/ARCMT/objcmt-arc-cf-annotations.m @@ -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; } } diff --git a/clang/test/ARCMT/objcmt-arc-cf-annotations.m.result b/clang/test/ARCMT/objcmt-arc-cf-annotations.m.result index 75dda6ca4014..84bc43dcb5ca 100644 --- a/clang/test/ARCMT/objcmt-arc-cf-annotations.m.result +++ b/clang/test/ARCMT/objcmt-arc-cf-annotations.m.result @@ -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; } } diff --git a/clang/test/Analysis/diagnostics/undef-value-param.m b/clang/test/Analysis/diagnostics/undef-value-param.m index e977acb70fd9..b0ce56caa348 100644 --- a/clang/test/Analysis/diagnostics/undef-value-param.m +++ b/clang/test/Analysis/diagnostics/undef-value-param.m @@ -542,7 +542,7 @@ static void CreateRefUndef(SCDynamicStoreRef *storeRef, unsigned x) { // CHECK-NEXT: // CHECK-NEXT: descriptionNull pointer argument in call to CFRelease // CHECK-NEXT: categoryAPI Misuse (Apple) -// CHECK-NEXT: typenull passed to CFRetain/CFRelease/CFMakeCollectable +// CHECK-NEXT: typenull passed to CF memory management function // CHECK-NEXT: issue_context_kindObjective-C method // CHECK-NEXT: issue_contexttest // CHECK-NEXT: issue_hash5 diff --git a/clang/test/Analysis/retain-release.m b/clang/test/Analysis/retain-release.m index afe997bf5d40..6973f9bcd67d 100644 --- a/clang/test/Analysis/retain-release.m +++ b/clang/test/Analysis/retain-release.m @@ -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: // CHECK-NEXT: descriptionNull pointer argument in call to CFRelease // CHECK-NEXT: categoryAPI Misuse (Apple) -// CHECK-NEXT: typenull passed to CFRetain/CFRelease/CFMakeCollectable +// CHECK-NEXT: typenull passed to CF memory management function // CHECK-NEXT: issue_context_kindfunction // CHECK-NEXT: issue_contextf16 // CHECK-NEXT: issue_hash5 @@ -9838,7 +9854,7 @@ id returnNSNull() { // CHECK-NEXT: // CHECK-NEXT: descriptionNull pointer argument in call to CFRetain // CHECK-NEXT: categoryAPI Misuse (Apple) -// CHECK-NEXT: typenull passed to CFRetain/CFRelease/CFMakeCollectable +// CHECK-NEXT: typenull passed to CF memory management function // CHECK-NEXT: issue_context_kindfunction // CHECK-NEXT: issue_contextf16 // CHECK-NEXT: issue_hash8 @@ -10175,7 +10191,7 @@ id returnNSNull() { // CHECK-NEXT: // CHECK-NEXT: descriptionNull pointer argument in call to CFMakeCollectable // CHECK-NEXT: categoryAPI Misuse (Apple) -// CHECK-NEXT: typenull passed to CFRetain/CFRelease/CFMakeCollectable +// CHECK-NEXT: typenull passed to CF memory management function // CHECK-NEXT: issue_context_kindfunction // CHECK-NEXT: issue_contextf16 // CHECK-NEXT: issue_hash11