clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ProBoundsConstantArrayIndexCheck.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -mframe-pointer=none -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/build-llvm/tools/clang/stage2-bins -resource-dir /usr/lib/llvm-15/lib/clang/15.0.0 -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I tools/clang/tools/extra/clang-tidy/cppcoreguidelines -I /build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/clang-tools-extra/clang-tidy/cppcoreguidelines -I tools/clang/tools/extra/clang-tidy -I /build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/clang/include -I tools/clang/include -I include -I /build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/llvm/include -D _FORTIFY_SOURCE=2 -D NDEBUG -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/x86_64-linux-gnu/c++/10 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/backward -internal-isystem /usr/lib/llvm-15/lib/clang/15.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fmacro-prefix-map=/build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/= -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fcoverage-prefix-map=/build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/= -O3 -Wno-unused-command-line-argument -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-class-memaccess -Wno-redundant-move -Wno-pessimizing-move -Wno-noexcept-type -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/build-llvm/tools/clang/stage2-bins=build-llvm/tools/clang/stage2-bins -fdebug-prefix-map=/build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/= -ferror-limit 19 -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcolor-diagnostics -vectorize-loops -vectorize-slp -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-02-12-012820-35430-1 -x c++ /build/llvm-toolchain-snapshot-15~++20220211101351+43a1756a5d53/clang-tools-extra/clang-tidy/cppcoreguidelines/ProBoundsConstantArrayIndexCheck.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "ProBoundsConstantArrayIndexCheck.h" |
10 | #include "clang/AST/ASTContext.h" |
11 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
12 | #include "clang/Frontend/CompilerInstance.h" |
13 | #include "clang/Lex/Preprocessor.h" |
14 | |
15 | using namespace clang::ast_matchers; |
16 | |
17 | namespace clang { |
18 | namespace tidy { |
19 | namespace cppcoreguidelines { |
20 | |
21 | ProBoundsConstantArrayIndexCheck::ProBoundsConstantArrayIndexCheck( |
22 | StringRef Name, ClangTidyContext *Context) |
23 | : ClangTidyCheck(Name, Context), GslHeader(Options.get("GslHeader", "")), |
24 | Inserter(Options.getLocalOrGlobal("IncludeStyle", |
25 | utils::IncludeSorter::IS_LLVM)) {} |
26 | |
27 | void ProBoundsConstantArrayIndexCheck::storeOptions( |
28 | ClangTidyOptions::OptionMap &Opts) { |
29 | Options.store(Opts, "GslHeader", GslHeader); |
30 | Options.store(Opts, "IncludeStyle", Inserter.getStyle()); |
31 | } |
32 | |
33 | void ProBoundsConstantArrayIndexCheck::registerPPCallbacks( |
34 | const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { |
35 | Inserter.registerPreprocessor(PP); |
36 | } |
37 | |
38 | void ProBoundsConstantArrayIndexCheck::registerMatchers(MatchFinder *Finder) { |
39 | |
40 | |
41 | Finder->addMatcher(arraySubscriptExpr(hasBase(ignoringImpCasts(hasType( |
42 | constantArrayType().bind("type")))), |
43 | hasIndex(expr().bind("index")), |
44 | unless(hasAncestor(decl(isImplicit())))) |
45 | .bind("expr"), |
46 | this); |
47 | |
48 | Finder->addMatcher( |
49 | cxxOperatorCallExpr( |
50 | hasOverloadedOperatorName("[]"), |
51 | hasArgument( |
52 | 0, hasType(cxxRecordDecl(hasName("::std::array")).bind("type"))), |
53 | hasArgument(1, expr().bind("index"))) |
54 | .bind("expr"), |
55 | this); |
56 | } |
57 | |
58 | void ProBoundsConstantArrayIndexCheck::check( |
59 | const MatchFinder::MatchResult &Result) { |
60 | const auto *Matched = Result.Nodes.getNodeAs<Expr>("expr"); |
61 | const auto *IndexExpr = Result.Nodes.getNodeAs<Expr>("index"); |
62 | |
63 | if (IndexExpr->isValueDependent()) |
| 1 | Assuming the condition is false | |
|
| |
64 | return; |
65 | |
66 | Optional<llvm::APSInt> Index = |
67 | IndexExpr->getIntegerConstantExpr(*Result.Context); |
68 | if (!Index) { |
| 3 | | Assuming the condition is true | |
|
| |
69 | SourceRange BaseRange; |
70 | if (const auto *ArraySubscriptE = dyn_cast<ArraySubscriptExpr>(Matched)) |
| 5 | | Assuming 'Matched' is not a 'ArraySubscriptExpr' | |
|
| |
71 | BaseRange = ArraySubscriptE->getBase()->getSourceRange(); |
72 | else |
73 | BaseRange = |
74 | dyn_cast<CXXOperatorCallExpr>(Matched)->getArg(0)->getSourceRange(); |
| 7 | | Assuming 'Matched' is not a 'CXXOperatorCallExpr' | |
|
| 8 | | Called C++ object pointer is null |
|
75 | SourceRange IndexRange = IndexExpr->getSourceRange(); |
76 | |
77 | auto Diag = diag(Matched->getExprLoc(), |
78 | "do not use array subscript when the index is " |
79 | "not an integer constant expression"); |
80 | if (!GslHeader.empty()) { |
81 | Diag << FixItHint::CreateInsertion(BaseRange.getBegin(), "gsl::at(") |
82 | << FixItHint::CreateReplacement( |
83 | SourceRange(BaseRange.getEnd().getLocWithOffset(1), |
84 | IndexRange.getBegin().getLocWithOffset(-1)), |
85 | ", ") |
86 | << FixItHint::CreateReplacement(Matched->getEndLoc(), ")") |
87 | << Inserter.createMainFileIncludeInsertion(GslHeader); |
88 | } |
89 | return; |
90 | } |
91 | |
92 | const auto *StdArrayDecl = |
93 | Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("type"); |
94 | |
95 | |
96 | if (!StdArrayDecl) |
97 | return; |
98 | |
99 | if (Index->isSigned() && Index->isNegative()) { |
100 | diag(Matched->getExprLoc(), "std::array<> index %0 is negative") |
101 | << toString(*Index, 10); |
102 | return; |
103 | } |
104 | |
105 | const TemplateArgumentList &TemplateArgs = StdArrayDecl->getTemplateArgs(); |
106 | if (TemplateArgs.size() < 2) |
107 | return; |
108 | |
109 | const auto &SizeArg = TemplateArgs[1]; |
110 | if (SizeArg.getKind() != TemplateArgument::Integral) |
111 | return; |
112 | llvm::APInt ArraySize = SizeArg.getAsIntegral(); |
113 | |
114 | |
115 | |
116 | if (Index->getZExtValue() >= ArraySize.getZExtValue()) { |
117 | diag(Matched->getExprLoc(), |
118 | "std::array<> index %0 is past the end of the array " |
119 | "(which contains %1 elements)") |
120 | << toString(*Index, 10) << toString(ArraySize, 10, false); |
121 | } |
122 | } |
123 | |
124 | } |
125 | } |
126 | } |