summaryrefslogtreecommitdiffstats
path: root/lib/Checker
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Checker')
-rw-r--r--lib/Checker/BasicObjCFoundationChecks.cpp41
-rw-r--r--lib/Checker/BasicStore.cpp2
-rw-r--r--lib/Checker/BugReporter.cpp2
-rw-r--r--lib/Checker/BugReporterVisitors.cpp14
-rw-r--r--lib/Checker/CFRefCount.cpp115
-rw-r--r--lib/Checker/CMakeLists.txt1
-rw-r--r--lib/Checker/CallAndMessageChecker.cpp19
-rw-r--r--lib/Checker/CastToStructChecker.cpp2
-rw-r--r--lib/Checker/CheckObjCDealloc.cpp30
-rw-r--r--lib/Checker/CheckObjCInstMethSignature.cpp6
-rw-r--r--lib/Checker/CheckSecuritySyntaxOnly.cpp12
-rw-r--r--lib/Checker/Environment.cpp7
-rw-r--r--lib/Checker/GRCXXExprEngine.cpp246
-rw-r--r--lib/Checker/GRCoreEngine.cpp27
-rw-r--r--lib/Checker/GRExprEngine.cpp369
-rw-r--r--lib/Checker/MemRegion.cpp21
-rw-r--r--lib/Checker/NSAutoreleasePoolChecker.cpp2
-rw-r--r--lib/Checker/NSErrorChecker.cpp2
-rw-r--r--lib/Checker/ObjCUnusedIVarsChecker.cpp3
-rw-r--r--lib/Checker/RegionStore.cpp44
-rw-r--r--lib/Checker/SVals.cpp3
-rw-r--r--lib/Checker/SimpleSValuator.cpp22
-rw-r--r--lib/Checker/Store.cpp22
-rw-r--r--lib/Checker/UnixAPIChecker.cpp85
24 files changed, 685 insertions, 412 deletions
diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index 810d0fb..e7275ca 100644
--- a/lib/Checker/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -31,13 +31,22 @@
using namespace clang;
static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
- const Expr* Receiver = ME->getReceiver();
-
- if (!Receiver)
- return NULL;
+ QualType T;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ T = ME->getInstanceReceiver()->getType();
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ T = ME->getSuperType();
+ break;
+
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ return 0;
+ }
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
+ if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
return PT->getInterfaceType();
return NULL;
@@ -509,11 +518,21 @@ public:
void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
-
- const IdentifierInfo *ClsName = ME->getClassName();
- if (!ClsName)
+ ObjCInterfaceDecl *Class = 0;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::Instance:
+ case ObjCMessageExpr::SuperInstance:
return;
-
+ }
+
Selector S = ME->getSelector();
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return;
@@ -531,7 +550,7 @@ void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
llvm::raw_svector_ostream os(buf);
os << "The '" << S.getAsString() << "' message should be sent to instances "
- "of class '" << ClsName->getName()
+ "of class '" << Class->getName()
<< "' and not the class directly";
RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
diff --git a/lib/Checker/BasicStore.cpp b/lib/Checker/BasicStore.cpp
index 7c53991..34470af 100644
--- a/lib/Checker/BasicStore.cpp
+++ b/lib/Checker/BasicStore.cpp
@@ -401,7 +401,7 @@ Store BasicStoreManager::BindDeclInternal(Store store, const VarRegion* VR,
const VarDecl *VD = VR->getDecl();
// BasicStore does not model arrays and structs.
- if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
+ if (VD->getType()->isArrayType() || VD->getType()->isStructureOrClassType())
return store;
if (VD->hasGlobalStorage()) {
diff --git a/lib/Checker/BugReporter.cpp b/lib/Checker/BugReporter.cpp
index 4475872..3bcc03f 100644
--- a/lib/Checker/BugReporter.cpp
+++ b/lib/Checker/BugReporter.cpp
@@ -607,7 +607,7 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD,
if (D) {
GetRawInt = false;
- os << D->getNameAsString();
+ os << D;
}
}
diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 06cee5b..776e12b 100644
--- a/lib/Checker/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -47,14 +47,6 @@ const Stmt *clang::bugreporter::GetDerefExpr(const ExplodedNode *N) {
}
const Stmt*
-clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
- const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
- if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
- return ME->getReceiver();
- return NULL;
-}
-
-const Stmt*
clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
@@ -144,7 +136,7 @@ public:
if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) {
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "Variable '" << VR->getDecl()->getNameAsString() << "' ";
+ os << "Variable '" << VR->getDecl() << "' ";
}
else
return NULL;
@@ -206,7 +198,7 @@ public:
return NULL;
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << '\'' << VR->getDecl()->getNameAsString() << '\'';
+ os << '\'' << VR->getDecl() << '\'';
}
else
return NULL;
@@ -402,7 +394,7 @@ public:
const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
if (!ME)
return 0;
- const Expr *Receiver = ME->getReceiver();
+ const Expr *Receiver = ME->getInstanceReceiver();
if (!Receiver)
return 0;
const GRState *state = N->getState();
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index 3c4a27c..d26ee1d 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -603,12 +603,33 @@ public:
Selector S = ME->getSelector();
- if (Expr* Receiver = ME->getReceiver()) {
- const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
- return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+ const ObjCInterfaceDecl* OD = 0;
+ bool IsInstanceMessage = false;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance:
+ OD = getReceiverDecl(ME->getInstanceReceiver());
+ IsInstanceMessage = true;
+ break;
+
+ case ObjCMessageExpr::SuperInstance:
+ IsInstanceMessage = true;
+ OD = ME->getSuperType()->getAs<ObjCObjectPointerType>()
+ ->getInterfaceDecl();
+ break;
+
+ case ObjCMessageExpr::Class:
+ OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
+
+ case ObjCMessageExpr::SuperClass:
+ OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+ break;
}
- return M[ObjCSummaryKey(ME->getClassName(), S)];
+ if (IsInstanceMessage)
+ return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+
+ return M[ObjCSummaryKey(OD->getIdentifier(), S)];
}
RetainSummary*& operator[](ObjCSummaryKey K) {
@@ -836,7 +857,7 @@ public:
RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
const ObjCInterfaceDecl* ID) {
- return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
+ return getInstanceMethodSummary(ME->getSelector(), 0,
ID, ME->getMethodDecl(), ME->getType());
}
@@ -851,8 +872,21 @@ public:
QualType RetTy);
RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
- return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
- ME->getClassInfo().Decl,
+ ObjCInterfaceDecl *Class = 0;
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Class:
+ case ObjCMessageExpr::SuperClass:
+ Class = ME->getReceiverInterface();
+ break;
+
+ case ObjCMessageExpr::Instance:
+ case ObjCMessageExpr::SuperInstance:
+ break;
+ }
+
+ return getClassMethodSummary(ME->getSelector(),
+ Class? Class->getIdentifier() : 0,
+ Class,
ME->getMethodDecl(), ME->getType());
}
@@ -1333,37 +1367,44 @@ RetainSummaryManager::getInstanceMethodSummary(const ObjCMessageExpr *ME,
// We need the type-information of the tracked receiver object
// Retrieve it from the state.
- const Expr *Receiver = ME->getReceiver();
+ const Expr *Receiver = ME->getInstanceReceiver();
const ObjCInterfaceDecl* ID = 0;
// FIXME: Is this really working as expected? There are cases where
// we just use the 'ID' from the message expression.
- SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
+ SVal receiverV;
+
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ receiverV = state->getSValAsScalarOrLoc(Receiver);
- // FIXME: Eventually replace the use of state->get<RefBindings> with
- // a generic API for reasoning about the Objective-C types of symbolic
- // objects.
- if (SymbolRef Sym = receiverV.getAsLocSymbol())
- if (const RefVal *T = state->get<RefBindings>(Sym))
- if (const ObjCObjectPointerType* PT =
+ // FIXME: Eventually replace the use of state->get<RefBindings> with
+ // a generic API for reasoning about the Objective-C types of symbolic
+ // objects.
+ if (SymbolRef Sym = receiverV.getAsLocSymbol())
+ if (const RefVal *T = state->get<RefBindings>(Sym))
+ if (const ObjCObjectPointerType* PT =
T->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
+ ID = PT->getInterfaceDecl();
- // FIXME: this is a hack. This may or may not be the actual method
- // that is called.
- if (!ID) {
- if (const ObjCObjectPointerType *PT =
- Receiver->getType()->getAs<ObjCObjectPointerType>())
- ID = PT->getInterfaceDecl();
+ // FIXME: this is a hack. This may or may not be the actual method
+ // that is called.
+ if (!ID) {
+ if (const ObjCObjectPointerType *PT =
+ Receiver->getType()->getAs<ObjCObjectPointerType>())
+ ID = PT->getInterfaceDecl();
+ }
+ } else {
+ // FIXME: Hack for 'super'.
+ ID = ME->getReceiverInterface();
}
-
+
// FIXME: The receiver could be a reference to a class, meaning that
// we should use the class method.
RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
// Special-case: are we sending a mesage to "self"?
// This is a hack. When we have full-IP this should be removed.
- if (isa<ObjCMethodDecl>(LC->getDecl())) {
+ if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) {
if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
// Get the region associated with 'self'.
if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
@@ -2081,7 +2122,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
// Get the name of the callee (if it is available).
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee());
if (const FunctionDecl* FD = X.getAsFunctionDecl())
- os << "Call to function '" << FD->getNameAsString() <<'\'';
+ os << "Call to function '" << FD << '\'';
else
os << "function call";
}
@@ -2144,7 +2185,7 @@ PathDiagnosticPiece* CFRefReport::VisitNode(const ExplodedNode* N,
}
}
else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
- if (const Expr *receiver = ME->getReceiver())
+ if (const Expr *receiver = ME->getInstanceReceiver())
if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
// The symbol we are tracking is the receiver.
AEffects.push_back(Summ->getReceiverEffect());
@@ -2510,7 +2551,7 @@ static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
// id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
// is a call to a class method whose type we can resolve. In such
// cases, promote the return type to XXX* (where XXX is the class).
- const ObjCInterfaceDecl *D = ME->getClassInfo().Decl;
+ const ObjCInterfaceDecl *D = ME->getReceiverInterface();
return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
}
@@ -2660,15 +2701,15 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
RetEffect RE = Summ.getRetEffect();
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
- assert(Receiver);
- SVal V = state->getSValAsScalarOrLoc(Receiver);
bool found = false;
- if (SymbolRef Sym = V.getAsLocSymbol())
- if (state->get<RefBindings>(Sym)) {
- found = true;
- RE = Summaries.getObjAllocRetEffect();
- }
-
+ if (Receiver) {
+ SVal V = state->getSValAsScalarOrLoc(Receiver);
+ if (SymbolRef Sym = V.getAsLocSymbol())
+ if (state->get<RefBindings>(Sym)) {
+ found = true;
+ RE = Summaries.getObjAllocRetEffect();
+ }
+ } // FIXME: Otherwise, this is a send-to-super instance message.
if (!found)
RE = RetEffect::MakeNoRet();
}
@@ -2802,12 +2843,12 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
ExplodedNode* Pred,
const GRState *state) {
RetainSummary *Summ =
- ME->getReceiver()
+ ME->isInstanceMessage()
? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
: Summaries.getClassMethodSummary(ME);
assert(Summ && "RetainSummary is null");
- EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
+ EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL,
ME->arg_begin(), ME->arg_end(), Pred, state);
}
diff --git a/lib/Checker/CMakeLists.txt b/lib/Checker/CMakeLists.txt
index dec375e..82e93a4 100644
--- a/lib/Checker/CMakeLists.txt
+++ b/lib/Checker/CMakeLists.txt
@@ -31,6 +31,7 @@ add_clang_library(clangChecker
FlatStore.cpp
GRBlockCounter.cpp
GRCoreEngine.cpp
+ GRCXXExprEngine.cpp
GRExprEngine.cpp
GRExprEngineExperimentalChecks.cpp
GRState.cpp
diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index dd1856c9..c619d75 100644
--- a/lib/Checker/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -154,8 +154,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
os << "Passed-by-value struct argument contains uninitialized data";
if (F.FieldChain.size() == 1)
- os << " (e.g., field: '" << F.FieldChain[0]->getNameAsString()
- << "')";
+ os << " (e.g., field: '" << F.FieldChain[0] << "')";
else {
os << " (e.g., via the field chain: '";
bool first = true;
@@ -165,7 +164,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
first = false;
else
os << '.';
- os << (*DI)->getNameAsString();
+ os << *DI;
}
os << "')";
}
@@ -219,7 +218,8 @@ void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const GRState *state = C.getState();
- if (const Expr *receiver = ME->getReceiver())
+ // FIXME: Handle 'super'?
+ if (const Expr *receiver = ME->getInstanceReceiver())
if (state->getSVal(receiver).isUndef()) {
if (ExplodedNode *N = C.GenerateSink()) {
if (!BT_msg_undef)
@@ -266,10 +266,11 @@ void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
<< ME->getType().getAsString() << "' that will be garbage";
EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
- const Expr *receiver = ME->getReceiver();
- report->addRange(receiver->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- receiver);
+ if (const Expr *receiver = ME->getInstanceReceiver()) {
+ report->addRange(receiver->getSourceRange());
+ report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+ receiver);
+ }
C.EmitReport(report);
}
@@ -289,7 +290,7 @@ void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
ASTContext &Ctx = C.getASTContext();
CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
- if (CanRetTy->isStructureType()) {
+ if (CanRetTy->isStructureOrClassType()) {
// FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
// have the "use of undefined value" be smarter about where the
// undefined value came from.
diff --git a/lib/Checker/CastToStructChecker.cpp b/lib/Checker/CastToStructChecker.cpp
index 2c16f89..eeaed97 100644
--- a/lib/Checker/CastToStructChecker.cpp
+++ b/lib/Checker/CastToStructChecker.cpp
@@ -51,7 +51,7 @@ void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
QualType OrigPointeeTy = OrigPTy->getPointeeType();
QualType ToPointeeTy = ToPTy->getPointeeType();
- if (!ToPointeeTy->isStructureType())
+ if (!ToPointeeTy->isStructureOrClassType())
return;
// We allow cast from void*.
diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp
index d9606f1..c23be87 100644
--- a/lib/Checker/CheckObjCDealloc.cpp
+++ b/lib/Checker/CheckObjCDealloc.cpp
@@ -27,10 +27,14 @@ using namespace clang;
static bool scan_dealloc(Stmt* S, Selector Dealloc) {
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getSelector() == Dealloc)
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
- return isa<ObjCSuperExpr>(Receiver);
+ if (ME->getSelector() == Dealloc) {
+ switch (ME->getReceiverKind()) {
+ case ObjCMessageExpr::Instance: return false;
+ case ObjCMessageExpr::SuperInstance: return true;
+ case ObjCMessageExpr::Class: break;
+ case ObjCMessageExpr::SuperClass: break;
+ }
+ }
// Recurse to children.
@@ -50,16 +54,16 @@ static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
// [mMyIvar release]
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
if (ME->getSelector() == Release)
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (ME->getInstanceReceiver())
+ if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
if (E->getDecl() == ID)
return true;
// [self setMyIvar:nil];
if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getReceiver())
- if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+ if (ME->getInstanceReceiver())
+ if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
if (E->getDecl()->getIdentifier() == SelfII)
if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
@@ -166,8 +170,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
std::string buf;
llvm::raw_string_ostream os(buf);
- os << "Objective-C class '" << D->getNameAsString()
- << "' lacks a 'dealloc' instance method";
+ os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method";
BR.EmitBasicReport(name, os.str(), D->getLocStart());
return;
@@ -182,8 +185,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
std::string buf;
llvm::raw_string_ostream os(buf);
- os << "The 'dealloc' instance method in Objective-C class '"
- << D->getNameAsString()
+ os << "The 'dealloc' instance method in Objective-C class '" << D
<< "' does not send a 'dealloc' message to its super class"
" (missing [super dealloc])";
@@ -238,7 +240,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
? "missing ivar release (leak)"
: "missing ivar release (Hybrid MM, non-GC)";
- os << "The '" << ID->getNameAsString()
+ os << "The '" << ID
<< "' instance variable was retained by a synthesized property but "
"wasn't released in 'dealloc'";
} else {
@@ -246,7 +248,7 @@ void clang::CheckObjCDealloc(const ObjCImplementationDecl* D,
? "extra ivar release (use-after-release)"
: "extra ivar release (Hybrid MM, non-GC)";
- os << "The '" << ID->getNameAsString()
+ os << "The '" << ID
<< "' instance variable was not retained by a synthesized property "
"but was released in 'dealloc'";
}
diff --git a/lib/Checker/CheckObjCInstMethSignature.cpp b/lib/Checker/CheckObjCInstMethSignature.cpp
index 8c43a45..76a0923 100644
--- a/lib/Checker/CheckObjCInstMethSignature.cpp
+++ b/lib/Checker/CheckObjCInstMethSignature.cpp
@@ -49,16 +49,16 @@ static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
llvm::raw_string_ostream os(sbuf);
os << "The Objective-C class '"
- << MethDerived->getClassInterface()->getNameAsString()
+ << MethDerived->getClassInterface()
<< "', which is derived from class '"
- << MethAncestor->getClassInterface()->getNameAsString()
+ << MethAncestor->getClassInterface()
<< "', defines the instance method '"
<< MethDerived->getSelector().getAsString()
<< "' whose return type is '"
<< ResDerived.getAsString()
<< "'. A method with the same name (same selector) is also defined in "
"class '"
- << MethAncestor->getClassInterface()->getNameAsString()
+ << MethAncestor->getClassInterface()
<< "' and has a return type of '"
<< ResAncestor.getAsString()
<< "'. These two types are incompatible, and may result in undefined "
diff --git a/lib/Checker/CheckSecuritySyntaxOnly.cpp b/lib/Checker/CheckSecuritySyntaxOnly.cpp
index efbce61..74e12b1 100644
--- a/lib/Checker/CheckSecuritySyntaxOnly.cpp
+++ b/lib/Checker/CheckSecuritySyntaxOnly.cpp
@@ -387,11 +387,11 @@ void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
// Issue a warning.
llvm::SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
- os1 << "'" << FD->getNameAsString() << "' is a poor random number generator";
+ os1 << '\'' << FD << "' is a poor random number generator";
llvm::SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
- os2 << "Function '" << FD->getNameAsString()
+ os2 << "Function '" << FD
<< "' is obsolete because it implements a poor random number generator."
<< " Use 'arc4random' instead";
@@ -472,14 +472,12 @@ void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
// Issue a warning.
llvm::SmallString<256> buf1;
llvm::raw_svector_ostream os1(buf1);
- os1 << "Return value is not checked in call to '" << FD->getNameAsString()
- << "'";
+ os1 << "Return value is not checked in call to '" << FD << '\'';
llvm::SmallString<256> buf2;
llvm::raw_svector_ostream os2(buf2);
- os2 << "The return value from the call to '" << FD->getNameAsString()
- << "' is not checked. If an error occurs in '"
- << FD->getNameAsString()
+ os2 << "The return value from the call to '" << FD
+ << "' is not checked. If an error occurs in '" << FD
<< "', the following code may execute with unexpected privileges";
SourceRange R = CE->getCallee()->getSourceRange();
diff --git a/lib/Checker/Environment.cpp b/lib/Checker/Environment.cpp
index be1a677..addfc21 100644
--- a/lib/Checker/Environment.cpp
+++ b/lib/Checker/Environment.cpp
@@ -37,6 +37,13 @@ SVal Environment::GetSVal(const Stmt *E, ValueManager& ValMgr) const {
return ValMgr.makeIntVal(C->getValue(), C->getType());
}
+ case Stmt::CXXBoolLiteralExprClass: {
+ const SVal *X = ExprBindings.lookup(E);
+ if (X)
+ return *X;
+ else
+ return ValMgr.makeIntVal(cast<CXXBoolLiteralExpr>(E));
+ }
case Stmt::IntegerLiteralClass: {
// In C++, this expression may have been bound to a temporary object.
SVal const *X = ExprBindings.lookup(E);
diff --git a/lib/Checker/GRCXXExprEngine.cpp b/lib/Checker/GRCXXExprEngine.cpp
new file mode 100644
index 0000000..00ac995
--- /dev/null
+++ b/lib/Checker/GRCXXExprEngine.cpp
@@ -0,0 +1,246 @@
+//===- GRCXXExprEngine.cpp - C++ expr evaluation engine ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the C++ expression evaluation engine.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/AST/DeclCXX.h"
+
+using namespace clang;
+
+void GRExprEngine::EvalArguments(ExprIterator AI, ExprIterator AE,
+ const FunctionProtoType *FnType,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ llvm::SmallVector<CallExprWLItem, 20> WorkList;
+ WorkList.reserve(AE - AI);
+ WorkList.push_back(CallExprWLItem(AI, Pred));
+
+ while (!WorkList.empty()) {
+ CallExprWLItem Item = WorkList.back();
+ WorkList.pop_back();
+
+ if (Item.I == AE) {
+ Dst.insert(Item.N);
+ continue;
+ }
+
+ ExplodedNodeSet Tmp;
+ const unsigned ParamIdx = Item.I - AI;
+ bool VisitAsLvalue = FnType? FnType->getArgType(ParamIdx)->isReferenceType()
+ : false;
+ if (VisitAsLvalue)
+ VisitLValue(*Item.I, Item.N, Tmp);
+ else
+ Visit(*Item.I, Item.N, Tmp);
+
+ ++(Item.I);
+ for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
+ WorkList.push_back(CallExprWLItem(Item.I, *NI));
+ }
+}
+
+const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
+ const StackFrameContext *SFC) {
+ Type *T = D->getParent()->getTypeForDecl();
+ QualType PT = getContext().getPointerType(QualType(T,0));
+ return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
+}
+
+void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ ExplodedNodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+ for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+
+ // Bind the temporary object to the value of the expression. Then bind
+ // the expression to the location of the object.
+ SVal V = state->getSVal(Ex);
+
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXObjectRegion(Ex,
+ Pred->getLocationContext());
+
+ state = state->bindLoc(loc::MemRegionVal(R), V);
+ MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
+ }
+}
+
+void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ if (E->isElidable()) {
+ VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
+ return;
+ }
+
+ const CXXConstructorDecl *CD = E->getConstructor();
+ assert(CD);
+
+ if (!CD->isThisDeclarationADefinition())
+ // FIXME: invalidate the object.
+ return;
+
+
+ // Evaluate other arguments.
+ ExplodedNodeSet ArgsEvaluated;
+ const FunctionProtoType *FnType = CD->getType()->getAs<FunctionProtoType>();
+ EvalArguments(const_cast<CXXConstructExpr*>(E)->arg_begin(),
+ const_cast<CXXConstructExpr*>(E)->arg_end(),
+ FnType, Pred, ArgsEvaluated);
+ // The callee stack frame context used to create the 'this' parameter region.
+ const StackFrameContext *SFC = AMgr.getStackFrame(CD,
+ Pred->getLocationContext(),
+ E, Builder->getBlock(), Builder->getIndex());
+
+ const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
+
+ CallEnter Loc(E, CD, Pred->getLocationContext());
+ for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
+ NE = ArgsEvaluated.end(); NI != NE; ++NI) {
+ const GRState *state = GetState(*NI);
+ // Setup 'this' region.
+ state = state->bindLoc(loc::MemRegionVal(ThisR), Dest);
+ ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
+ if (N)
+ Dst.Add(N);
+ }
+}
+
+void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
+ ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Get the method type.
+ const FunctionProtoType *FnType =
+ MCE->getCallee()->getType()->getAs<FunctionProtoType>();
+ assert(FnType && "Method type not available");
+
+ // Evaluate explicit arguments with a worklist.
+ ExplodedNodeSet ArgsEvaluated;
+ EvalArguments(const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
+ const_cast<CXXMemberCallExpr*>(MCE)->arg_end(),
+ FnType, Pred, ArgsEvaluated);
+
+ // Evaluate the implicit object argument.
+ ExplodedNodeSet AllArgsEvaluated;
+ const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
+ if (!ME)
+ return;
+ Expr *ObjArgExpr = ME->getBase();
+ for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
+ E = ArgsEvaluated.end(); I != E; ++I) {
+ if (ME->isArrow())
+ Visit(ObjArgExpr, *I, AllArgsEvaluated);
+ else
+ VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
+ }
+
+ const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
+ assert(MD && "not a CXXMethodDecl?");
+
+ if (!MD->isThisDeclarationADefinition())
+ // FIXME: conservative method call evaluation.
+ return;
+
+ const StackFrameContext *SFC = AMgr.getStackFrame(MD,
+ Pred->getLocationContext(),
+ MCE,
+ Builder->getBlock(),
+ Builder->getIndex());
+ const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
+ CallEnter Loc(MCE, MD, Pred->getLocationContext());
+ for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
+ E = AllArgsEvaluated.end(); I != E; ++I) {
+ // Set up 'this' region.
+ const GRState *state = GetState(*I);
+ state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
+ ExplodedNode *N = Builder->generateNode(Loc, state, *I);
+ if (N)
+ Dst.Add(N);
+ }
+}
+
+void GRExprEngine::VisitCXXNewExpr(CXXNewExpr *CNE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ if (CNE->isArray()) {
+ // FIXME: allocating an array has not been handled.
+ return;
+ }
+
+ unsigned Count = Builder->getCurrentBlockCount();
+ DefinedOrUnknownSVal SymVal = getValueManager().getConjuredSymbolVal(NULL,CNE,
+ CNE->getType(), Count);
+ const MemRegion *NewReg = cast<loc::MemRegionVal>(SymVal).getRegion();
+
+ QualType ObjTy = CNE->getType()->getAs<PointerType>()->getPointeeType();
+
+ const ElementRegion *EleReg =
+ getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
+
+ // Evaluate constructor arguments.
+ const FunctionProtoType *FnType = NULL;
+ const CXXConstructorDecl *CD = CNE->getConstructor();
+ if (CD)
+ FnType = CD->getType()->getAs<FunctionProtoType>();
+ ExplodedNodeSet ArgsEvaluated;
+ EvalArguments(CNE->constructor_arg_begin(), CNE->constructor_arg_end(),
+ FnType, Pred, ArgsEvaluated);
+
+ // Initialize the object region and bind the 'new' expression.
+ for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
+ E = ArgsEvaluated.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+
+ if (ObjTy->isRecordType()) {
+ Store store = state->getStore();
+ StoreManager::InvalidatedSymbols IS;
+ store = getStoreManager().InvalidateRegion(store, EleReg, CNE, Count, &IS);
+ state = state->makeWithStore(store);
+ } else {
+ if (CNE->hasInitializer()) {
+ SVal V = state->getSVal(*CNE->constructor_arg_begin());
+ state = state->bindLoc(loc::MemRegionVal(EleReg), V);
+ } else {
+ // Explicitly set to undefined, because currently we retrieve symbolic
+ // value from symbolic region.
+ state = state->bindLoc(loc::MemRegionVal(EleReg), UndefinedVal());
+ }
+ }
+ state = state->BindExpr(CNE, loc::MemRegionVal(EleReg));
+ MakeNode(Dst, CNE, *I, state);
+ }
+}
+
+void GRExprEngine::VisitCXXDeleteExpr(CXXDeleteExpr *CDE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Should do more checking.
+ ExplodedNodeSet ArgEvaluated;
+ Visit(CDE->getArgument(), Pred, ArgEvaluated);
+ for (ExplodedNodeSet::iterator I = ArgEvaluated.begin(),
+ E = ArgEvaluated.end(); I != E; ++I) {
+ const GRState *state = GetState(*I);
+ MakeNode(Dst, CDE, *I, state);
+ }
+}
+
+void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst) {
+ // Get the this object region from StoreManager.
+ const MemRegion *R =
+ ValMgr.getRegionManager().getCXXThisRegion(
+ getContext().getCanonicalType(TE->getType()),
+ Pred->getLocationContext());
+
+ const GRState *state = GetState(Pred);
+ SVal V = state->getSVal(loc::MemRegionVal(R));
+ MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
+}
diff --git a/lib/Checker/GRCoreEngine.cpp b/lib/Checker/GRCoreEngine.cpp
index e4ef6b0..23a87d3 100644
--- a/lib/Checker/GRCoreEngine.cpp
+++ b/lib/Checker/GRCoreEngine.cpp
@@ -455,6 +455,33 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
Eng.WList->Enqueue(Succ, B, Idx+1);
}
+ExplodedNode* GRStmtNodeBuilder::MakeNode(ExplodedNodeSet& Dst, Stmt* S,
+ ExplodedNode* Pred, const GRState* St,
+ ProgramPoint::Kind K) {
+ const GRState* PredState = GetState(Pred);
+
+ // If the state hasn't changed, don't generate a new node.
+ if (!BuildSinks && St == PredState && Auditor == 0) {
+ Dst.Add(Pred);
+ return NULL;
+ }
+
+ ExplodedNode* N = generateNode(S, St, Pred, K);
+
+ if (N) {
+ if (BuildSinks)
+ N->markAsSink();
+ else {
+ if (Auditor && Auditor->Audit(N, Mgr))
+ N->markAsSink();
+
+ Dst.Add(N);
+ }
+ }
+
+ return N;
+}
+
static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
const LocationContext *LC, const void *tag){
switch (K) {
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index bab8922..67090b8 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -584,43 +584,81 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
switch (S->getStmtClass()) {
// C++ stuff we don't support yet.
- case Stmt::CXXNamedCastExprClass:
- case Stmt::CXXStaticCastExprClass:
- case Stmt::CXXDynamicCastExprClass:
- case Stmt::CXXReinterpretCastExprClass:
- case Stmt::CXXConstCastExprClass:
- case Stmt::CXXFunctionalCastExprClass:
- case Stmt::CXXTypeidExprClass:
- case Stmt::CXXBoolLiteralExprClass:
- case Stmt::CXXNullPtrLiteralExprClass:
- case Stmt::CXXThrowExprClass:
- case Stmt::CXXDefaultArgExprClass:
- case Stmt::CXXZeroInitValueExprClass:
- case Stmt::CXXNewExprClass:
- case Stmt::CXXDeleteExprClass:
- case Stmt::CXXPseudoDestructorExprClass:
- case Stmt::UnresolvedLookupExprClass:
- case Stmt::UnaryTypeTraitExprClass:
- case Stmt::DependentScopeDeclRefExprClass:
- case Stmt::CXXConstructExprClass:
+ case Stmt::CXXBindReferenceExprClass:
case Stmt::CXXBindTemporaryExprClass:
+ case Stmt::CXXCatchStmtClass:
+ case Stmt::CXXConstructExprClass:
+ case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXExprWithTemporariesClass:
+ case Stmt::CXXNullPtrLiteralExprClass:
+ case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTemporaryObjectExprClass:
+ case Stmt::CXXThrowExprClass:
+ case Stmt::CXXTryStmtClass:
+ case Stmt::CXXTypeidExprClass:
case Stmt::CXXUnresolvedConstructExprClass:
- case Stmt::CXXDependentScopeMemberExprClass:
+ case Stmt::CXXZeroInitValueExprClass:
+ case Stmt::DependentScopeDeclRefExprClass:
+ case Stmt::UnaryTypeTraitExprClass:
+ case Stmt::UnresolvedLookupExprClass:
case Stmt::UnresolvedMemberExprClass:
- case Stmt::CXXCatchStmtClass:
- case Stmt::CXXTryStmtClass: {
+ {
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Builder->BuildSinks = true;
MakeNode(Dst, S, Pred, GetState(Pred));
break;
}
- default:
- // Cases we intentionally have "default" handle:
- // AddrLabelExpr, IntegerLiteral, CharacterLiteral
+ // Cases that should never be evaluated simply because they shouldn't
+ // appear in the CFG.
+ case Stmt::BreakStmtClass:
+ case Stmt::CaseStmtClass:
+ case Stmt::CompoundStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::DoStmtClass:
+ case Stmt::GotoStmtClass:
+ case Stmt::IndirectGotoStmtClass:
+ case Stmt::LabelStmtClass:
+ case Stmt::NoStmtClass:
+ case Stmt::NullStmtClass:
+ case Stmt::SwitchCaseClass:
+ llvm_unreachable("Stmt should not be in analyzer evaluation loop");
+ break;
+ // Cases not handled yet; but will handle some day.
+ case Stmt::DesignatedInitExprClass:
+ case Stmt::ExtVectorElementExprClass:
+ case Stmt::GNUNullExprClass:
+ case Stmt::ImaginaryLiteralClass:
+ case Stmt::ImplicitValueInitExprClass:
+ case Stmt::ObjCAtCatchStmtClass:
+ case Stmt::ObjCAtFinallyStmtClass:
+ case Stmt::ObjCAtSynchronizedStmtClass:
+ case Stmt::ObjCAtTryStmtClass:
+ case Stmt::ObjCEncodeExprClass:
+ case Stmt::ObjCImplicitSetterGetterRefExprClass:
+ case Stmt::ObjCIsaExprClass:
+ case Stmt::ObjCPropertyRefExprClass:
+ case Stmt::ObjCProtocolExprClass:
+ case Stmt::ObjCSelectorExprClass:
+ case Stmt::ObjCStringLiteralClass:
+ case Stmt::ObjCSuperExprClass:
+ case Stmt::ParenListExprClass:
+ case Stmt::PredefinedExprClass:
+ case Stmt::ShuffleVectorExprClass:
+ case Stmt::TypesCompatibleExprClass:
+ case Stmt::VAArgExprClass:
+ // Fall through.
+
+ // Cases we intentionally don't evaluate, since they don't need
+ // to be explicitly evaluated.
+ case Stmt::AddrLabelExprClass:
+ case Stmt::IntegerLiteralClass:
+ case Stmt::CharacterLiteralClass:
+ case Stmt::CXXBoolLiteralExprClass:
+ case Stmt::FloatingLiteralClass:
Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
break;
@@ -678,6 +716,17 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
}
+ case Stmt::CXXNewExprClass: {
+ CXXNewExpr *NE = cast<CXXNewExpr>(S);
+ VisitCXXNewExpr(NE, Pred, Dst);
+ break;
+ }
+
+ case Stmt::CXXDeleteExprClass: {
+ CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
+ VisitCXXDeleteExpr(CDE, Pred, Dst);
+ break;
+ }
// FIXME: ChooseExpr is really a constant. We need to fix
// the CFG do not model them as explicit control-flow.
@@ -720,7 +769,12 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
break;
case Stmt::ImplicitCastExprClass:
- case Stmt::CStyleCastExprClass: {
+ case Stmt::CStyleCastExprClass:
+ case Stmt::CXXStaticCastExprClass:
+ case Stmt::CXXDynamicCastExprClass:
+ case Stmt::CXXReinterpretCastExprClass:
+ case Stmt::CXXConstCastExprClass:
+ case Stmt::CXXFunctionalCastExprClass: {
CastExpr* C = cast<CastExpr>(S);
VisitCast(C, C->getSubExpr(), Pred, Dst, false);
break;
@@ -769,6 +823,10 @@ void GRExprEngine::Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst) {
VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
break;
+ case Stmt::OffsetOfExprClass:
+ VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
+ break;
+
case Stmt::SizeOfAlignOfExprClass:
VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
break;
@@ -935,6 +993,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, ExplodedNode* Pred,
return;
// In C++, binding an rvalue to a reference requires to create an object.
+ case Stmt::CXXBoolLiteralExprClass:
case Stmt::IntegerLiteralClass:
CreateCXXTemporaryObject(Ex, Pred, Dst);
return;
@@ -1751,21 +1810,6 @@ void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
}
}
-//===----------------------------------------------------------------------===//
-// Transfer function: Function calls.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class CallExprWLItem {
-public:
- CallExpr::arg_iterator I;
- ExplodedNode *N;
-
- CallExprWLItem(const CallExpr::arg_iterator &i, ExplodedNode *n)
- : I(i), N(n) {}
-};
-} // end anonymous namespace
-
void GRExprEngine::VisitCall(CallExpr* CE, ExplodedNode* Pred,
CallExpr::arg_iterator AI,
CallExpr::arg_iterator AE,
@@ -1916,7 +1960,7 @@ void GRExprEngine::EvalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
continue;
}
- const GRState* state = Pred->getState();
+ const GRState* state = GetState(Pred);
SVal V = state->getSVal(Ex);
if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
// First assume that the condition is true.
@@ -2087,7 +2131,7 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// But first evaluate the receiver (if any).
ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
- if (Expr *Receiver = ME->getReceiver()) {
+ if (Expr *Receiver = ME->getInstanceReceiver()) {
ExplodedNodeSet Tmp;
Visit(Receiver, Pred, Tmp);
@@ -2139,8 +2183,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
- if (const Expr *Receiver = ME->getReceiver()) {
- const GRState *state = Pred->getState();
+ if (const Expr *Receiver = ME->getInstanceReceiver()) {
+ const GRState *state = GetState(Pred);
// Bifurcate the state into nil and non-nil ones.
DefinedOrUnknownSVal receiverVal =
@@ -2169,8 +2213,8 @@ void GRExprEngine::VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
// Dispatch to plug-in transfer function.
EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
}
- else {
- IdentifierInfo* ClsName = ME->getClassName();
+ else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
+ IdentifierInfo* ClsName = Iface->getIdentifier();
Selector S = ME->getSelector();
// Check for special instance methods.
@@ -2464,9 +2508,7 @@ void GRExprEngine::VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
QualType T = getContext().getCanonicalType(E->getType());
unsigned NumInitElements = E->getNumInits();
- if (T->isArrayType() || T->isStructureType() ||
- T->isUnionType() || T->isVectorType()) {
-
+ if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList();
// Handle base case where the initializer has no elements.
@@ -2573,6 +2615,21 @@ void GRExprEngine::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex,
ValMgr.makeIntVal(amt.getQuantity(), Ex->getType())));
}
+void GRExprEngine::VisitOffsetOfExpr(OffsetOfExpr* OOE, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst) {
+ Expr::EvalResult Res;
+ if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
+ const APSInt &IV = Res.Val.getInt();
+ assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
+ assert(OOE->getType()->isIntegerType());
+ assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
+ SVal X = ValMgr.makeIntVal(IV);
+ MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
+ return;
+ }
+ // FIXME: Handle the case where __builtin_offsetof is not a constant.
+ Dst.Add(Pred);
+}
void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
ExplodedNodeSet& Dst, bool asLValue) {
@@ -2654,19 +2711,19 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
case UnaryOperator::OffsetOf: {
Expr::EvalResult Res;
if (U->Evaluate(Res, getContext()) && Res.Val.isInt()) {
- const APSInt &IV = Res.Val.getInt();
- assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
- assert(U->getType()->isIntegerType());
- assert(IV.isSigned() == U->getType()->isSignedIntegerType());
- SVal X = ValMgr.makeIntVal(IV);
- MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
- return;
- }
+ const APSInt &IV = Res.Val.getInt();
+ assert(IV.getBitWidth() == getContext().getTypeSize(U->getType()));
+ assert(U->getType()->isIntegerType());
+ assert(IV.isSigned() == U->getType()->isSignedIntegerType());
+ SVal X = ValMgr.makeIntVal(IV);
+ MakeNode(Dst, U, Pred, GetState(Pred)->BindExpr(U, X));
+ return;
+ }
// FIXME: Handle the case where __builtin_offsetof is not a constant.
Dst.Add(Pred);
return;
}
-
+
case UnaryOperator::Plus: assert (!asLValue); // FALL-THROUGH.
case UnaryOperator::Extension: {
@@ -2860,20 +2917,6 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, ExplodedNode* Pred,
}
}
-
-void GRExprEngine::VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
- ExplodedNodeSet & Dst) {
- // Get the this object region from StoreManager.
- const MemRegion *R =
- ValMgr.getRegionManager().getCXXThisRegion(
- getContext().getCanonicalType(TE->getType()),
- Pred->getLocationContext());
-
- const GRState *state = GetState(Pred);
- SVal V = state->getSVal(loc::MemRegionVal(R));
- MakeNode(Dst, TE, Pred, state->BindExpr(TE, V));
-}
-
void GRExprEngine::VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred,
ExplodedNodeSet& Dst) {
VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
@@ -3006,7 +3049,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
ExplodedNodeSet Tmp3;
for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
- SVal LeftV = (*I1)->getState()->getSVal(LHS);
+ SVal LeftV = GetState(*I1)->getSVal(LHS);
ExplodedNodeSet Tmp2;
Visit(RHS, *I1, Tmp2);
@@ -3147,184 +3190,6 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
CheckerVisit(B, Dst, Tmp3, false);
}
-void GRExprEngine::CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) {
- const GRState *state = GetState(*I);
-
- // Bind the temporary object to the value of the expression. Then bind
- // the expression to the location of the object.
- SVal V = state->getSVal(Ex);
-
- const MemRegion *R =
- ValMgr.getRegionManager().getCXXObjectRegion(Ex,
- Pred->getLocationContext());
-
- state = state->bindLoc(loc::MemRegionVal(R), V);
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, loc::MemRegionVal(R)));
- }
-}
-
-void GRExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *E, SVal Dest,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- if (E->isElidable()) {
- VisitAggExpr(E->getArg(0), Dest, Pred, Dst);
- return;
- }
-
- const CXXConstructorDecl *CD = E->getConstructor();
- assert(CD);
-
- if (!CD->isThisDeclarationADefinition())
- // FIXME: invalidate the object.
- return;
-
-
- // Evaluate other arguments.
- CXXConstructExpr::arg_iterator AB
- = const_cast<CXXConstructExpr*>(E)->arg_begin();
- CXXConstructExpr::arg_iterator AE
- = const_cast<CXXConstructExpr*>(E)->arg_end();
- llvm::SmallVector<CallExprWLItem, 20> WorkList;
- WorkList.reserve(AE - AB);
- WorkList.push_back(CallExprWLItem(AB, Pred));
- ExplodedNodeSet ArgsEvaluated;
- const FunctionProtoType *Proto = CD->getType()->getAs<FunctionProtoType>();
-
- while (!WorkList.empty()) {
- CallExprWLItem Item = WorkList.back();
- WorkList.pop_back();
-
- if (Item.I == AE) {
- ArgsEvaluated.insert(Item.N);
- continue;
- }
-
- // Evaluate the argument.
- ExplodedNodeSet Tmp;
- const unsigned ParamIdx = Item.I - AB;
-
- bool VisitAsLvalue = false;
-
- if (ParamIdx < Proto->getNumArgs())
- VisitAsLvalue = Proto->getArgType(ParamIdx)->isReferenceType();
-
- if (VisitAsLvalue)
- VisitLValue(*Item.I, Item.N, Tmp);
- else
- Visit(*Item.I, Item.N, Tmp);
-
- ++(Item.I);
-
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- WorkList.push_back(CallExprWLItem(Item.I, *NI));
- }
- // The callee stack frame context used to create the 'this' parameter region.
- const StackFrameContext *SFC = AMgr.getStackFrame(CD,
- Pred->getLocationContext(),
- E, Builder->getBlock(), Builder->getIndex());
-
- const CXXThisRegion *ThisR = getCXXThisRegion(E->getConstructor(), SFC);
-
- CallEnter Loc(E, CD, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator NI = ArgsEvaluated.begin(),
- NE = ArgsEvaluated.end(); NI != NE; ++NI) {
- const GRState *state = GetState(*NI);
- // Setup 'this' region.
- state = state->bindLoc(loc::MemRegionVal(ThisR), Dest);
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- if (N)
- Dst.Add(N);
- }
-}
-
-void GRExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- // Get the method type.
- const FunctionProtoType *FnType =
- MCE->getCallee()->getType()->getAs<FunctionProtoType>();
- assert(FnType && "Method type not available");
-
- // Evaluate explicit arguments with a worklist.
- CallExpr::arg_iterator AB = const_cast<CXXMemberCallExpr*>(MCE)->arg_begin(),
- AE = const_cast<CXXMemberCallExpr*>(MCE)->arg_end();
- llvm::SmallVector<CallExprWLItem, 20> WorkList;
- WorkList.reserve(AE - AB);
- WorkList.push_back(CallExprWLItem(AB, Pred));
- ExplodedNodeSet ArgsEvaluated;
-
- while (!WorkList.empty()) {
- CallExprWLItem Item = WorkList.back();
- WorkList.pop_back();
-
- if (Item.I == AE) {
- ArgsEvaluated.insert(Item.N);
- continue;
- }
-
- ExplodedNodeSet Tmp;
- const unsigned ParamIdx = Item.I - AB;
- bool VisitAsLvalue = FnType->getArgType(ParamIdx)->isReferenceType();
-
- if (VisitAsLvalue)
- VisitLValue(*Item.I, Item.N, Tmp);
- else
- Visit(*Item.I, Item.N, Tmp);
-
- ++(Item.I);
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI != NE; ++NI)
- WorkList.push_back(CallExprWLItem(Item.I, *NI));
- }
- // Evaluate the implicit object argument.
- ExplodedNodeSet AllArgsEvaluated;
- const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens());
- if (!ME)
- return;
- Expr *ObjArgExpr = ME->getBase();
- for (ExplodedNodeSet::iterator I = ArgsEvaluated.begin(),
- E = ArgsEvaluated.end(); I != E; ++I) {
- if (ME->isArrow())
- Visit(ObjArgExpr, *I, AllArgsEvaluated);
- else
- VisitLValue(ObjArgExpr, *I, AllArgsEvaluated);
- }
-
- const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl());
- assert(MD && "not a CXXMethodDecl?");
-
- if (!MD->isThisDeclarationADefinition())
- // FIXME: conservative method call evaluation.
- return;
-
- const StackFrameContext *SFC = AMgr.getStackFrame(MD,
- Pred->getLocationContext(),
- MCE,
- Builder->getBlock(),
- Builder->getIndex());
- const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC);
- CallEnter Loc(MCE, MD, Pred->getLocationContext());
- for (ExplodedNodeSet::iterator I = AllArgsEvaluated.begin(),
- E = AllArgsEvaluated.end(); I != E; ++I) {
- // Set up 'this' region.
- const GRState *state = GetState(*I);
- state = state->bindLoc(loc::MemRegionVal(ThisR),state->getSVal(ObjArgExpr));
- ExplodedNode *N = Builder->generateNode(Loc, state, *I);
- if (N)
- Dst.Add(N);
- }
-}
-
-const CXXThisRegion *GRExprEngine::getCXXThisRegion(const CXXMethodDecl *D,
- const StackFrameContext *SFC) {
- Type *T = D->getParent()->getTypeForDecl();
- QualType PT = getContext().getPointerType(QualType(T,0));
- return ValMgr.getRegionManager().getCXXThisRegion(PT, SFC);
-}
-
//===----------------------------------------------------------------------===//
// Checker registration/lookup.
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/MemRegion.cpp b/lib/Checker/MemRegion.cpp
index 9f12ab6..9a664c7 100644
--- a/lib/Checker/MemRegion.cpp
+++ b/lib/Checker/MemRegion.cpp
@@ -365,11 +365,11 @@ void ElementRegion::dumpToStream(llvm::raw_ostream& os) const {
}
void FieldRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << superRegion << "->" << getDecl()->getNameAsString();
+ os << superRegion << "->" << getDecl();
}
void ObjCIvarRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << "ivar{" << superRegion << ',' << getDecl()->getNameAsString() << '}';
+ os << "ivar{" << superRegion << ',' << getDecl() << '}';
}
void StringRegion::dumpToStream(llvm::raw_ostream& os) const {
@@ -381,7 +381,7 @@ void SymbolicRegion::dumpToStream(llvm::raw_ostream& os) const {
}
void VarRegion::dumpToStream(llvm::raw_ostream& os) const {
- os << cast<VarDecl>(D)->getNameAsString();
+ os << cast<VarDecl>(D);
}
void RegionRawOffset::dump() const {
@@ -647,13 +647,14 @@ bool MemRegion::hasGlobalsOrParametersStorage() const {
const MemRegion *MemRegion::getBaseRegion() const {
const MemRegion *R = this;
while (true) {
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- R = ER->getSuperRegion();
- continue;
- }
- if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
- R = FR->getSuperRegion();
- continue;
+ switch (R->getKind()) {
+ case MemRegion::ElementRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ R = cast<SubRegion>(R)->getSuperRegion();
+ continue;
+ default:
+ break;
}
break;
}
diff --git a/lib/Checker/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp
index 29bac9c..48f03a3 100644
--- a/lib/Checker/NSAutoreleasePoolChecker.cpp
+++ b/lib/Checker/NSAutoreleasePoolChecker.cpp
@@ -56,7 +56,7 @@ void
NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
const ObjCMessageExpr *ME) {
- const Expr *receiver = ME->getReceiver();
+ const Expr *receiver = ME->getInstanceReceiver();
if (!receiver)
return;
diff --git a/lib/Checker/NSErrorChecker.cpp b/lib/Checker/NSErrorChecker.cpp
index 9130bfa..e30d54c 100644
--- a/lib/Checker/NSErrorChecker.cpp
+++ b/lib/Checker/NSErrorChecker.cpp
@@ -226,7 +226,7 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
else
os << "documented in CoreFoundation/CFError.h the parameter '";
- os << Param->getNameAsString() << "' may be null.";
+ os << Param << "' may be null.";
BugReport *report = new BugReport(*this, os.str(), *I);
// FIXME: Notable symbols are now part of the report. We should
diff --git a/lib/Checker/ObjCUnusedIVarsChecker.cpp b/lib/Checker/ObjCUnusedIVarsChecker.cpp
index 04d897a..0e47621 100644
--- a/lib/Checker/ObjCUnusedIVarsChecker.cpp
+++ b/lib/Checker/ObjCUnusedIVarsChecker.cpp
@@ -150,8 +150,7 @@ void clang::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
if (I->second == Unused) {
std::string sbuf;
llvm::raw_string_ostream os(sbuf);
- os << "Instance variable '" << I->first->getNameAsString()
- << "' in class '" << ID->getNameAsString()
+ os << "Instance variable '" << I->first << "' in class '" << ID
<< "' is never used by the methods in its @implementation "
"(although it may be used by category methods).";
diff --git a/lib/Checker/RegionStore.cpp b/lib/Checker/RegionStore.cpp
index c97da33..1e15d43 100644
--- a/lib/Checker/RegionStore.cpp
+++ b/lib/Checker/RegionStore.cpp
@@ -14,22 +14,22 @@
// parameters are created lazily.
//
//===----------------------------------------------------------------------===//
-#include "clang/Checker/PathSensitive/MemRegion.h"
-#include "clang/Analysis/AnalysisContext.h"
-#include "clang/Checker/PathSensitive/GRState.h"
-#include "clang/Checker/PathSensitive/GRStateTrait.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Support/Optional.h"
-#include "clang/Basic/TargetInfo.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
-
-#include "llvm/ADT/ImmutableMap.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRStateTrait.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
+using llvm::Optional;
//===----------------------------------------------------------------------===//
// Representation of binding keys.
@@ -346,8 +346,6 @@ public: // Part of public interface to class.
Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
const TypedRegion *R);
- const ElementRegion *GetElementZeroRegion(const MemRegion *R, QualType T);
-
//===------------------------------------------------------------------===//
// State pruning.
//===------------------------------------------------------------------===//
@@ -995,14 +993,6 @@ static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
return true;
}
-const ElementRegion *
-RegionStoreManager::GetElementZeroRegion(const MemRegion *R, QualType T) {
- ASTContext &Ctx = getContext();
- SVal idx = ValMgr.makeZeroArrayIndex();
- assert(!T.isNull());
- return MRMgr.getElementRegion(T, idx, R, Ctx);
-}
-
SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
@@ -1047,7 +1037,7 @@ SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
}
#endif
- if (RTy->isStructureType() || RTy->isClassType())
+ if (RTy->isStructureOrClassType())
return RetrieveStruct(store, R);
// FIXME: Handle unions.
@@ -1355,7 +1345,7 @@ SVal RegionStoreManager::RetrieveLazySymbol(const TypedRegion *R) {
SVal RegionStoreManager::RetrieveStruct(Store store, const TypedRegion* R) {
QualType T = R->getValueType(getContext());
- assert(T->isStructureType() || T->isClassType());
+ assert(T->isStructureOrClassType());
return ValMgr.makeLazyCompoundVal(store, R);
}
@@ -1385,7 +1375,7 @@ Store RegionStoreManager::Bind(Store store, Loc L, SVal V) {
// Check if the region is a struct region.
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
- if (TR->getValueType(getContext())->isStructureType())
+ if (TR->getValueType(getContext())->isStructureOrClassType())
return BindStruct(store, TR, V);
// Special case: the current region represents a cast and it and the super
@@ -1439,7 +1429,7 @@ Store RegionStoreManager::BindDecl(Store store, const VarRegion *VR,
if (T->isArrayType())
return BindArray(store, VR, InitVal);
- if (T->isStructureType())
+ if (T->isStructureOrClassType())
return BindStruct(store, VR, InitVal);
return Bind(store, ValMgr.makeLoc(VR), InitVal);
@@ -1464,7 +1454,7 @@ Store RegionStoreManager::setImplicitDefaultValue(Store store,
V = ValMgr.makeNull();
else if (T->isIntegerType())
V = ValMgr.makeZeroVal(T);
- else if (T->isStructureType() || T->isArrayType()) {
+ else if (T->isStructureOrClassType() || T->isArrayType()) {
// Set the default value to a zero constant when it is a structure
// or array. The type doesn't really matter.
V = ValMgr.makeZeroVal(ValMgr.getContext().IntTy);
@@ -1540,7 +1530,7 @@ Store RegionStoreManager::BindArray(Store store, const TypedRegion* R,
SVal Idx = ValMgr.makeArrayIndex(i);
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
- if (ElementTy->isStructureType())
+ if (ElementTy->isStructureOrClassType())
store = BindStruct(store, ER, *VI);
else
store = Bind(store, ValMgr.makeLoc(ER), *VI);
@@ -1561,7 +1551,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
return store;
QualType T = R->getValueType(getContext());
- assert(T->isStructureType());
+ assert(T->isStructureOrClassType());
const RecordType* RT = T->getAs<RecordType>();
RecordDecl* RD = RT->getDecl();
@@ -1593,7 +1583,7 @@ Store RegionStoreManager::BindStruct(Store store, const TypedRegion* R,
if (FTy->isArrayType())
store = BindArray(store, FR, *VI);
- else if (FTy->isStructureType())
+ else if (FTy->isStructureOrClassType())
store = BindStruct(store, FR, *VI);
else
store = Bind(store, ValMgr.makeLoc(FR), *VI);
diff --git a/lib/Checker/SVals.cpp b/lib/Checker/SVals.cpp
index 4bfa2cd..d756be7 100644
--- a/lib/Checker/SVals.cpp
+++ b/lib/Checker/SVals.cpp
@@ -318,7 +318,8 @@ void NonLoc::dumpToStream(llvm::raw_ostream& os) const {
}
case nonloc::LazyCompoundValKind: {
const nonloc::LazyCompoundVal &C = *cast<nonloc::LazyCompoundVal>(this);
- os << "lazyCompoundVal{" << (void*) C.getStore() << ',' << C.getRegion()
+ os << "lazyCompoundVal{" << const_cast<void *>(C.getStore())
+ << ',' << C.getRegion()
<< '}';
break;
}
diff --git a/lib/Checker/SimpleSValuator.cpp b/lib/Checker/SimpleSValuator.cpp
index fb1d74a..dd38a43 100644
--- a/lib/Checker/SimpleSValuator.cpp
+++ b/lib/Checker/SimpleSValuator.cpp
@@ -113,16 +113,22 @@ SVal SimpleSValuator::EvalCastL(Loc val, QualType castTy) {
if (castTy->isUnionType())
return UnknownVal();
- assert(castTy->isIntegerType());
- unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
+ if (castTy->isIntegerType()) {
+ unsigned BitWidth = ValMgr.getContext().getTypeSize(castTy);
- if (!isa<loc::ConcreteInt>(val))
- return ValMgr.makeLocAsInteger(val, BitWidth);
+ if (!isa<loc::ConcreteInt>(val))
+ return ValMgr.makeLocAsInteger(val, BitWidth);
- llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
- i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
- i.extOrTrunc(BitWidth);
- return ValMgr.makeIntVal(i);
+ llvm::APSInt i = cast<loc::ConcreteInt>(val).getValue();
+ i.setIsUnsigned(castTy->isUnsignedIntegerType() || Loc::IsLocType(castTy));
+ i.extOrTrunc(BitWidth);
+ return ValMgr.makeIntVal(i);
+ }
+
+ // All other cases: return 'UnknownVal'. This includes casting pointers
+ // to floats, which is probably badness it itself, but this is a good
+ // intermediate solution until we do something better.
+ return UnknownVal();
}
//===----------------------------------------------------------------------===//
diff --git a/lib/Checker/Store.cpp b/lib/Checker/Store.cpp
index e524cb3..c12065b 100644
--- a/lib/Checker/Store.cpp
+++ b/lib/Checker/Store.cpp
@@ -38,6 +38,13 @@ static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
return true;
}
+const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R,
+ QualType T) {
+ SVal idx = ValMgr.makeZeroArrayIndex();
+ assert(!T.isNull());
+ return MRMgr.getElementRegion(T, idx, R, Ctx);
+}
+
const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy) {
ASTContext& Ctx = StateMgr.getContext();
@@ -170,13 +177,14 @@ const MemRegion *StoreManager::CastRegion(const MemRegion *R, QualType CastToTy)
if (IsCompleteType(Ctx, PointeeTy)) {
// Compute the size in **bytes**.
CharUnits pointeeTySize = Ctx.getTypeSizeInChars(PointeeTy);
-
- // Is the offset a multiple of the size? If so, we can layer the
- // ElementRegion (with elementType == PointeeTy) directly on top of
- // the base region.
- if (off % pointeeTySize == 0) {
- newIndex = off / pointeeTySize;
- newSuperR = baseR;
+ if (!pointeeTySize.isZero()) {
+ // Is the offset a multiple of the size? If so, we can layer the
+ // ElementRegion (with elementType == PointeeTy) directly on top of
+ // the base region.
+ if (off % pointeeTySize == 0) {
+ newIndex = off / pointeeTySize;
+ newSuperR = baseR;
+ }
}
}
diff --git a/lib/Checker/UnixAPIChecker.cpp b/lib/Checker/UnixAPIChecker.cpp
index d75e5d2..e9b8f09 100644
--- a/lib/Checker/UnixAPIChecker.cpp
+++ b/lib/Checker/UnixAPIChecker.cpp
@@ -13,23 +13,30 @@
//===----------------------------------------------------------------------===//
#include "GRExprEngineInternalChecks.h"
-#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Checker/BugReporter/BugType.h"
+#include "clang/Checker/PathSensitive/CheckerVisitor.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringSwitch.h"
#include <fcntl.h>
using namespace clang;
+using llvm::Optional;
namespace {
class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
enum SubChecks {
OpenFn = 0,
+ PthreadOnceFn = 1,
NumChecks
};
BugType *BTypes[NumChecks];
public:
+ Optional<uint64_t> Val_O_CREAT;
+
+public:
UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
static void *getTag() { static unsigned tag = 0; return &tag; }
@@ -55,7 +62,21 @@ static inline void LazyInitialize(BugType *&BT, const char *name) {
// "open" (man 2 open)
//===----------------------------------------------------------------------===//
-static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
+static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
+ const CallExpr *CE, BugType *&BT) {
+ // The definition of O_CREAT is platform specific. We need a better way
+ // of querying this information from the checking environment.
+ if (!UC.Val_O_CREAT.hasValue()) {
+ if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
+ UC.Val_O_CREAT = 0x0200;
+ else {
+ // FIXME: We need a more general way of getting the O_CREAT value.
+ // We could possibly grovel through the preprocessor state, but
+ // that would require passing the Preprocessor object to the GRExprEngine.
+ return;
+ }
+ }
+
LazyInitialize(BT, "Improper use of 'open'");
// Look at the 'oflags' argument for the O_CREAT flag.
@@ -77,7 +98,7 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
}
NonLoc oflags = cast<NonLoc>(V);
NonLoc ocreateFlag =
- cast<NonLoc>(C.getValueManager().makeIntVal((uint64_t) O_CREAT,
+ cast<NonLoc>(C.getValueManager().makeIntVal(UC.Val_O_CREAT.getValue(),
oflagsEx->getType()));
SVal maskedFlagsUC = C.getSValuator().EvalBinOpNN(state, BinaryOperator::And,
oflags, ocreateFlag,
@@ -110,21 +131,67 @@ static void CheckOpen(CheckerContext &C, const CallExpr *CE, BugType *&BT) {
}
//===----------------------------------------------------------------------===//
+// pthread_once
+//===----------------------------------------------------------------------===//
+
+static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
+ const CallExpr *CE, BugType *&BT) {
+
+ // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
+ // They can possibly be refactored.
+
+ LazyInitialize(BT, "Improper use of 'pthread_once'");
+
+ if (CE->getNumArgs() < 1)
+ return;
+
+ // Check if the first argument is stack allocated. If so, issue a warning
+ // because that's likely to be bad news.
+ const GRState *state = C.getState();
+ const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
+ if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
+ return;
+
+ ExplodedNode *N = C.GenerateSink(state);
+ if (!N)
+ return;
+
+ llvm::SmallString<256> S;
+ llvm::raw_svector_ostream os(S);
+ os << "Call to 'pthread_once' uses";
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ os << " the local variable '" << VR->getDecl()->getName() << '\'';
+ else
+ os << " stack allocated memory";
+ os << " for the \"control\" value. Using such transient memory for "
+ "the control value is potentially dangerous.";
+ if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
+ os << " Perhaps you intended to declare the variable as 'static'?";
+
+ EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
+ report->addRange(CE->getArg(0)->getSourceRange());
+ C.EmitReport(report);
+}
+
+//===----------------------------------------------------------------------===//
// Central dispatch function.
//===----------------------------------------------------------------------===//
-typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT);
+typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC,
+ const CallExpr *CE, BugType *&BT);
namespace {
class SubCheck {
SubChecker SC;
+ UnixAPIChecker *UC;
BugType **BT;
public:
- SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
- SubCheck() : SC(NULL), BT(NULL) {}
+ SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc),
+ BT(&bt) {}
+ SubCheck() : SC(NULL), UC(NULL), BT(NULL) {}
void run(CheckerContext &C, const CallExpr *CE) const {
if (SC)
- SC(C, CE, *BT);
+ SC(C, *UC, CE, *BT);
}
};
} // end anonymous namespace
@@ -146,7 +213,9 @@ void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
const SubCheck &SC =
llvm::StringSwitch<SubCheck>(FI->getName())
- .Case("open", SubCheck(CheckOpen, BTypes[OpenFn]))
+ .Case("open", SubCheck(CheckOpen, this, BTypes[OpenFn]))
+ .Case("pthread_once", SubCheck(CheckPthreadOnce, this,
+ BTypes[PthreadOnceFn]))
.Default(SubCheck());
SC.run(C, CE);
OpenPOWER on IntegriCloud