balazske created this revision.
Herald added subscribers: manas, steakhal, ASDenysPetrov, martong, gamesh411, 
dkrupp, donat.nagy, Szelethus, arphaman, mikhail.ramalho, a.sidorin, szepet, 
baloghadamsoftware, xazax.hun, whisperity.
Herald added a reviewer: Szelethus.
balazske requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

The checker did not work with negative array index at return.
Specially for -1 it did not produce a bug.
`assumeInBound` may not work correct with negative values so a pre-
check is added to the checker for negative array index.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D107960

Files:
  clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
  clang/test/Analysis/return-ptr-range.cpp

Index: clang/test/Analysis/return-ptr-range.cpp
===================================================================
--- clang/test/Analysis/return-ptr-range.cpp
+++ clang/test/Analysis/return-ptr-range.cpp
@@ -115,3 +115,24 @@
 
 }
 
+int *test_negative_index(int I) {
+  static int arr[10]; // expected-note{{Original object declared here}}
+                      // expected-note@-1{{'arr' initialized here}}
+                      // expected-note@-2{{Original object declared here}}
+                      // expected-note@-3{{'arr' initialized here}}
+  if (I == -1)        // expected-note{{Assuming the condition is true}}
+                      // expected-note@-1{{Taking true branch}}
+                      // expected-note@-2{{Assuming the condition is false}}
+                      // expected-note@-3{{Taking false branch}}
+    return arr + I;   // expected-warning{{Returned pointer value points outside the original object}}
+                      // expected-note@-1{{Returned pointer value points outside the original object}}
+                      // expected-note@-2{{Original object 'arr' is an array of 10 'int' objects, returned pointer points at index -1}}
+  if (I == -2)        // expected-note{{Assuming the condition is true}}
+                      // expected-note@-1{{Taking true branch}}
+    return arr + I;   // expected-warning{{Returned pointer value points outside the original object}}
+                      // expected-note@-1{{Returned pointer value points outside the original object}}
+                      // expected-note@-2{{Original object 'arr' is an array of 10 'int' objects, returned pointer points at index -2}}
+  if (I == 0)
+    return arr + I;
+  return arr + I;
+}
Index: clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -64,61 +64,79 @@
   if (Idx == ElementCount)
     return;
 
-  ProgramStateRef StInBound = state->assumeInBound(Idx, ElementCount, true);
-  ProgramStateRef StOutBound = state->assumeInBound(Idx, ElementCount, false);
-  if (StOutBound && !StInBound) {
-    ExplodedNode *N = C.generateErrorNode(StOutBound);
-
-    if (!N)
+  auto ElementCountNL = ElementCount.getAs<NonLoc>();
+  assert(ElementCountNL && "Array size should not be a pointer");
+  auto IdxNegativeVal =
+      C.getSValBuilder()
+          .evalBinOpNN(state, BO_LT, *ElementCountNL,
+                       C.getSValBuilder().makeZeroArrayIndex(),
+                       C.getSValBuilder().getConditionType())
+          .castAs<DefinedOrUnknownSVal>();
+  ProgramStateRef IdxNegative, IdxNonNegative;
+  std::tie(IdxNegative, IdxNonNegative) = state->assume(IdxNegativeVal);
+
+  ProgramStateRef StError;
+  if (IdxNegative && !IdxNonNegative) {
+    StError = IdxNegative;
+  } else {
+    ProgramStateRef StInBound = state->assumeInBound(Idx, ElementCount, true);
+    ProgramStateRef StOutBound = state->assumeInBound(Idx, ElementCount, false);
+    if (StOutBound && !StInBound)
+      StError = StOutBound;
+    else
       return;
+  }
 
-    // FIXME: This bug correspond to CWE-466.  Eventually we should have bug
-    // types explicitly reference such exploit categories (when applicable).
-    if (!BT)
-      BT.reset(new BuiltinBug(
-          this, "Buffer overflow",
-          "Returned pointer value points outside the original object "
-          "(potential buffer overflow)"));
-
-    // Generate a report for this bug.
-    auto Report =
-        std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
-    Report->addRange(RetE->getSourceRange());
-
-    const auto ConcreteElementCount = ElementCount.getAs<nonloc::ConcreteInt>();
-    const auto ConcreteIdx = Idx.getAs<nonloc::ConcreteInt>();
-
-    const auto *DeclR = ER->getSuperRegion()->getAs<DeclRegion>();
-
-    if (DeclR)
-      Report->addNote("Original object declared here",
-                      {DeclR->getDecl(), C.getSourceManager()});
-
-    if (ConcreteElementCount) {
-      SmallString<128> SBuf;
-      llvm::raw_svector_ostream OS(SBuf);
-      OS << "Original object ";
-      if (DeclR) {
-        OS << "'";
-        DeclR->getDecl()->printName(OS);
-        OS << "' ";
-      }
-      OS << "is an array of " << ConcreteElementCount->getValue() << " '";
-      ER->getValueType().print(OS,
-                               PrintingPolicy(C.getASTContext().getLangOpts()));
-      OS << "' objects";
-      if (ConcreteIdx) {
-        OS << ", returned pointer points at index " << ConcreteIdx->getValue();
-      }
-
-      Report->addNote(SBuf,
-                      {RetE, C.getSourceManager(), C.getLocationContext()});
-    }
+  ExplodedNode *N = C.generateErrorNode(StError);
 
-    bugreporter::trackExpressionValue(N, RetE, *Report);
+  if (!N)
+    return;
 
-    C.emitReport(std::move(Report));
+  // FIXME: This bug correspond to CWE-466.  Eventually we should have bug
+  // types explicitly reference such exploit categories (when applicable).
+  if (!BT)
+    BT.reset(new BuiltinBug(
+        this, "Buffer overflow",
+        "Returned pointer value points outside the original object "
+        "(potential buffer overflow)"));
+
+  // Generate a report for this bug.
+  auto Report =
+      std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
+  Report->addRange(RetE->getSourceRange());
+
+  const auto ConcreteElementCount = ElementCount.getAs<nonloc::ConcreteInt>();
+  const auto ConcreteIdx = Idx.getAs<nonloc::ConcreteInt>();
+
+  const auto *DeclR = ER->getSuperRegion()->getAs<DeclRegion>();
+
+  if (DeclR)
+    Report->addNote("Original object declared here",
+                    {DeclR->getDecl(), C.getSourceManager()});
+
+  if (ConcreteElementCount) {
+    SmallString<128> SBuf;
+    llvm::raw_svector_ostream OS(SBuf);
+    OS << "Original object ";
+    if (DeclR) {
+      OS << "'";
+      DeclR->getDecl()->printName(OS);
+      OS << "' ";
+    }
+    OS << "is an array of " << ConcreteElementCount->getValue() << " '";
+    ER->getValueType().print(OS,
+                             PrintingPolicy(C.getASTContext().getLangOpts()));
+    OS << "' objects";
+    if (ConcreteIdx) {
+      OS << ", returned pointer points at index " << ConcreteIdx->getValue();
+    }
+
+    Report->addNote(SBuf, {RetE, C.getSourceManager(), C.getLocationContext()});
   }
+
+  bugreporter::trackExpressionValue(N, RetE, *Report);
+
+  C.emitReport(std::move(Report));
 }
 
 void ento::registerReturnPointerRangeChecker(CheckerManager &mgr) {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to