This revision was automatically updated to reflect the committed changes.
Closed by commit rGa46154cb1cd0: [analyzer] Warn if the size of the array in 
`new[]` is undefined (authored by isuckatcs).
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D131299/new/

https://reviews.llvm.org/D131299

Files:
  clang/docs/analyzer/checkers.rst
  clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
  clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
  clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
  clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
  clang/test/Analysis/Issue56873.cpp
  clang/test/Analysis/undefined-new-element.cpp

Index: clang/test/Analysis/undefined-new-element.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/undefined-new-element.cpp
@@ -0,0 +1,69 @@
+// RUN: %clang_analyze_cc1 %s -analyzer-checker=core.uninitialized.NewArraySize -analyzer-output=text -verify
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void checkUndefinedElmenetCountValue() {
+  int n;
+  // expected-note@-1{{'n' declared without an initial value}}
+
+  int *arr = new int[n]; // expected-warning{{Element count in new[] is a garbage value}}
+  // expected-note@-1{{Element count in new[] is a garbage value}}
+}
+
+void checkUndefinedElmenetCountMultiDimensionalValue() {
+  int n;
+  // expected-note@-1{{'n' declared without an initial value}}
+
+  auto *arr = new int[n][5]; // expected-warning{{Element count in new[] is a garbage value}}
+  // expected-note@-1{{Element count in new[] is a garbage value}}
+}
+
+void checkUndefinedElmenetCountReference() {
+  int n;
+  // expected-note@-1{{'n' declared without an initial value}}
+
+  int &ref = n;
+  // expected-note@-1{{'ref' initialized here}}
+
+  int *arr = new int[ref]; // expected-warning{{Element count in new[] is a garbage value}}
+  // expected-note@-1{{Element count in new[] is a garbage value}}
+}
+
+void checkUndefinedElmenetCountMultiDimensionalReference() {
+  int n;
+  // expected-note@-1{{'n' declared without an initial value}}
+
+  int &ref = n;
+  // expected-note@-1{{'ref' initialized here}}
+
+  auto *arr = new int[ref][5]; // expected-warning{{Element count in new[] is a garbage value}}
+  // expected-note@-1{{Element count in new[] is a garbage value}}
+}
+
+int foo() {
+  int n;
+
+  return n;
+}
+
+void checkUndefinedElmenetCountFunction() {
+  int *arr = new int[foo()]; // expected-warning{{Element count in new[] is a garbage value}}
+  // expected-note@-1{{Element count in new[] is a garbage value}}
+}
+
+void checkUndefinedElmenetCountMultiDimensionalFunction() {
+  auto *arr = new int[foo()][5]; // expected-warning{{Element count in new[] is a garbage value}}
+  // expected-note@-1{{Element count in new[] is a garbage value}}
+}
+
+void *malloc(size_t);
+
+void checkUndefinedPlacementElementCount() {
+  int n;
+  // expected-note@-1{{'n' declared without an initial value}}
+  
+  void *buffer = malloc(sizeof(std::string) * 10);
+  std::string *p =
+      ::new (buffer) std::string[n]; // expected-warning{{Element count in new[] is a garbage value}}
+  // expected-note@-1{{Element count in new[] is a garbage value}}
+}
Index: clang/test/Analysis/Issue56873.cpp
===================================================================
--- clang/test/Analysis/Issue56873.cpp
+++ clang/test/Analysis/Issue56873.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -verify %s
 
 void clang_analyzer_warnIfReached();
 
