diff options
Diffstat (limited to 'lib/Analysis/GRExprEngineInternalChecks.cpp')
-rw-r--r-- | lib/Analysis/GRExprEngineInternalChecks.cpp | 94 |
1 files changed, 63 insertions, 31 deletions
diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index aff58df42d..c84b6c001b 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -14,6 +14,7 @@ #include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/CheckerVisitor.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" @@ -536,54 +537,85 @@ public: //===----------------------------------------------------------------------===// // __attribute__(nonnull) checking -class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck { +class VISIBILITY_HIDDEN CheckAttrNonNull : + public CheckerVisitor<CheckAttrNonNull> { + BugType *BT; - BugReporter &BR; public: - CheckAttrNonNull(BugReporter &br) : BT(0), BR(br) {} + CheckAttrNonNull() : BT(0) {} + + const void *getTag() { + static int x = 0; + return &x; + } - virtual bool Audit(ExplodedNode<GRState>* N, GRStateManager& VMgr) { - CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt()); - const GRState* state = N->getState(); + void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) { + const GRState *state = C.getState(); + const GRState *originalState = state; + // Check if the callee has a 'nonnull' attribute. SVal X = state->getSVal(CE->getCallee()); - + const FunctionDecl* FD = X.getAsFunctionDecl(); if (!FD) - return false; + return; - const NonNullAttr* Att = FD->getAttr<NonNullAttr>(); - + const NonNullAttr* Att = FD->getAttr<NonNullAttr>(); if (!Att) - return false; + return; // Iterate through the arguments of CE and check them for null. unsigned idx = 0; - bool hasError = false; - for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; + for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E; ++I, ++idx) { - - if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx)) + + if (!Att->isNonNull(idx)) continue; - - // Lazily allocate the BugType object if it hasn't already been created. - // Ownership is transferred to the BugReporter object once the BugReport - // is passed to 'EmitWarning'. - if (!BT) BT = - new BugType("Argument with 'nonnull' attribute passed null", "API"); - RangedBugReport *R = new RangedBugReport(*BT, - "Null pointer passed as an argument to a " - "'nonnull' parameter", N); - - R->addRange((*I)->getSourceRange()); - BR.EmitReport(R); - hasError = true; + ConstraintManager &CM = C.getConstraintManager(); + const GRState *stateNotNull, *stateNull; + llvm::tie(stateNotNull, stateNull) = CM.AssumeDual(state, + state->getSVal(*I)); + + if (stateNull && !stateNotNull) { + // Generate an error node. Check for a null node in case + // we cache out. + if (ExplodedNode<GRState> *errorNode = C.generateNode(CE, stateNull)) { + + // Lazily allocate the BugType object if it hasn't already been + // created. Ownership is transferred to the BugReporter object once + // the BugReport is passed to 'EmitWarning'. + if (!BT) + BT = new BugType("Argument with 'nonnull' attribute passed null", + "API"); + + RangedBugReport *R = + new RangedBugReport(*BT, "Null pointer passed as an argument to a " + "'nonnull' parameter", errorNode); + + // Highlight the range of the argument that was null. + R->addRange((*I)->getSourceRange()); + + // Emit the bug report. + C.EmitReport(R); + } + + // Always return. Either we cached out or we just emitted an error. + return; + } + + // If a pointer value passed the check we should assume that it is + // indeed not null from this point forward. + assert(stateNotNull); + state = stateNotNull; } - - return hasError; + + // If we reach here all of the arguments passed the nonnull check. + // If 'state' has been updated generated a new node. + if (state != originalState) + C.generateNode(CE, state); } }; } // end anonymous namespace @@ -619,5 +651,5 @@ void GRExprEngine::RegisterInternalChecks() { // their associated BugType will get registered with the BugReporter // automatically. Note that the check itself is owned by the GRExprEngine // object. - AddCheck(new CheckAttrNonNull(BR), Stmt::CallExprClass); + registerCheck(new CheckAttrNonNull()); } |