clang-tools 6.0.0

BufferDerefCheck.cpp
Go to the documentation of this file.
1 //===--- BufferDerefCheck.cpp - clang-tidy---------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "BufferDerefCheck.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h"
14 #include "clang/Tooling/FixIt.h"
15
16 using namespace clang::ast_matchers;
17
18 namespace clang {
19 namespace tidy {
20 namespace mpi {
21
22 void BufferDerefCheck::registerMatchers(MatchFinder *Finder) {
23 Finder->addMatcher(callExpr().bind("CE"), this);
24 }
25
26 void BufferDerefCheck::check(const MatchFinder::MatchResult &Result) {
27 static ento::mpi::MPIFunctionClassifier FuncClassifier(*Result.Context);
28 const auto *CE = Result.Nodes.getNodeAs<CallExpr>("CE");
29 if (!CE->getDirectCallee())
30 return;
31
32 const IdentifierInfo *Identifier = CE->getDirectCallee()->getIdentifier();
33 if (!Identifier || !FuncClassifier.isMPIType(Identifier))
34 return;
35
36 // These containers are used, to capture the type and expression of a buffer.
37 SmallVector<const Type *, 1> BufferTypes;
38 SmallVector<const Expr *, 1> BufferExprs;
39
40 // Adds the type and expression of a buffer that is used in the MPI call
41 // expression to the captured containers.
42 auto addBuffer = [&CE, &Result, &BufferTypes,
43 &BufferExprs](const size_t BufferIdx) {
44 // Skip null pointer constants and in place 'operators'.
45 if (CE->getArg(BufferIdx)->isNullPointerConstant(
46 *Result.Context, Expr::NPC_ValueDependentIsNull) ||
47 tooling::fixit::getText(*CE->getArg(BufferIdx), *Result.Context) ==
48 "MPI_IN_PLACE")
49 return;
50
51 const Expr *ArgExpr = CE->getArg(BufferIdx);
52 if (!ArgExpr)
53 return;
54 const Type *ArgType = ArgExpr->IgnoreImpCasts()->getType().getTypePtr();
55 if (!ArgType)
56 return;
57 BufferExprs.push_back(ArgExpr);
58 BufferTypes.push_back(ArgType);
59 };
60
61 // Collect buffer types and argument expressions for all buffers used in the
62 // MPI call expression. The number passed to the lambda corresponds to the
63 // argument index of the currently verified MPI function call.
64 if (FuncClassifier.isPointToPointType(Identifier)) {
65 addBuffer(0);
66 } else if (FuncClassifier.isCollectiveType(Identifier)) {
67 if (FuncClassifier.isReduceType(Identifier)) {
68 addBuffer(0);
69 addBuffer(1);
70 } else if (FuncClassifier.isScatterType(Identifier) ||
71 FuncClassifier.isGatherType(Identifier) ||
72 FuncClassifier.isAlltoallType(Identifier)) {
73 addBuffer(0);
74 addBuffer(3);
75 } else if (FuncClassifier.isBcastType(Identifier)) {
76 addBuffer(0);
77 }
78 }
79
80 checkBuffers(BufferTypes, BufferExprs);
81 }
82
83 void BufferDerefCheck::checkBuffers(ArrayRef<const Type *> BufferTypes,
84 ArrayRef<const Expr *> BufferExprs) {
85 for (size_t i = 0; i < BufferTypes.size(); ++i) {
86 unsigned IndirectionCount = 0;
87 const Type *BufferType = BufferTypes[i];
88 llvm::SmallVector<IndirectionType, 1> Indirections;
89
90 // Capture the depth and types of indirections for the passed buffer.
91 while (true) {
92 if (BufferType->isPointerType()) {
93 BufferType = BufferType->getPointeeType().getTypePtr();
94 Indirections.push_back(IndirectionType::Pointer);
95 } else if (BufferType->isArrayType()) {
96 BufferType = BufferType->getArrayElementTypeNoTypeQual();
97 Indirections.push_back(IndirectionType::Array);
98 } else {
99 break;
100 }
101 ++IndirectionCount;
102 }
103
104 if (IndirectionCount > 1) {
105 // Referencing an array with '&' is valid, as this also points to the
106 // beginning of the array.
107 if (IndirectionCount == 2 &&
108 Indirections[0] == IndirectionType::Pointer &&
109 Indirections[1] == IndirectionType::Array)
110 return;
111
112 // Build the indirection description in reverse order of discovery.
113 std::string IndirectionDesc;
114 for (auto It = Indirections.rbegin(); It != Indirections.rend(); ++It) {
115 if (!IndirectionDesc.empty())
116 IndirectionDesc += "->";
117 if (*It == IndirectionType::Pointer) {
118 IndirectionDesc += "pointer";
119 } else {
120 IndirectionDesc += "array";
121 }
122 }
123
124 const auto Loc = BufferExprs[i]->getSourceRange().getBegin();
125 diag(Loc, "buffer is insufficiently dereferenced: %0") << IndirectionDesc;
126 }
127 }
128 }
129
130 } // namespace mpi
131 } // namespace tidy
132 } // namespace clang
Loc
SourceLocation Loc
&#39;#&#39; location in the include directive
Definition: IncludeOrderCheck.cpp:36
clang::ast_matchers
Definition: ClangTidyDiagnosticConsumer.h:27
clang
Definition: AndroidTidyModule.cpp:28
BufferDerefCheck.h