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