GRExprEngine &Eng) {
return Pred;
}
+
+ virtual ExplodedNode *CheckType(QualType T, ExplodedNode *Pred,
+ const GRState *state, Stmt *S,
+ GRExprEngine &Eng) {
+ return Pred;
+ }
+
};
} // end clang namespace
--- /dev/null
+//=== 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);
+};
+
+}
--- /dev/null
+//=== 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);
+};
+
+}
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);
// 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);
#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"
}
};
-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
//===----------------------------------------------------------------------===//
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));
registerCheck<DivZeroChecker>(new DivZeroChecker());
registerCheck<UndefDerefChecker>(new UndefDerefChecker());
registerCheck<NullDerefChecker>(new NullDerefChecker());
+ registerCheck<UndefSizedVLAChecker>(new UndefSizedVLAChecker());
+ registerCheck<ZeroSizedVLAChecker>(new ZeroSizedVLAChecker());
}
--- /dev/null
+//=== 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;
+}
--- /dev/null
+//=== 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;
+}
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)