[cfe-commits] r76797 - in /cfe/trunk: lib/Analysis/GRExprEngineInternalChecks.cpp test/Analysis/null-deref-ps.c
Ted Kremenek
kremenek at apple.com
Wed Jul 22 14:46:56 PDT 2009
Author: kremenek
Date: Wed Jul 22 16:46:56 2009
New Revision: 76797
URL: http://llvm.org/viewvc/llvm-project?rev=76797&view=rev
Log:
Migrate the path-sensitive checking of 'nonnull' arguments over to the new
'Checker' interface. An updated test case illustrates that after calling a
function with the 'nonnull' attribute we now register the fact that the passed
pointer must be non-null. This retention of information was not possible with
the previously used GRSimpleAPICheck interface.
Modified:
cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp
cfe/trunk/test/Analysis/null-deref-ps.c
Modified: cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp?rev=76797&r1=76796&r2=76797&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngineInternalChecks.cpp Wed Jul 22 16:46:56 2009
@@ -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 @@
//===----------------------------------------------------------------------===//
// __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 @@
// 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());
}
Modified: cfe/trunk/test/Analysis/null-deref-ps.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/null-deref-ps.c?rev=76797&r1=76796&r2=76797&view=diff
==============================================================================
--- cfe/trunk/test/Analysis/null-deref-ps.c (original)
+++ cfe/trunk/test/Analysis/null-deref-ps.c Wed Jul 22 16:46:56 2009
@@ -105,6 +105,15 @@
: bar3(p, 2, q); // no-warning
}
+int f6d(int *p) {
+ bar(p, 0);
+ // At this point, 'p' cannot be null.
+ if (!p) {
+ int *q = 0;
+ *q = 0xDEADBEEF; // no-warning
+ }
+}
+
int* qux();
int f7(int x) {
More information about the cfe-commits
mailing list