Author: alexander_droste
Date: Fri Aug 12 14:30:31 2016
New Revision: 278553

URL: http://llvm.org/viewvc/llvm-project?rev=278553&view=rev
Log:
[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


Added:
    clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.cpp
    clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/mpi-buffer-deref.rst
    clang-tools-extra/trunk/test/clang-tidy/mpi-buffer-deref.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/mpi/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/mpi/MPITidyModule.cpp
    clang-tools-extra/trunk/docs/ReleaseNotes.rst
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
    clang-tools-extra/trunk/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h

Added: clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.cpp?rev=278553&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.cpp Fri Aug 12 
14:30:31 2016
@@ -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

Added: clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.h
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.h?rev=278553&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/mpi/BufferDerefCheck.h Fri Aug 12 
14:30:31 2016
@@ -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

Modified: clang-tools-extra/trunk/clang-tidy/mpi/CMakeLists.txt
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/mpi/CMakeLists.txt?rev=278553&r1=278552&r2=278553&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/mpi/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/mpi/CMakeLists.txt Fri Aug 12 14:30:31 
2016
@@ -1,6 +1,7 @@
 set(LLVM_LINK_COMPONENTS support)
 
 add_clang_library(clangTidyMPIModule
+  BufferDerefCheck.cpp
   MPITidyModule.cpp
   TypeMismatchCheck.cpp
 

Modified: clang-tools-extra/trunk/clang-tidy/mpi/MPITidyModule.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/mpi/MPITidyModule.cpp?rev=278553&r1=278552&r2=278553&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/mpi/MPITidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/mpi/MPITidyModule.cpp Fri Aug 12 
14:30:31 2016
@@ -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");
   }
 };

Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=278553&r1=278552&r2=278553&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Fri Aug 12 14:30:31 2016
@@ -69,6 +69,16 @@ Improvements to clang-tidy
 
   Flags classes where some, but not all, special member functions are 
user-defined.
 
+- New `mpi-buffer-deref
+  <http://clang.llvm.org/extra/clang-tidy/checks/mpi-buffer-deref.html>`_ check
+
+  Flags buffers which are insufficiently dereferenced when passed to an MPI 
function call.
+
+- New `mpi-type-mismatch
+  <http://clang.llvm.org/extra/clang-tidy/checks/mpi-type-mismatch.html>`_ 
check
+
+  Flags MPI function calls with a buffer type and MPI data type mismatch.
+
 - New `performance-inefficient-string-concatenation
   
<http://clang.llvm.org/extra/clang-tidy/checks/performance-inefficient-string-concatenation.html>`_
 check
 

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=278553&r1=278552&r2=278553&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Fri Aug 12 14:30:31 
2016
@@ -110,6 +110,7 @@ Clang-Tidy Checks
    modernize-use-nullptr
    modernize-use-override
    modernize-use-using
+   mpi-buffer-deref
    mpi-type-mismatch
    performance-faster-string-find
    performance-for-range-copy

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/mpi-buffer-deref.rst
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/mpi-buffer-deref.rst?rev=278553&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/mpi-buffer-deref.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/mpi-buffer-deref.rst Fri Aug 
12 14:30:31 2016
@@ -0,0 +1,25 @@
+.. title:: clang-tidy - mpi-buffer-deref
+
+mpi-buffer-deref
+================
+
+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.
+
+Examples:
+.. code:: c++
+
+  // A double pointer is passed to the MPI function.
+  char *buf;
+  MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+  // A multidimensional array is passed to the MPI function.
+  short buf[1][1];
+  MPI_Send(buf, 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
+
+  // A pointer to an array is passed to the MPI function.
+  short *buf[1];
+  MPI_Send(buf, 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);

Modified: 
clang-tools-extra/trunk/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h?rev=278553&r1=278552&r2=278553&view=diff
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h 
(original)
+++ clang-tools-extra/trunk/test/clang-tidy/Inputs/mpi-type-mismatch/mpimock.h 
Fri Aug 12 14:30:31 2016
@@ -24,6 +24,7 @@ namespace std { template<class T> struct
 #define MPI_DATATYPE_NULL 0
 #define MPI_CHAR 0
 #define MPI_BYTE 0
+#define MPI_SHORT 0
 #define MPI_INT 0
 #define MPI_LONG 0
 #define MPI_LONG_DOUBLE 0
@@ -31,6 +32,7 @@ namespace std { template<class T> struct
 #define MPI_INT8_T 0
 #define MPI_UINT8_T 0
 #define MPI_UINT16_T 0
+#define MPI_C_FLOAT_COMPLEX 0
 #define MPI_C_LONG_DOUBLE_COMPLEX 0
 #define MPI_FLOAT 0
 #define MPI_DOUBLE 0

Added: clang-tools-extra/trunk/test/clang-tidy/mpi-buffer-deref.cpp
URL: 
http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/mpi-buffer-deref.cpp?rev=278553&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/mpi-buffer-deref.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/mpi-buffer-deref.cpp Fri Aug 12 
14:30:31 2016
@@ -0,0 +1,50 @@
+// RUN: %check_clang_tidy %s mpi-buffer-deref %t -- -- -I 
%S/Inputs/mpi-type-mismatch
+
+#include "mpimock.h"
+
+void negativeTests() {
+  char *buf;
+  MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently 
dereferenced: pointer->pointer [mpi-buffer-deref]
+
+  unsigned **buf2;
+  MPI_Send(buf2, 1, MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently 
dereferenced: pointer->pointer
+
+  short buf3[1][1];
+  MPI_Send(buf3, 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently 
dereferenced: array->array
+
+  long double _Complex *buf4[1];
+  MPI_Send(buf4, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently 
dereferenced: pointer->array
+
+  std::complex<float> *buf5[1][1];
+  MPI_Send(&buf5, 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: buffer is insufficiently 
dereferenced: pointer->array->array->pointer
+}
+
+void positiveTests() {
+  char buf;
+  MPI_Send(&buf, 1, MPI_CHAR, 0, 0, MPI_COMM_WORLD);
+
+  unsigned *buf2;
+  MPI_Send(buf2, 1, MPI_UNSIGNED, 0, 0, MPI_COMM_WORLD);
+
+  short buf3[1][1];
+  MPI_Send(buf3[0], 1, MPI_SHORT, 0, 0, MPI_COMM_WORLD);
+
+  long double _Complex *buf4[1];
+  MPI_Send(*buf4, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+  long double _Complex buf5[1];
+  MPI_Send(buf5, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+  std::complex<float> *buf6[1][1];
+  MPI_Send(*buf6[0], 1, MPI_CXX_FLOAT_COMPLEX, 0, 0, MPI_COMM_WORLD);
+
+  // Referencing an array with '&' is valid, as this also points to the
+  // beginning of the array.
+  long double _Complex buf7[1];
+  MPI_Send(&buf7, 1, MPI_C_LONG_DOUBLE_COMPLEX, 0, 0, MPI_COMM_WORLD);
+}


_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to