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