#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"
//===----------------------------------------------------------------------===//
// __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
// 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());
}