diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp | 45 |
1 files changed, 36 insertions, 9 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index eea93a41f138..b856b0edc615 100644 --- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -19,6 +19,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/FormatVariadic.h" using namespace clang; using namespace ento; @@ -40,6 +41,11 @@ class PointerSubChecker "Indexing the address of a variable with other than 1 at this place " "is undefined behavior."; + /// Check that an array is indexed in the allowed range that is 0 to "one + /// after the end". The "array" can be address of a non-array variable. + /// @param E Expression of the pointer subtraction. + /// @param ElemReg An indexed region in the subtraction expression. + /// @param Reg Region of the other side of the expression. bool checkArrayBounds(CheckerContext &C, const Expr *E, const ElementRegion *ElemReg, const MemRegion *Reg) const; @@ -49,12 +55,28 @@ public: }; } +static bool isArrayVar(const MemRegion *R) { + while (R) { + if (isa<VarRegion>(R)) + return true; + if (const auto *ER = dyn_cast<ElementRegion>(R)) + R = ER->getSuperRegion(); + else + return false; + } + return false; +} + bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E, const ElementRegion *ElemReg, const MemRegion *Reg) const { if (!ElemReg) return true; + const MemRegion *SuperReg = ElemReg->getSuperRegion(); + if (!isArrayVar(SuperReg)) + return true; + auto ReportBug = [&](const llvm::StringLiteral &Msg) { if (ExplodedNode *N = C.generateNonFatalErrorNode()) { auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N); @@ -64,10 +86,10 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E, }; ProgramStateRef State = C.getState(); - const MemRegion *SuperReg = ElemReg->getSuperRegion(); SValBuilder &SVB = C.getSValBuilder(); if (SuperReg == Reg) { + // Case like `(&x + 1) - &x`. Only 1 or 0 is allowed as index. if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex()); I && (!I->isOne() && !I->isZero())) ReportBug(Msg_BadVarIndex); @@ -121,8 +143,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, if (LR == RR) return; - // No warning if one operand is unknown. - if (isa<SymbolicRegion>(LR) || isa<SymbolicRegion>(RR)) + // No warning if one operand is unknown or resides in a region that could be + // equal to the other. + if (LR->getSymbolicBase() || RR->getSymbolicBase()) return; const auto *ElemLR = dyn_cast<ElementRegion>(LR); @@ -159,12 +182,16 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, // do_something(&a.array[5] - &b.array[5]); // In this case don't emit notes. if (DiffDeclL != DiffDeclR) { - if (DiffDeclL) - R->addNote("Array at the left-hand side of subtraction", - {DiffDeclL, C.getSourceManager()}); - if (DiffDeclR) - R->addNote("Array at the right-hand side of subtraction", - {DiffDeclR, C.getSourceManager()}); + auto AddNote = [&R, &C](const ValueDecl *D, StringRef SideStr) { + if (D) { + std::string Msg = llvm::formatv( + "{0} at the {1}-hand side of subtraction", + D->getType()->isArrayType() ? "Array" : "Object", SideStr); + R->addNote(Msg, {D, C.getSourceManager()}); + } + }; + AddNote(DiffDeclL, "left"); + AddNote(DiffDeclR, "right"); } C.emitReport(std::move(R)); } |