Index: clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
===================================================================
--- /dev/null
+++ clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
@@ -0,0 +1,80 @@
+//===--- UndefinedNewArraySizeChecker.cpp -----------------------*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines UndefinedNewArraySizeChecker, a builtin check in ExprEngine
+// that checks if the size of the array in a new[] expression is undefined.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class UndefinedNewArraySizeChecker : public Checker<check::PreCall> {
+
+private:
+  BugType BT{this, "Undefined array element count in new[]",
+             categories::LogicError};
+
+public:
+  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+  void HandleUndefinedArrayElementCount(CheckerContext &C, SVal ArgVal,
+                                        const Expr *Init,
+                                        SourceRange Range) const;
+};
+} // namespace
+
+void UndefinedNewArraySizeChecker::checkPreCall(const CallEvent &Call,
+                                                CheckerContext &C) const {
+  if (const auto *AC = dyn_cast<CXXAllocatorCall>(&Call)) {
+    if (!AC->isArray())
+      return;
+
+    auto *SizeEx = *AC->getArraySizeExpr();
+    auto SizeVal = AC->getArraySizeVal();
+
+    if (SizeVal.isUndef())
+      HandleUndefinedArrayElementCount(C, SizeVal, SizeEx,
+                                       SizeEx->getSourceRange());
+  }
+}
+
+void UndefinedNewArraySizeChecker::HandleUndefinedArrayElementCount(
+    CheckerContext &C, SVal ArgVal, const Expr *Init, SourceRange Range) const {
+
+  if (ExplodedNode *N = C.generateErrorNode()) {
+
+    SmallString<100> buf;
+    llvm::raw_svector_ostream os(buf);
+
+    os << "Element count in new[] is a garbage value";
+
+    auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
+    R->markInteresting(ArgVal);
+    R->addRange(Range);
+    bugreporter::trackExpressionValue(N, Init, *R);
+
+    C.emitReport(std::move(R));
+  }
+}
+
+void ento::registerUndefinedNewArraySizeChecker(CheckerManager &mgr) {
+  mgr.registerChecker<UndefinedNewArraySizeChecker>();
+}
+
+bool ento::shouldRegisterUndefinedNewArraySizeChecker(
+    const CheckerManager &mgr) {
+  return mgr.getLangOpts().CPlusPlus;
+}
Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1733,6 +1733,10 @@
   // Fill the region with the initialization value.
   State = State->bindDefaultInitial(RetVal, Init, LCtx);
 
+  // If Size is somehow undefined at this point, this line prevents a crash.
+  if (Size.isUndef())
+    Size = UnknownVal();
+
   // Set the region's extent.
   State = setDynamicExtent(State, RetVal.getAsRegion(),
                            Size.castAs<DefinedOrUnknownSVal>(), svalBuilder);
Index: clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -120,6 +120,7 @@
   UndefResultChecker.cpp
   UndefinedArraySubscriptChecker.cpp
   UndefinedAssignmentChecker.cpp
+  UndefinedNewArraySizeChecker.cpp
   UninitializedObject/UninitializedObjectChecker.cpp
   UninitializedObject/UninitializedPointee.cpp
   UnixAPIChecker.cpp
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -1033,6 +1033,18 @@
     return getOriginExpr()->getNumPlacementArgs() + getNumImplicitArgs();
   }
 
+  bool isArray() const { return getOriginExpr()->isArray(); }
+
+  Optional<const clang::Expr *> getArraySizeExpr() const {
+    return getOriginExpr()->getArraySize();
+  }
+
+  SVal getArraySizeVal() const {
+    assert(isArray() && "The allocator call doesn't allocate and array!");
+
+    return getState()->getSVal(*getArraySizeExpr(), getLocationContext());
+  }
+
   const Expr *getArgExpr(unsigned Index) const override {
     // The first argument of an allocator call is the size of the allocation.
     if (Index < getNumImplicitArgs())
Index: clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -437,6 +437,10 @@
   HelpText<"Check for uninitialized values being returned to the caller">,
   Documentation<HasDocumentation>;
 
+def UndefinedNewArraySizeChecker : Checker<"NewArraySize">,
+  HelpText<"Check if the size of the array in a new[] expression is undefined">,
+  Documentation<HasDocumentation>;
+
 } // end "core.uninitialized"
 
 //===----------------------------------------------------------------------===//
Index: clang/docs/analyzer/checkers.rst
===================================================================
--- clang/docs/analyzer/checkers.rst
+++ clang/docs/analyzer/checkers.rst
@@ -245,6 +245,22 @@
    return x; // warn
  }
 
+.. _core-uninitialized-NewArraySize:
+
+core.uninitialized.NewArraySize (C++)
+"""""""""""""""""""""""""""""""""""""
+
+Check if the element count in new[] is garbage or undefined.
+
+.. code-block:: cpp
+
+  void test() {
+    int n;
+    int *arr = new int[n]; // warn: Element count in new[] is a garbage value
+    delete[] arr;
+  }
+
+
 .. _cplusplus-checkers:
 
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to