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