aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp')
-rw-r--r--lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp114
1 files changed, 70 insertions, 44 deletions
diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index b3c9955086..4934cda1ae 100644
--- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -31,6 +31,28 @@ class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
mutable llvm::OwningPtr<BugType> BT;
public:
+ /// AllocationState is a part of the checker specific state together with the
+ /// MemRegion corresponding to the allocated data.
+ struct AllocationState {
+ const Expr *Address;
+ /// The index of the allocator function.
+ unsigned int AllocatorIdx;
+ SymbolRef RetValue;
+
+ AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) :
+ Address(E),
+ AllocatorIdx(Idx),
+ RetValue(R) {}
+
+ bool operator==(const AllocationState &X) const {
+ return Address == X.Address;
+ }
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ ID.AddPointer(Address);
+ ID.AddInteger(AllocatorIdx);
+ }
+ };
+
void checkPreStmt(const CallExpr *S, CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
void checkPostStmt(const CallExpr *S, CheckerContext &C) const;
@@ -62,31 +84,11 @@ private:
};
}
-/// AllocationState is a part of the checker specific state together with the
-/// MemRegion corresponding to the allocated data.
-struct AllocationState {
- const Expr *Address;
- /// The index of the allocator function.
- unsigned int AllocatorIdx;
- SymbolRef RetValue;
-
- AllocationState(const Expr *E, unsigned int Idx, SymbolRef R) :
- Address(E),
- AllocatorIdx(Idx),
- RetValue(R) {}
-
- bool operator==(const AllocationState &X) const {
- return Address == X.Address;
- }
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddPointer(Address);
- ID.AddInteger(AllocatorIdx);
- }
-};
-
/// GRState traits to store the currently allocated (and not yet freed) symbols.
-typedef llvm::ImmutableMap<const SymbolMetadata *,
- AllocationState> AllocatedSetTy;
+/// This is a map from the allocated content symbol to the corresponding
+/// AllocationState.
+typedef llvm::ImmutableMap<SymbolRef,
+ MacOSKeychainAPIChecker::AllocationState> AllocatedSetTy;
namespace { struct AllocatedData {}; }
namespace clang { namespace ento {
@@ -134,16 +136,25 @@ unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name,
return InvalidIdx;
}
-static const SymbolMetadata *getSymbolMetadata(CheckerContext &C,
- const MemRegion *R) {
- QualType sizeTy = C.getSValBuilder().getContext().getSizeType();
- return C.getSymbolManager().getMetadataSymbol(R, 0, sizeTy, 0);
+static SymbolRef getSymbolForRegion(CheckerContext &C,
+ const MemRegion *R) {
+ if (!isa<SymbolicRegion>(R))
+ return 0;
+ return cast<SymbolicRegion>(R)->getSymbol();
}
+static bool isBadDeallocationArgument(const MemRegion *Arg) {
+ if (isa<AllocaRegion>(Arg) ||
+ isa<BlockDataRegion>(Arg) ||
+ isa<TypedRegion>(Arg)) {
+ return true;
+ }
+ return false;
+}
/// 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 SymbolMetadata *getAsPointeeMemoryRegion(const Expr *Expr,
- CheckerContext &C) {
+/// that value is itself an address, and return the corresponding symbol.
+static SymbolRef getAsPointeeSymbol(const Expr *Expr,
+ CheckerContext &C) {
const GRState *State = C.getState();
SVal ArgV = State->getSVal(Expr);
@@ -151,7 +162,7 @@ static const SymbolMetadata *getAsPointeeMemoryRegion(const Expr *Expr,
StoreManager& SM = C.getStoreManager();
const MemRegion *V = SM.Retrieve(State->getStore(), *X).getAsRegion();
if (V)
- return getSymbolMetadata(C, V);
+ return getSymbolForRegion(C, V);
}
return 0;
}
@@ -175,7 +186,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
idx = getTrackedFunctionIndex(funName, true);
if (idx != InvalidIdx) {
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
- if (const SymbolMetadata *V = getAsPointeeMemoryRegion(ArgExpr, C))
+ if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C))
if (const AllocationState *AS = State->get<AllocatedData>(V)) {
ExplodedNode *N = C.generateSink(State);
if (!N)
@@ -200,15 +211,28 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
if (idx == InvalidIdx)
return;
+ // Check the argument to the deallocator.
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
- const MemRegion *Arg = State->getSVal(ArgExpr).getAsRegion();
+ SVal ArgSVal = State->getSVal(ArgExpr);
+
+ // Undef is reported by another checker.
+ if (ArgSVal.isUndef())
+ return;
+
+ const MemRegion *Arg = ArgSVal.getAsRegion();
if (!Arg)
return;
- const SymbolMetadata *ArgSM = getSymbolMetadata(C, Arg);
+
+ SymbolRef ArgSM = getSymbolForRegion(C, Arg);
+ bool RegionArgIsBad = ArgSM ? false : isBadDeallocationArgument(Arg);
+ // If the argument is coming from the heap, globals, or unknown, do not
+ // report it.
+ if (!ArgSM && !RegionArgIsBad)
+ return;
// If trying to free data which has not been allocated yet, report as bug.
const AllocationState *AS = State->get<AllocatedData>(ArgSM);
- if (!AS) {
+ if (!AS || RegionArgIsBad) {
// It is possible that this is a false positive - the argument might
// have entered as an enclosing function parameter.
if (isEnclosingFunctionParam(ArgExpr))
@@ -243,8 +267,8 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
return;
}
- // If a value has been freed, remove it from the list and continue exploring
- // from the new state.
+ // The call is deallocating a value we previously allocated, so remove it
+ // from the next state.
State = State->remove<AllocatedData>(ArgSM);
C.addTransition(State);
}
@@ -269,14 +293,15 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
return;
const Expr *ArgExpr = CE->getArg(FunctionsToTrack[idx].Param);
- if (const SymbolMetadata *V = getAsPointeeMemoryRegion(ArgExpr, C)) {
- // If the argument points to something that's not a region, it can be:
+ if (SymbolRef V = getAsPointeeSymbol(ArgExpr, C)) {
+ // If the argument points to something that's not a symbolic region, it
+ // can be:
// - unknown (cannot reason about it)
// - undefined (already reported by other checker)
// - constant (null - should not be tracked,
// other constant will generate a compiler warning)
// - goto (should be reported by other checker)
-
+
// 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
// state.
@@ -285,8 +310,9 @@ void MacOSKeychainAPIChecker::checkPostStmt(const CallExpr *CE,
const GRState *NoErr = State->BindExpr(CE, NoErrVal);
// Add the symbolic value V, which represents the location of the allocated
// data, to the set.
- NoErr = NoErr->set<AllocatedData>(V,
- AllocationState(ArgExpr, idx, State->getSVal(CE).getAsSymbol()));
+ SymbolRef RetStatusSymbol = State->getSVal(CE).getAsSymbol();
+ NoErr = NoErr->set<AllocatedData>(V, AllocationState(ArgExpr, idx,
+ RetStatusSymbol));
assert(NoErr);
C.addTransition(NoErr);
@@ -314,7 +340,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const ReturnStmt *S,
const MemRegion *V = state->getSVal(retExpr).getAsRegion();
if (!V)
return;
- state = state->remove<AllocatedData>(getSymbolMetadata(C, V));
+ state = state->remove<AllocatedData>(getSymbolForRegion(C, V));
// Proceed from the new state.
C.addTransition(state);