diff --git a/clang/include/clang/Analysis/PathSensitive/MemRegion.h b/clang/include/clang/Analysis/PathSensitive/MemRegion.h index 91db5982495b..06d0d976df01 100644 --- a/clang/include/clang/Analysis/PathSensitive/MemRegion.h +++ b/clang/include/clang/Analysis/PathSensitive/MemRegion.h @@ -75,6 +75,8 @@ public: const MemSpaceRegion *getMemorySpace() const; + const MemRegion *getBaseRegion() const; + const MemRegion *StripCasts() const; bool hasStackStorage() const; diff --git a/clang/lib/Analysis/MemRegion.cpp b/clang/lib/Analysis/MemRegion.cpp index ad3d36e79d10..8c0b85c0c729 100644 --- a/clang/lib/Analysis/MemRegion.cpp +++ b/clang/lib/Analysis/MemRegion.cpp @@ -378,6 +378,24 @@ bool MemRegion::hasGlobalsOrParametersStorage() const { return false; } +// getBaseRegion strips away all elements and fields, and get the base region +// of them. +const MemRegion *MemRegion::getBaseRegion() const { + const MemRegion *R = this; + while (true) { + if (const ElementRegion *ER = dyn_cast(R)) { + R = ER->getSuperRegion(); + continue; + } + if (const FieldRegion *FR = dyn_cast(R)) { + R = FR->getSuperRegion(); + continue; + } + break; + } + return R; +} + //===----------------------------------------------------------------------===// // View handling. //===----------------------------------------------------------------------===// diff --git a/clang/lib/Analysis/PointerSubChecker.cpp b/clang/lib/Analysis/PointerSubChecker.cpp index 5cac8aa99e79..20279c67b3eb 100644 --- a/clang/lib/Analysis/PointerSubChecker.cpp +++ b/clang/lib/Analysis/PointerSubChecker.cpp @@ -48,11 +48,17 @@ void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C, const MemRegion *LR = LV.getAsRegion(); const MemRegion *RR = RV.getAsRegion(); - if (!(LR && RR) || (LR == RR)) + if (!(LR && RR)) return; - // We don't reason about SymbolicRegions for now. - if (isa(LR) || isa(RR)) + const MemRegion *BaseLR = LR->getBaseRegion(); + const MemRegion *BaseRR = RR->getBaseRegion(); + + if (BaseLR == BaseRR) + return; + + // Allow arithmetic on different symbolic regions. + if (isa(BaseLR) || isa(BaseRR)) return; if (ExplodedNode *N = C.GenerateNode(B)) { diff --git a/clang/test/Analysis/ptr-arith.c b/clang/test/Analysis/ptr-arith.c index 3659ef33658c..f77d7f5ee5ad 100644 --- a/clang/test/Analysis/ptr-arith.c +++ b/clang/test/Analysis/ptr-arith.c @@ -35,6 +35,11 @@ domain_port (const char *domain_b, const char *domain_e, void f3() { int x, y; int d = &y - &x; // expected-warning{{Subtraction of two pointers that do not point to the same memory chunk may cause incorrect result.}} + + int a[10]; + int *p = &a[2]; + int *q = &a[8]; + d = q-p; // no-warning } void f4() {