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