aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp12
-rw-r--r--test/Analysis/keychainAPI.m64
2 files changed, 73 insertions, 3 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index e5f99307a5..bee27ec9ae 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -447,7 +447,8 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
// If the argument entered as an enclosing function parameter, skip it to
// avoid false positives.
- if (isEnclosingFunctionParam(ArgExpr))
+ if (isEnclosingFunctionParam(ArgExpr) &&
+ C.getLocationContext()->getParent() == 0)
return;
if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) {
@@ -481,6 +482,10 @@ void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S,
if (!retExpr)
return;
+ // If inside inlined call, skip it.
+ if (C.getLocationContext()->getParent() != 0)
+ return;
+
// Check if the value is escaping through the return.
ProgramStateRef state = C.getState();
const MemRegion *V =
@@ -549,6 +554,11 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR,
// TODO: Remove this after we ensure that checkDeadSymbols are always called.
void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &Ctx) const {
ProgramStateRef state = Ctx.getState();
+
+ // If inside inlined call, skip it.
+ if (Ctx.getLocationContext()->getParent() != 0)
+ return;
+
AllocatedSetTy AS = state->get<AllocatedData>();
if (AS.isEmpty())
return;
diff --git a/test/Analysis/keychainAPI.m b/test/Analysis/keychainAPI.m
index 613d74659f..a98ebfdf42 100644
--- a/test/Analysis/keychainAPI.m
+++ b/test/Analysis/keychainAPI.m
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -verify
+// RUN: %clang_cc1 -analyze -analyzer-checker=osx.SecKeychainAPI %s -analyzer-inline-call -verify
// Fake typedefs.
typedef unsigned int OSStatus;
@@ -133,7 +133,7 @@ void* returnContent() {
return outData;
} // no-warning
-// Password was passed in as an argument and does nt have to be deleted.
+// Password was passed in as an argument and does not have to be deleted.
OSStatus getPasswordAndItem(void** password, UInt32* passwordLength) {
OSStatus err;
SecKeychainItemRef item;
@@ -337,3 +337,63 @@ static int *bug10798(int *p, int columns, int prevRow) {
} while(10 >= row[1]);
return row;
}
+
+// Test inter-procedural behaviour.
+
+void my_FreeParam(void *attrList, void* X) {
+ SecKeychainItemFreeContent(attrList, X);
+}
+
+void *my_AllocateReturn(OSStatus *st) {
+ unsigned int *ptr = 0;
+ UInt32 length;
+ void *outData;
+ *st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+ return outData;
+}
+
+OSStatus my_Allocate_Param(void** password, UInt32* passwordLength) {
+ OSStatus err;
+ SecKeychainItemRef item;
+ err = SecKeychainFindGenericPassword(0, 3, "xx", 3, "xx",
+ passwordLength, password, &item);
+ return err;
+}
+
+void allocAndFree1() {
+ unsigned int *ptr = 0;
+ OSStatus st = 0;
+ UInt32 length;
+ void *outData;
+ st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
+ if (st == noErr)
+ my_FreeParam(ptr, outData);
+}
+
+void allocNoFree2() {
+ OSStatus st = 0;
+ void *outData = my_AllocateReturn(&st); // expected-warning{{Allocated data is not released:}}
+}
+
+void allocAndFree2(void *attrList) {
+ OSStatus st = 0;
+ void *outData = my_AllocateReturn(&st);
+ if (st == noErr)
+ my_FreeParam(attrList, outData);
+}
+
+void allocNoFree3() {
+ UInt32 length = 32;
+ void *outData;
+ OSStatus st = my_Allocate_Param(&outData, &length); // expected-warning{{Allocated data is not released}}
+}
+
+void allocAndFree3(void *attrList) {
+ UInt32 length = 32;
+ void *outData;
+ OSStatus st = my_Allocate_Param(&outData, &length);
+ if (st == noErr)
+ SecKeychainItemFreeContent(attrList, outData);
+
+}
+