[cfe-commits] [PATCH][Review request]Support for c++0x nullptr in static analyzer
Jim Goodnow II
Jim at TheGoodnows.net
Tue Apr 19 21:13:21 PDT 2011
Ok, here's a stab at implementing support for the C++ nullptr in the
static analyzer. There's also a test file. Please review and give any
feedback.
- jim
Index: include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
(revision 129845)
+++ include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
(working copy)
@@ -150,6 +150,10 @@
DefinedSVal getBlockPointer(const BlockDecl *block, CanQualType locTy,
const LocationContext *locContext);
+ DefinedSVal makeNullPtrVal( void ) {
+ return nonloc::NullPtrVal();
+ }
+
NonLoc makeCompoundVal(QualType type, llvm::ImmutableList<SVal> vals) {
return nonloc::CompoundVal(BasicVals.getCompoundValData(type, vals));
}
Index: include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (revision
129845)
+++ include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h (working
copy)
@@ -276,7 +276,8 @@
namespace nonloc {
enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
- LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
+ LocAsIntegerKind, CompoundValKind, LazyCompoundValKind,
+ NullPtrValKind };
class SymbolVal : public NonLoc {
public:
@@ -420,6 +421,27 @@
}
};
+// Specail SVal class for C0xx nullptr.
+class NullPtrVal : public NonLoc {
+ friend class ento::SValBuilder;
+
+ explicit NullPtrVal( void) :
+ NonLoc(NullPtrValKind, NULL) {
+ }
+
+public:
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == NullPtrValKind;
+ }
+
+ static inline bool classof(const Loc* V) {
+ return V->getSubKind() == NullPtrValKind;
+ }
+};
+
} // end namespace ento::nonloc
//==------------------------------------------------------------------------==//
Index: lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp (revision 129845)
+++ lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp (working copy)
@@ -85,7 +85,7 @@
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
// Check for null dereferences.
- if (!isa<Loc>(location))
+ if (!isa<Loc>(location) && !isa<nonloc::NullPtrVal>(location))
return;
const Stmt *S = C.getStmt();
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp (revision 129845)
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp (working copy)
@@ -424,7 +424,6 @@
case Stmt::CXXCatchStmtClass:
case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXForRangeStmtClass:
- case Stmt::CXXNullPtrLiteralExprClass:
case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXThrowExprClass:
@@ -523,6 +522,7 @@
case Stmt::ExprWithCleanupsClass:
case Stmt::FloatingLiteralClass:
case Stmt::SizeOfPackExprClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
Dst.Add(Pred); // No-op. Simply propagate the current state
unchanged.
break;
Index: lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (revision 129845)
+++ lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (working copy)
@@ -89,6 +89,10 @@
return UnknownVal();
}
+ // Special C0xx nullptr case, just return it.
+ if (isa<nonloc::NullPtrVal>(val))
+ return val;
+
if (!isa<nonloc::ConcreteInt>(val))
return UnknownVal();
@@ -293,6 +297,16 @@
return evalCastFromNonLoc(lhs, resultTy);
}
+ // For nullptr, assume that only exact comparison is legal
+ // for which we know the result for all cases, otherwise,
+ // the result is unknown and should be caught by a checker.
+ if (isa<nonloc::NullPtrVal>(rhs)) {
+ if (op == BO_EQ)
+ return makeTruthVal(false, resultTy);
+ if (op == BO_NE)
+ return makeTruthVal(true, resultTy);
+ return UnknownVal();
+ }
while (1) {
switch (lhs.getSubKind()) {
default:
@@ -803,6 +817,7 @@
// If we get here, we have no way of comparing the regions.
return UnknownVal();
}
+
}
}
@@ -831,8 +846,20 @@
return evalBinOpLL(state, op, lhs, loc::ConcreteInt(*x),
resultTy);
}
}
+ if (isa<nonloc::NullPtrVal>(rhs)) {
+ // We know for sure that the two fields are not the same, since lhs
+ // is a Loc.
+ if (op == BO_EQ)
+ return makeTruthVal(false, resultTy);
+ if (op == BO_NE)
+ return makeTruthVal(true, resultTy);
+ }
}
+ // any other op with nullptr is bad
+ if (isa<nonloc::NullPtrVal>(rhs))
+ return UnknownVal();
+
// We are dealing with pointer arithmetic.
// Handle pointer arithmetic on constant values.
Index: lib/StaticAnalyzer/Core/SVals.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SVals.cpp (revision 129845)
+++ lib/StaticAnalyzer/Core/SVals.cpp (working copy)
@@ -338,6 +338,9 @@
<< '}';
break;
}
+ case nonloc::NullPtrValKind:
+ os << "NullPtrVal";
+ break;
default:
assert (false && "Pretty-printed not implemented for this NonLoc.");
break;
Index: lib/StaticAnalyzer/Core/Environment.cpp
===================================================================
--- lib/StaticAnalyzer/Core/Environment.cpp (revision 129845)
+++ lib/StaticAnalyzer/Core/Environment.cpp (working copy)
@@ -64,6 +64,9 @@
else
return svalBuilder.makeIntVal(cast<IntegerLiteral>(E));
}
+ // For special C0xx nullptr case, make a null pointer SVal.
+ case Stmt::CXXNullPtrLiteralExprClass:
+ return svalBuilder.makeNullPtrVal();
case Stmt::ImplicitCastExprClass:
case Stmt::CXXFunctionalCastExprClass:
case Stmt::CStyleCastExprClass: {
Index: lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
===================================================================
--- lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp (revision 129845)
+++ lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp (working copy)
@@ -196,6 +196,10 @@
return isFeasible ? state : NULL;
}
+ // Reverse assumption for special C0xx nullptr case.
+ case nonloc::NullPtrValKind:
+ return Assumption ? NULL : state;
+
case nonloc::LocAsIntegerKind:
return assumeAux(state, cast<nonloc::LocAsInteger>(Cond).getLoc(),
Assumption);
Index: lib/StaticAnalyzer/Core/Store.cpp
===================================================================
--- lib/StaticAnalyzer/Core/Store.cpp (revision 129845)
+++ lib/StaticAnalyzer/Core/Store.cpp (working copy)
@@ -238,7 +238,7 @@
}
SVal StoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
- if (Base.isUnknownOrUndef())
+ if (Base.isUnknownOrUndef() || isa<nonloc::NullPtrVal>(Base))
return Base;
Loc BaseL = cast<Loc>(Base);
@@ -280,7 +280,9 @@
// FIXME: For absolute pointer addresses, we just return that value
back as
// well, although in reality we should return the offset added to that
// value.
- if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base))
+ // Also, for nullptr, just return the base. Checker should detect this.
+ if (Base.isUnknownOrUndef() || isa<loc::ConcreteInt>(Base) ||
+ isa<nonloc::NullPtrVal>(Base))
return Base;
const MemRegion* BaseRegion = cast<loc::MemRegionVal>(Base).getRegion();
=====================
test/Analysis/nullptr.cpp
=====================
// RUN: %clang_cc1 -std=c++0x -analyze -analyzer-checker=core
-analyzer-inline-call -analyzer-store region -verify %s
// test to see if nullptr is detected as a null pointer
void foo1(void) {
char *np = nullptr;
*np = 0; // expected-warning{{Dereference of null pointer}}
}
// check if comparing nullptr to nullptr is detected properly
void foo2(void) {
char *np1 = nullptr;
char *np2 = np1;
char c;
if (np1 == np2)
np1 = &c;
*np1 = 0; // no-warning
}
// invoving a nullptr in a more complex operation should be cause a warning
void foo3(void) {
struct foo {
int a, f;
};
char *np = nullptr;
// casting a nullptr to anything should be caught eventually
int *ip = &(((struct foo *)np)->f);
*ip = 0; // expected-warning{{Dereference of null pointer}}
// should be error here too, but analysis gets stopped
// *np = 0;
}
#ifdef TEST_THIS
// check to determine if the correct function is picked
// which was the whole point of the nullptr to begin with
// FIXME: disabled for now until inline-call works again
struct A {
int x;
A(int a) { x = a; }
A(int *ip) { x = 1; }
int getx() const { return x; }
};
void f1() {
A x((int *)0);
if (x.getx() == 0) {
int *p = 0;
*p = 3; // warning
} else {
int *p = 0;
*p = 3; // no-warning
}
}
void f2() {
A x(nullptr);
if (x.getx() == 1) {
int *p = 0;
*p = 3; // warning
} else {
int *p = 0;
*p = 3; // no-warning
}
}
#endif
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: nullptr.cpp
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20110419/bfb565fd/attachment.ksh>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: NullPtr.patch
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20110419/bfb565fd/attachment-0001.ksh>
More information about the cfe-commits
mailing list