diff options
-rw-r--r-- | include/clang/Analysis/PathSensitive/Checker.h | 7 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h | 29 | ||||
-rw-r--r-- | include/clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h | 29 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 53 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngineInternalChecks.cpp | 65 | ||||
-rw-r--r-- | lib/Analysis/UndefSizedVLAChecker.cpp | 54 | ||||
-rw-r--r-- | lib/Analysis/ZeroSizedVLAChecker.cpp | 66 | ||||
-rw-r--r-- | test/Analysis/misc-ps.m | 4 |
8 files changed, 208 insertions, 99 deletions
diff --git a/include/clang/Analysis/PathSensitive/Checker.h b/include/clang/Analysis/PathSensitive/Checker.h index ac856d370f..0134599511 100644 --- a/include/clang/Analysis/PathSensitive/Checker.h +++ b/include/clang/Analysis/PathSensitive/Checker.h @@ -126,6 +126,13 @@ public: GRExprEngine &Eng) { return Pred; } + + virtual ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, + GRExprEngine &Eng) { + return Pred; + } + }; } // end clang namespace diff --git a/include/clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h b/include/clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h new file mode 100644 index 0000000000..9d4507cb0c --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h @@ -0,0 +1,29 @@ +//=== UndefSizedVLAChecker.h - Undefined dereference checker ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines UndefSizedVLAChecker, a builtin check in GRExprEngine that +// performs checks for declaration of VLA of undefined size. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checker.h" + +namespace clang { + +class UndefSizedVLAChecker : public Checker { + BugType *BT; + +public: + UndefSizedVLAChecker() : BT(0) {} + static void *getTag(); + ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, GRExprEngine &Eng); +}; + +} diff --git a/include/clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h b/include/clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h new file mode 100644 index 0000000000..4d3be31acf --- /dev/null +++ b/include/clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h @@ -0,0 +1,29 @@ +//=== ZeroSizedVLAChecker.cpp - Undefined dereference checker ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines ZeorSizedVLAChecker, a builtin check in GRExprEngine that +// performs checks for declaration of VLA of zero size. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checker.h" + +namespace clang { + +class ZeroSizedVLAChecker : public Checker { + BugType *BT; + +public: + ZeroSizedVLAChecker() : BT(0) {} + static void *getTag(); + ExplodedNode *CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, GRExprEngine &Eng); +}; + +} diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index d0710e5880..eb8c39c306 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -2058,45 +2058,25 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, Tmp.Add(Pred); for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) { - const GRState* state = GetState(*I); - unsigned Count = Builder->getCurrentBlockCount(); - - // Check if 'VD' is a VLA and if so check if has a non-zero size. - QualType T = getContext().getCanonicalType(VD->getType()); - if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { - // FIXME: Handle multi-dimensional VLAs. - - Expr* SE = VLA->getSizeExpr(); - SVal Size_untested = state->getSVal(SE); - - if (Size_untested.isUndef()) { - if (ExplodedNode* N = Builder->generateNode(DS, state, Pred)) { - N->markAsSink(); - ExplicitBadSizedVLA.insert(N); - } - continue; - } - - DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Size_untested); - const GRState *zeroState = state->Assume(Size, false); - state = state->Assume(Size, true); + ExplodedNode *N = *I; + const GRState *state; + + for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end(); + CI != CE; ++CI) { + state = GetState(N); + N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()), + N, state, DS, *this); + if (!N) + break; + } - if (zeroState) { - if (ExplodedNode* N = Builder->generateNode(DS, zeroState, Pred)) { - N->markAsSink(); - if (state) - ImplicitBadSizedVLA.insert(N); - else - ExplicitBadSizedVLA.insert(N); - } - } + if (!N) + continue; - if (!state) - continue; - } + state = GetState(N); // Decls without InitExpr are not initialized explicitly. - const LocationContext *LC = (*I)->getLocationContext(); + const LocationContext *LC = N->getLocationContext(); if (InitEx) { SVal InitVal = state->getSVal(InitEx); @@ -2106,7 +2086,8 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred, // UnknownVal. if (InitVal.isUnknown() || !getConstraintManager().canReasonAbout(InitVal)) { - InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, Count); + InitVal = ValMgr.getConjuredSymbolVal(NULL, InitEx, + Builder->getCurrentBlockCount()); } state = state->bindDecl(VD, LC, InitVal); diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp index 908835a53c..089d25d6cf 100644 --- a/lib/Analysis/GRExprEngineInternalChecks.cpp +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -21,6 +21,8 @@ #include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h" #include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h" #include "clang/Analysis/PathSensitive/Checkers/AttrNonNullChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h" +#include "clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/Compiler.h" @@ -449,66 +451,6 @@ public: } }; -class VISIBILITY_HIDDEN BadSizeVLA : public BuiltinBug { -public: - BadSizeVLA(GRExprEngine* eng) : - BuiltinBug(eng, "Bad variable-length array (VLA) size") {} - - void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) { - for (GRExprEngine::ErrorNodes::iterator - I = Eng.ExplicitBadSizedVLA.begin(), - E = Eng.ExplicitBadSizedVLA.end(); I!=E; ++I) { - - // Determine whether this was a 'zero-sized' VLA or a VLA with an - // undefined size. - ExplodedNode* N = *I; - PostStmt PS = cast<PostStmt>(N->getLocation()); - const DeclStmt *DS = cast<DeclStmt>(PS.getStmt()); - VarDecl* VD = cast<VarDecl>(*DS->decl_begin()); - QualType T = Eng.getContext().getCanonicalType(VD->getType()); - VariableArrayType* VT = cast<VariableArrayType>(T); - Expr* SizeExpr = VT->getSizeExpr(); - - std::string buf; - llvm::raw_string_ostream os(buf); - os << "The expression used to specify the number of elements in the " - "variable-length array (VLA) '" - << VD->getNameAsString() << "' evaluates to "; - - bool isUndefined = N->getState()->getSVal(SizeExpr).isUndef(); - - if (isUndefined) - os << "an undefined or garbage value."; - else - os << "0. VLAs with no elements have undefined behavior."; - - std::string shortBuf; - llvm::raw_string_ostream os_short(shortBuf); - os_short << "Variable-length array '" << VD->getNameAsString() << "' " - << (isUndefined ? "garbage value for array size" - : "has zero elements (undefined behavior)"); - - ArgReport *report = new ArgReport(*this, os_short.str().c_str(), - os.str().c_str(), N, SizeExpr); - - report->addRange(SizeExpr->getSourceRange()); - BR.EmitReport(report); - } - } - - void registerInitialVisitors(BugReporterContext& BRC, - const ExplodedNode* N, - BuiltinBugReport *R) { - registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(), - N); - } -}; - -//===----------------------------------------------------------------------===// -// __attribute__(nonnull) checking - - - } // end clang namespace //===----------------------------------------------------------------------===// @@ -528,7 +470,6 @@ void GRExprEngine::RegisterInternalChecks() { BR.Register(new BadMsgExprArg(this)); BR.Register(new BadReceiver(this)); BR.Register(new OutOfBoundMemoryAccess(this)); - BR.Register(new BadSizeVLA(this)); BR.Register(new NilReceiverStructRet(this)); BR.Register(new NilReceiverLargerThanVoidPtrRet(this)); @@ -543,4 +484,6 @@ void GRExprEngine::RegisterInternalChecks() { registerCheck<DivZeroChecker>(new DivZeroChecker()); registerCheck<UndefDerefChecker>(new UndefDerefChecker()); registerCheck<NullDerefChecker>(new NullDerefChecker()); + registerCheck<UndefSizedVLAChecker>(new UndefSizedVLAChecker()); + registerCheck<ZeroSizedVLAChecker>(new ZeroSizedVLAChecker()); } diff --git a/lib/Analysis/UndefSizedVLAChecker.cpp b/lib/Analysis/UndefSizedVLAChecker.cpp new file mode 100644 index 0000000000..e51e10e3aa --- /dev/null +++ b/lib/Analysis/UndefSizedVLAChecker.cpp @@ -0,0 +1,54 @@ +//=== UndefSizedVLAChecker.cpp - Undefined dereference checker --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines UndefSizedVLAChecker, a builtin check in GRExprEngine that +// performs checks for declaration of VLA of undefined size. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/UndefSizedVLAChecker.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *UndefSizedVLAChecker::getTag() { + static int x = 0; + return &x; +} + +ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, + Stmt *S, GRExprEngine &Eng) { + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { + // FIXME: Handle multi-dimensional VLAs. + Expr* SE = VLA->getSizeExpr(); + SVal Size_untested = state->getSVal(SE); + + if (Size_untested.isUndef()) { + if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) { + N->markAsSink(); + if (!BT) + BT = new BugType("Declare variable-length array (VLA) of undefined " + "size", "Logic error"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getName().c_str(), N); + R->addRange(SE->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + BR.EmitReport(R); + } + return 0; + } + } + return Pred; +} diff --git a/lib/Analysis/ZeroSizedVLAChecker.cpp b/lib/Analysis/ZeroSizedVLAChecker.cpp new file mode 100644 index 0000000000..8984a5f390 --- /dev/null +++ b/lib/Analysis/ZeroSizedVLAChecker.cpp @@ -0,0 +1,66 @@ +//=== ZeroSizedVLAChecker.cpp - Undefined dereference checker ---*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This defines ZeorSizedVLAChecker, a builtin check in GRExprEngine that +// performs checks for declaration of VLA of zero size. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/PathSensitive/Checkers/ZeroSizedVLAChecker.h" +#include "clang/Analysis/PathSensitive/GRExprEngine.h" +#include "clang/Analysis/PathSensitive/BugReporter.h" + +using namespace clang; + +void *ZeroSizedVLAChecker::getTag() { + static int x; + return &x; +} + +ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred, + const GRState *state, Stmt *S, + GRExprEngine &Eng) { + GRStmtNodeBuilder &Builder = Eng.getBuilder(); + BugReporter &BR = Eng.getBugReporter(); + + if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) { + // FIXME: Handle multi-dimensional VLAs. + Expr* SE = VLA->getSizeExpr(); + SVal Size_untested = state->getSVal(SE); + + DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested); + // Undefined size is checked in another checker. + if (!Size) + return Pred; + + const GRState *zeroState = state->Assume(*Size, false); + state = state->Assume(*Size, true); + + if (zeroState && !state) { + if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) { + N->markAsSink(); + if (!BT) + BT = new BugType("Declare variable-length array (VLA) of zero size", + "Logic error"); + + EnhancedBugReport *R = + new EnhancedBugReport(*BT, BT->getName().c_str(), N); + R->addRange(SE->getSourceRange()); + R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE); + BR.EmitReport(R); + } + } + if (!state) + return 0; + + return Builder.generateNode(S, state, Pred); + } + else + return Pred; +} diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index 0d4592a9e3..947b41ae79 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -121,12 +121,12 @@ void check_zero_sized_VLA(int x) { if (x) return; - int vla[x]; // expected-warning{{Variable-length array 'vla' has zero elements (undefined behavior)}} + int vla[x]; // expected-warning{{Declare variable-length array (VLA) of zero size}} } void check_uninit_sized_VLA() { int x; - int vla[x]; // expected-warning{{Variable-length array 'vla' garbage value for array size}} + int vla[x]; // expected-warning{{Declare variable-length array (VLA) of undefined size}} } // sizeof(void) |