Skip to content
Snippets Groups Projects
Commit c52bed18 authored by Anna Zaks's avatar Anna Zaks
Browse files

KeychainAPI checker: Generate an error on double allocation. Pull out...

KeychainAPI checker: Generate an error on double allocation. Pull out getAsPointeeMemoryRegion so that it could be reused.

llvm-svn: 136952
parent 2ced913c
No related branches found
No related tags found
No related merge requests found
...@@ -127,11 +127,26 @@ unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name, ...@@ -127,11 +127,26 @@ unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name,
return InvalidIdx; return InvalidIdx;
} }
/// Given the address expression, retrieve the value it's pointing to. Assume
/// that value is itself an address, and return the corresponding MemRegion.
static const MemRegion *getAsPointeeMemoryRegion(const Expr *Expr,
CheckerContext &C) {
const GRState *State = C.getState();
SVal ArgV = State->getSVal(Expr);
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&ArgV)) {
StoreManager& SM = C.getStoreManager();
const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion();
return V;
}
return 0;
}
void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
CheckerContext &C) const { CheckerContext &C) const {
const GRState *State = C.getState(); const GRState *State = C.getState();
const Expr *Callee = CE->getCallee(); const Expr *Callee = CE->getCallee();
SVal L = State->getSVal(Callee); SVal L = State->getSVal(Callee);
unsigned idx = InvalidIdx;
const FunctionDecl *funDecl = L.getAsFunctionDecl(); const FunctionDecl *funDecl = L.getAsFunctionDecl();
if (!funDecl) if (!funDecl)
...@@ -141,8 +156,32 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, ...@@ -141,8 +156,32 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
return; return;
StringRef funName = funI->getName(); StringRef funName = funI->getName();
// If a value has been freed, remove from the list. // If it is a call to an allocator function, it could be a double allocation.
unsigned idx = getTrackedFunctionIndex(funName, false); idx = getTrackedFunctionIndex(funName, true);
if (idx != InvalidIdx) {
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
if (const MemRegion *V = getAsPointeeMemoryRegion(ArgExpr, C))
if (const AllocationState *AS = State->get<AllocatedData>(V)) {
ExplodedNode *N = C.generateSink(State);
if (!N)
return;
initBugType();
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
os << "Allocated data should be released before another call to "
<< "the allocator: missing a call to '"
<< FunctionsToTrack[DIdx].Name
<< "'.";
RangedBugReport *Report = new RangedBugReport(*BT, os.str(), N);
Report->addRange(ArgExpr->getSourceRange());
C.EmitReport(Report);
}
return;
}
// Is it a call to one of deallocator functions?
idx = getTrackedFunctionIndex(funName, false);
if (idx == InvalidIdx) if (idx == InvalidIdx)
return; return;
...@@ -188,7 +227,8 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, ...@@ -188,7 +227,8 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
return; return;
} }
// Continue exploring from the new state. // If a value has been freed, remove it from the list and continue exploring
// from the new state.
State = State->remove<AllocatedData>(Arg); State = State->remove<AllocatedData>(Arg);
C.addTransition(State); C.addTransition(State);
} }
...@@ -198,7 +238,6 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, ...@@ -198,7 +238,6 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
const GRState *State = C.getState(); const GRState *State = C.getState();
const Expr *Callee = CE->getCallee(); const Expr *Callee = CE->getCallee();
SVal L = State->getSVal(Callee); SVal L = State->getSVal(Callee);
StoreManager& SM = C.getStoreManager();
const FunctionDecl *funDecl = L.getAsFunctionDecl(); const FunctionDecl *funDecl = L.getAsFunctionDecl();
if (!funDecl) if (!funDecl)
...@@ -214,19 +253,13 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, ...@@ -214,19 +253,13 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
return; return;
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param); const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
SVal Arg = State->getSVal(ArgExpr); if (const MemRegion *V = getAsPointeeMemoryRegion(ArgExpr, C)) {
if (const loc::MemRegionVal *X = dyn_cast<loc::MemRegionVal>(&Arg)) { // If the argument points to something that's not a region, it can be:
// Add the symbolic value, which represents the location of the allocated
// data, to the set.
const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion();
// If this is not a region, it can be:
// - unknown (cannot reason about it) // - unknown (cannot reason about it)
// - undefined (already reported by other checker) // - undefined (already reported by other checker)
// - constant (null - should not be tracked, // - constant (null - should not be tracked,
// other constant will generate a compiler warning) // other constant will generate a compiler warning)
// - goto (should be reported by other checker) // - goto (should be reported by other checker)
if (!V)
return;
// We only need to track the value if the function returned noErr(0), so // We only need to track the value if the function returned noErr(0), so
// bind the return value of the function to 0 and proceed from the no error // bind the return value of the function to 0 and proceed from the no error
...@@ -234,6 +267,8 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE, ...@@ -234,6 +267,8 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
SValBuilder &Builder = C.getSValBuilder(); SValBuilder &Builder = C.getSValBuilder();
SVal ZeroVal = Builder.makeIntVal(0, CE->getCallReturnType()); SVal ZeroVal = Builder.makeIntVal(0, CE->getCallReturnType());
const GRState *NoErr = State->BindExpr(CE, ZeroVal); const GRState *NoErr = State->BindExpr(CE, ZeroVal);
// Add the symbolic value V, which represents the location of the allocated
// data, to the set.
NoErr = NoErr->set<AllocatedData>(V, AllocationState(ArgExpr, idx)); NoErr = NoErr->set<AllocatedData>(V, AllocationState(ArgExpr, idx));
assert(NoErr); assert(NoErr);
C.addTransition(NoErr); C.addTransition(NoErr);
......
...@@ -93,11 +93,13 @@ void fooDoNotReportNull() { ...@@ -93,11 +93,13 @@ void fooDoNotReportNull() {
void doubleAlloc() { void doubleAlloc() {
unsigned int *ptr = 0; unsigned int *ptr = 0;
OSStatus st = 0; OSStatus st = 0;
UInt32 *length = 0; UInt32 length;
void **outData = 0; void *outData;
SecKeychainItemCopyContent(2, ptr, ptr, length, outData); st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData);
SecKeychainItemCopyContent(2, ptr, ptr, length, outData); st = SecKeychainItemCopyContent(2, ptr, ptr, &length, &outData); // expected-warning {{Allocated data should be released before another call to the allocator:}}
}// no-warning if (st == noErr)
SecKeychainItemFreeContent(ptr, outData);
}
void fooOnlyFree() { void fooOnlyFree() {
unsigned int *ptr = 0; unsigned int *ptr = 0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment