summaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp45
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));
}