1//===--- UndefinedNewArraySizeChecker.cpp -----------------------*- C++ -*--==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This defines UndefinedNewArraySizeChecker, a builtin check in ExprEngine
10// that checks if the size of the array in a new[] expression is undefined.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
16#include "clang/StaticAnalyzer/Core/Checker.h"
17#include "clang/StaticAnalyzer/Core/CheckerManager.h"
18#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
19#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20
21using namespace clang;
22using namespace ento;
23
24namespace {
25class UndefinedNewArraySizeChecker : public Checker<check::PreCall> {
26
27private:
28  BugType BT{this, "Undefined array element count in new[]",
29             categories::LogicError};
30
31public:
32  void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
33  void HandleUndefinedArrayElementCount(CheckerContext &C, SVal ArgVal,
34                                        const Expr *Init,
35                                        SourceRange Range) const;
36};
37} // namespace
38
39void UndefinedNewArraySizeChecker::checkPreCall(const CallEvent &Call,
40                                                CheckerContext &C) const {
41  if (const auto *AC = dyn_cast<CXXAllocatorCall>(&Call)) {
42    if (!AC->isArray())
43      return;
44
45    auto *SizeEx = *AC->getArraySizeExpr();
46    auto SizeVal = AC->getArraySizeVal();
47
48    if (SizeVal.isUndef())
49      HandleUndefinedArrayElementCount(C, SizeVal, SizeEx,
50                                       SizeEx->getSourceRange());
51  }
52}
53
54void UndefinedNewArraySizeChecker::HandleUndefinedArrayElementCount(
55    CheckerContext &C, SVal ArgVal, const Expr *Init, SourceRange Range) const {
56
57  if (ExplodedNode *N = C.generateErrorNode()) {
58
59    SmallString<100> buf;
60    llvm::raw_svector_ostream os(buf);
61
62    os << "Element count in new[] is a garbage value";
63
64    auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
65    R->markInteresting(ArgVal);
66    R->addRange(Range);
67    bugreporter::trackExpressionValue(N, Init, *R);
68
69    C.emitReport(std::move(R));
70  }
71}
72
73void ento::registerUndefinedNewArraySizeChecker(CheckerManager &mgr) {
74  mgr.registerChecker<UndefinedNewArraySizeChecker>();
75}
76
77bool ento::shouldRegisterUndefinedNewArraySizeChecker(
78    const CheckerManager &mgr) {
79  return mgr.getLangOpts().CPlusPlus;
80}
81