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