diff options
| author | Alexander Droste <alexander.ra.droste@gmail.com> | 2016-08-12 19:30:31 +0000 |
|---|---|---|
| committer | Alexander Droste <alexander.ra.droste@gmail.com> | 2016-08-12 19:30:31 +0000 |
| commit | 1512f9a0f96f2795ca497099d3d39ed30cdaea33 (patch) | |
| tree | 2a882a91b985b237d94b92dcd61b488060170dcf /clang-tools-extra/clang-tidy/mpi | |
| parent | af32ccb195ece1a25511d1d35d8c14ce1b58ee9b (diff) | |
| download | bcm5719-llvm-1512f9a0f96f2795ca497099d3d39ed30cdaea33.tar.gz bcm5719-llvm-1512f9a0f96f2795ca497099d3d39ed30cdaea33.zip | |
[clang-tidy] MPIBufferDerefCheck
...
This check verifies if a buffer passed to an MPI (Message Passing Interface)
function is sufficiently dereferenced. Buffers should be passed as a single
pointer or array. As MPI function signatures specify void * for their buffer
types, insufficiently dereferenced buffers can be passed, like for example
as double pointers or multidimensional arrays, without a compiler warning
emitted.
Instructions on how to apply the check can be found at:
https://github.com/0ax1/MPI-Checker/tree/master/examples
Reviewers: Haojian Wu
Differential revision: https://reviews.llvm.org/D22729
llvm-svn: 278553
Diffstat (limited to 'clang-tools-extra/clang-tidy/mpi')
4 files changed, 186 insertions, 0 deletions
diff --git a/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.cpp b/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.cpp new file mode 100644 index 00000000000..8e2c0e34e13 --- /dev/null +++ b/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.cpp @@ -0,0 +1,132 @@ +//===--- BufferDerefCheck.cpp - clang-tidy---------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "BufferDerefCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/StaticAnalyzer/Checkers/MPIFunctionClassifier.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace mpi { + +void BufferDerefCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher(callExpr().bind("CE"), this); +} + +void BufferDerefCheck::check(const MatchFinder::MatchResult &Result) { + static ento::mpi::MPIFunctionClassifier FuncClassifier(*Result.Context); + const auto *CE = Result.Nodes.getNodeAs<CallExpr>("CE"); + if (!CE->getDirectCallee()) + return; + + const IdentifierInfo *Identifier = CE->getDirectCallee()->getIdentifier(); + if (!Identifier || !FuncClassifier.isMPIType(Identifier)) + return; + + // These containers are used, to capture the type and expression of a buffer. + SmallVector<const Type *, 1> BufferTypes; + SmallVector<const Expr *, 1> BufferExprs; + + // Adds the type and expression of a buffer that is used in the MPI call + // expression to the captured containers. + auto addBuffer = [&CE, &Result, &BufferTypes, + &BufferExprs](const size_t BufferIdx) { + // Skip null pointer constants and in place 'operators'. + if (CE->getArg(BufferIdx)->isNullPointerConstant( + *Result.Context, Expr::NPC_ValueDependentIsNull) || + tooling::fixit::getText(*CE->getArg(BufferIdx), *Result.Context) == + "MPI_IN_PLACE") + return; + + const Expr *ArgExpr = CE->getArg(BufferIdx); + if (!ArgExpr) + return; + const Type *ArgType = ArgExpr->IgnoreImpCasts()->getType().getTypePtr(); + if (!ArgType) + return; + BufferExprs.push_back(ArgExpr); + BufferTypes.push_back(ArgType); + }; + + // Collect buffer types and argument expressions for all buffers used in the + // MPI call expression. The number passed to the lambda corresponds to the + // argument index of the currently verified MPI function call. + if (FuncClassifier.isPointToPointType(Identifier)) { + addBuffer(0); + } else if (FuncClassifier.isCollectiveType(Identifier)) { + if (FuncClassifier.isReduceType(Identifier)) { + addBuffer(0); + addBuffer(1); + } else if (FuncClassifier.isScatterType(Identifier) || + FuncClassifier.isGatherType(Identifier) || + FuncClassifier.isAlltoallType(Identifier)) { + addBuffer(0); + addBuffer(3); + } else if (FuncClassifier.isBcastType(Identifier)) { + addBuffer(0); + } + } + + checkBuffers(BufferTypes, BufferExprs); +} + +void BufferDerefCheck::checkBuffers(ArrayRef<const Type *> BufferTypes, + ArrayRef<const Expr *> BufferExprs) { + for (size_t i = 0; i < BufferTypes.size(); ++i) { + unsigned IndirectionCount = 0; + const Type *BufferType = BufferTypes[i]; + llvm::SmallVector<IndirectionType, 1> Indirections; + + // Capture the depth and types of indirections for the passed buffer. + while (true) { + if (BufferType->isPointerType()) { + BufferType = BufferType->getPointeeType().getTypePtr(); + Indirections.push_back(IndirectionType::Pointer); + } else if (BufferType->isArrayType()) { + BufferType = BufferType->getArrayElementTypeNoTypeQual(); + Indirections.push_back(IndirectionType::Array); + } else { + break; + } + ++IndirectionCount; + } + + if (IndirectionCount > 1) { + // Referencing an array with '&' is valid, as this also points to the + // beginning of the array. + if (IndirectionCount == 2 && + Indirections[0] == IndirectionType::Pointer && + Indirections[1] == IndirectionType::Array) + return; + + // Build the indirection description in reverse order of discovery. + std::string IndirectionDesc; + for (auto It = Indirections.rbegin(); It != Indirections.rend(); ++It) { + if (!IndirectionDesc.empty()) + IndirectionDesc += "->"; + if (*It == IndirectionType::Pointer) { + IndirectionDesc += "pointer"; + } else { + IndirectionDesc += "array"; + } + } + + const auto Loc = BufferExprs[i]->getSourceRange().getBegin(); + diag(Loc, "buffer is insufficiently dereferenced: %0") << IndirectionDesc; + } + } +} + +} // namespace mpi +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.h b/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.h new file mode 100644 index 00000000000..8490fa1c852 --- /dev/null +++ b/clang-tools-extra/clang-tidy/mpi/BufferDerefCheck.h @@ -0,0 +1,51 @@ +//===--- BufferDerefCheck.h - clang-tidy-------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_BUFFER_DEREF_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_BUFFER_DEREF_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace mpi { + +/// This check verifies if a buffer passed to an MPI (Message Passing Interface) +/// function is sufficiently dereferenced. Buffers should be passed as a single +/// pointer or array. As MPI function signatures specify void * for their buffer +/// types, insufficiently dereferenced buffers can be passed, like for example +/// as double pointers or multidimensional arrays, without a compiler warning +/// emitted. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/mpi-buffer-deref.html +class BufferDerefCheck : public ClangTidyCheck { +public: + BufferDerefCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + /// Checks for all buffers in an MPI call if they are sufficiently + /// dereferenced. + /// + /// \param BufferTypes buffer types + /// \param BufferExprs buffer arguments as expressions + void checkBuffers(ArrayRef<const Type *> BufferTypes, + ArrayRef<const Expr *> BufferExprs); + + enum class IndirectionType : unsigned char { Pointer, Array }; +}; + +} // namespace mpi +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MPI_BUFFER_DEREF_H diff --git a/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt b/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt index 15bfb337816..36584342c2e 100644 --- a/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/mpi/CMakeLists.txt @@ -1,6 +1,7 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTidyMPIModule + BufferDerefCheck.cpp MPITidyModule.cpp TypeMismatchCheck.cpp diff --git a/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp b/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp index babf7b6ad20..55e187dbe0a 100644 --- a/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp +++ b/clang-tools-extra/clang-tidy/mpi/MPITidyModule.cpp @@ -10,6 +10,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "BufferDerefCheck.h" #include "TypeMismatchCheck.h" namespace clang { @@ -19,6 +20,7 @@ namespace mpi { class MPIModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck<BufferDerefCheck>("mpi-buffer-deref"); CheckFactories.registerCheck<TypeMismatchCheck>("mpi-type-mismatch"); } }; |

