xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp (revision a46154cb1cd09aa26bc803d8696e6e9283aac6a9)
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