Alexander_Droste updated this revision to Diff 45126.
Alexander_Droste added a comment.
- removed AST related functionality from patch, as AST-based checks will be
integrated into clang tidy
- fix `checkMissingWaits()`
- moved `getVariableName()` from patch (currently under review here:
http://reviews.llvm.org/D16044)
- moved `is_contained()` from patch (currently under review here:
http://reviews.llvm.org/D16053)
http://reviews.llvm.org/D12761
Files:
tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.h
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.h
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.h
tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
tools/clang/test/Analysis/MPIChecker.cpp
tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
Index: tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
===================================================================
--- tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
+++ tools/clang/unittests/StaticAnalyzer/CMakeLists.txt
@@ -9,5 +9,5 @@
target_link_libraries(StaticAnalysisTests
clangBasic
clangAnalysis
- clangStaticAnalyzerCore
+ clangStaticAnalyzerCore
)
Index: tools/clang/test/Analysis/MPIChecker.cpp
===================================================================
--- tools/clang/test/Analysis/MPIChecker.cpp
+++ tools/clang/test/Analysis/MPIChecker.cpp
@@ -0,0 +1,267 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=mpi.MPI-Checker -verify %s
+
+// MPI-Checker makes no assumptions about details of an MPI implementation.
+// Typedefs and constants are compared as strings.
+
+#define NULL 0
+
+// mock types
+typedef int MPI_Datatype;
+typedef int MPI_Comm;
+typedef int MPI_Request;
+typedef int MPI_Status;
+typedef int MPI_Op;
+typedef int int8_t;
+typedef int uint8_t;
+typedef int uint16_t;
+typedef int int64_t;
+namespace std { template<class T> struct complex { T real; T imag; }; }
+
+// mock constants
+#define MPI_DATATYPE_NULL 0
+#define MPI_CHAR 0
+#define MPI_BYTE 0
+#define MPI_INT 0
+#define MPI_LONG 0
+#define MPI_LONG_DOUBLE 0
+#define MPI_UNSIGNED 0
+#define MPI_INT8_T 0
+#define MPI_UINT8_T 0
+#define MPI_UINT16_T 0
+#define MPI_C_LONG_DOUBLE_COMPLEX 0
+#define MPI_FLOAT 0
+#define MPI_DOUBLE 0
+#define MPI_CXX_BOOL 0
+#define MPI_CXX_FLOAT_COMPLEX 0
+#define MPI_CXX_DOUBLE_COMPLEX 0
+#define MPI_CXX_LONG_DOUBLE_COMPLEX 0
+#define MPI_IN_PLACE 0
+#define MPI_COMM_WORLD 0
+#define MPI_STATUS_IGNORE 0
+#define MPI_STATUSES_IGNORE 0
+#define MPI_SUM 0
+
+int MPI_Comm_size(MPI_Comm, int *);
+int MPI_Comm_rank(MPI_Comm, int *);
+int MPI_Send(const void *, int, MPI_Datatype, int, int, MPI_Comm);
+int MPI_Recv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Status *);
+int MPI_Isend(const void *, int, MPI_Datatype, int, int, MPI_Comm,
+ MPI_Request *);
+int MPI_Irecv(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *);
+int MPI_Wait(MPI_Request *, MPI_Status *);
+int MPI_Waitall(int, MPI_Request[], MPI_Status[]);
+int MPI_Reduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm);
+int MPI_Ireduce(const void *, void *, int, MPI_Datatype, MPI_Op, int, MPI_Comm,
+ MPI_Request *);
+int MPI_Bcast(void *, int count, MPI_Datatype, int, MPI_Comm);
+
+//integration tests-------------------------------------------------------
+
+void matchedWait1() {
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ if (rank >= 0) {
+ MPI_Request sendReq1, recvReq1;
+ MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 3, MPI_COMM_WORLD, &sendReq1);
+ MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 3, MPI_COMM_WORLD, &recvReq1);
+
+ MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+ MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+ }
+} // no error
+
+void matchedWait2() {
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ if (rank >= 0) {
+ MPI_Request sendReq1, recvReq1;
+ MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 4, MPI_COMM_WORLD, &sendReq1);
+ MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 4, MPI_COMM_WORLD, &recvReq1);
+ MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+ MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+ }
+} // no error
+
+void matchedWait3() {
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ if (rank >= 0) {
+ MPI_Request sendReq1, recvReq1;
+ MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 5, MPI_COMM_WORLD, &sendReq1);
+ MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 5, MPI_COMM_WORLD, &recvReq1);
+
+ if (rank > 1000) {
+ MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+ MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+ } else {
+ MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+ MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+ }
+ }
+} // no error
+
+void missingWait1() { // Check missing wait for dead region.
+ int rank = 0;
+ double buf = 0;
+ MPI_Request sendReq1;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &sendReq1); // Request is previously used by nonblocking call here.
+} // expected-warning{{Request 'sendReq1' has no matching wait.}}
+
+
+MPI_Request sendReq1;
+void missingWait2() { // Check missing wait for global variable.
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &sendReq1); // Request is previously used by nonblocking call here.
+} // expected-warning{{Request 'sendReq1' has no matching wait.}}
+
+void missingWait3() {
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ if (rank == 0) {
+ } else {
+ MPI_Request sendReq1, recvReq1;
+
+ MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 2, MPI_COMM_WORLD, &sendReq1); // Request is previously used by nonblocking call here.
+ MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 2, MPI_COMM_WORLD, &recvReq1); // expected-warning{{Request 'sendReq1' has no matching wait.}}
+ MPI_Wait(&recvReq1, MPI_STATUS_IGNORE);
+ }
+}
+
+void doubleNonblocking() {
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ if (rank == 1) {
+ } else {
+ MPI_Request sendReq1;
+
+ MPI_Isend(&buf, 1, MPI_DOUBLE, rank + 1, 6, MPI_COMM_WORLD, &sendReq1); // Request is previously used by nonblocking call here.
+ MPI_Irecv(&buf, 1, MPI_DOUBLE, rank - 1, 6, MPI_COMM_WORLD, &sendReq1); // expected-warning{{Double nonblocking on request 'sendReq1'.}}
+ MPI_Wait(&sendReq1, MPI_STATUS_IGNORE);
+ }
+}
+
+void doubleNonblocking2() {
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ MPI_Request req;
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &req); // Request is previously used by nonblocking call here.
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &req); // expected-warning{{Double nonblocking on request 'req'.}}
+ MPI_Wait(&req, MPI_STATUS_IGNORE);
+}
+
+void doubleNonblocking3() {
+ typedef struct { MPI_Request req; } ReqStruct;
+
+ ReqStruct rs;
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &rs.req); // Request is previously used by nonblocking call here.
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &rs.req); // expected-warning{{Double nonblocking on request 'rs.req'.}}
+ MPI_Wait(&rs.req, MPI_STATUS_IGNORE);
+}
+
+void doubleNonblocking4() {
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ MPI_Request req;
+ for (int i = 0; i < 2; ++i) {
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD, &req); // expected-warning{{Double nonblocking on request 'req'.}}
+ }
+ MPI_Wait(&req, MPI_STATUS_IGNORE);
+}
+
+void missingNonBlocking() {
+ int rank = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+ MPI_Request sendReq1[10][10][10];
+ MPI_Wait(&sendReq1[1][7][9], MPI_STATUS_IGNORE); // expected-warning{{Request 'sendReq1[1][7][9]' has no matching nonblocking call.}}
+}
+
+void noDoubleRequestUsage() {
+ typedef struct {
+ MPI_Request req;
+ MPI_Request req2;
+ } ReqStruct;
+
+ ReqStruct rs;
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &rs.req);
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &rs.req2);
+ MPI_Wait(&rs.req, MPI_STATUS_IGNORE);
+ MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
+}
+
+void noDoubleRequestUsage2() {
+ typedef struct {
+ MPI_Request req[2];
+ MPI_Request req2;
+ } ReqStruct;
+
+ ReqStruct rs;
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &rs.req[0]);
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &rs.req[1]);
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &rs.req2);
+ MPI_Wait(&rs.req[0], MPI_STATUS_IGNORE);
+ MPI_Wait(&rs.req[1], MPI_STATUS_IGNORE);
+ MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
+}
+
+void nestedRequest() {
+ typedef struct {
+ MPI_Request req[2];
+ MPI_Request req2;
+ } ReqStruct;
+
+ ReqStruct rs;
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &rs.req[0]);
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &rs.req[1]);
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &rs.req2);
+ MPI_Waitall(2, rs.req, MPI_STATUSES_IGNORE);
+ MPI_Wait(&rs.req2, MPI_STATUS_IGNORE);
+}
+
+void singleRequestInWaitall() {
+ MPI_Request r;
+ int rank = 0;
+ double buf = 0;
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ MPI_Ireduce(MPI_IN_PLACE, &buf, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD,
+ &r);
+ MPI_Waitall(1, &r, MPI_STATUSES_IGNORE);
+}
Index: tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ tools/clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -635,6 +635,47 @@
superRegion->printPrettyAsExpr(os);
}
+std::string MemRegion::getVariableName() const {
+ std::string VariableName{""};
+ std::string ArrayIndices{""};
+
+ const clang::ento::MemRegion *R = this;
+ llvm::SmallString<50> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ // Obtain array indices to add them to the variable name.
+ const clang::ento::ElementRegion *ER = nullptr;
+ while ((ER = R->getAs<clang::ento::ElementRegion>())) {
+
+ std::string idx{""};
+ if (auto CI = ER->getIndex().getAs<clang::ento::nonloc::ConcreteInt>()) {
+ llvm::SmallString<2> intValAsString;
+ CI->getValue().toString(intValAsString);
+ idx = {intValAsString.begin(), intValAsString.end()};
+ }
+
+ ArrayIndices += "[" + idx + "]";
+ R = ER->getSuperRegion();
+ }
+
+ std::reverse(ArrayIndices.begin(), ArrayIndices.end());
+
+ // Get variable name.
+ if (R && R->canPrintPretty()) {
+ R->printPretty(os);
+ VariableName += os.str();
+ }
+
+ // Combine variable name with indices.
+ if (VariableName.size() && VariableName.back() == '\'') {
+ VariableName.insert(VariableName.size() - 1, ArrayIndices);
+ } else {
+ VariableName += ArrayIndices;
+ }
+
+ return VariableName;
+}
+
//===----------------------------------------------------------------------===//
// MemRegionManager methods.
//===----------------------------------------------------------------------===//
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.h
@@ -0,0 +1,48 @@
+//===-- Utility.h - utility functions ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines utility helper functions for MPI-Checker.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_UTILITY_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_UTILITY_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+namespace util {
+
+/// Retrieve source range from memory region. The range retrieval
+/// is based on the decl obtained from the memory region.
+/// For a VarRegion the range of the base region is returned.
+/// For a FieldRegion the range of the field is returned.
+/// If no declaration is found, an empty source range is returned.
+/// The client is responsible for checking if the returned range is valid.
+///
+/// \param MR memory region to retrieve the source range for
+///
+/// \returns source range for declaration retrieved from memory region
+clang::SourceRange sourceRange(const clang::ento::MemRegion *MR);
+
+/// Returns the source range \p Range as a StringRef.
+clang::StringRef sourceRangeAsStringRef(const clang::SourceRange &Range,
+ clang::ento::AnalysisManager &AM);
+
+/// Retrieve identifier info for a call expression.
+/// Returns nullptr if there's no direct callee.
+///
+/// \param CE call expression to retrieve ident info for
+///
+/// \returns identifier info for passed call expression
+const clang::IdentifierInfo *getIdentInfo(const clang::CallExpr *CE);
+
+} // end of namespace: util
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/Utility.cpp
@@ -0,0 +1,55 @@
+//===-- Utility.cpp - utility functions -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines utility helper functions for MPI-Checker.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/Lex/Lexer.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "Utility.h"
+#include <sstream>
+#include <vector>
+
+namespace util {
+
+clang::SourceRange sourceRange(const clang::ento::MemRegion *MR) {
+ const clang::ento::VarRegion *VR =
+ clang::dyn_cast<clang::ento::VarRegion>(MR->getBaseRegion());
+
+ const clang::ento::FieldRegion *FR =
+ clang::dyn_cast<clang::ento::FieldRegion>(MR);
+
+ if (FR) {
+ return FR->getDecl()->getSourceRange();
+ } else if (VR) {
+ return VR->getDecl()->getSourceRange();
+ } else {
+ // non valid source range (can be checked by client)
+ return clang::SourceRange{};
+ }
+}
+
+clang::StringRef sourceRangeAsStringRef(const clang::SourceRange &Range,
+ clang::ento::AnalysisManager &AM) {
+ auto CharRange = clang::CharSourceRange::getTokenRange(Range);
+ return clang::Lexer::getSourceText(CharRange, AM.getSourceManager(),
+ clang::LangOptions());
+}
+
+const clang::IdentifierInfo *getIdentInfo(const clang::CallExpr *CE) {
+ if (CE->getDirectCallee()) {
+ return CE->getDirectCallee()->getIdentifier();
+ } else {
+ return nullptr;
+ }
+}
+
+} // end of namespace: util
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPITypes.h
@@ -0,0 +1,80 @@
+//===-- MPITypes.h - Functionality to model MPI concepts --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides definitions, to model the schema of MPI point-to-point
+/// functions and MPI requests. The mpi::Request class defines a wrapper
+/// class, in order to make MPI requests trackable for path-sensitive analysis.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPITYPES_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPITYPES_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "llvm/ADT/SmallSet.h"
+#include "MPIFunctionClassifier.h"
+#include "Utility.h"
+
+// for path-sensitive analysis–––––––––––––––––––––––––––––––––––––––––––––––
+namespace clang {
+namespace ento {
+namespace mpi {
+
+class Request {
+public:
+ enum State : unsigned char { Null, Undefined, Nonblocking, Wait };
+
+ Request(State UT) : CurrentState{UT} {}
+
+ void Profile(llvm::FoldingSetNodeID &Id) const {
+ Id.AddInteger(CurrentState);
+ }
+
+ bool operator==(const Request &ToCompare) const {
+ return CurrentState == ToCompare.CurrentState;
+ }
+
+ const State CurrentState;
+};
+
+} // end of namespace: mpi
+} // end of namespace: ento
+} // end of namespace: clang
+
+// Data structure for path-sensitive analysis. The map stores MPI
+// requests which are identified by their memory region. Requests are used in
+// MPI to complete nonblocking operations with wait operations. Requests can be
+// used as part of an array.
+struct RequestMap {};
+typedef llvm::ImmutableMap<const clang::ento::MemRegion *,
+ clang::ento::mpi::Request> RequestMapImpl;
+template <>
+struct clang::ento::ProgramStateTrait<RequestMap>
+ : public clang::ento::ProgramStatePartialTrait<RequestMapImpl> {
+ static void *GDMIndex() {
+ static int index = 0;
+ return &index;
+ }
+};
+
+// argument schema enums ––––––––––––––––––––––––––––––––––––––––––––––––––––
+namespace clang {
+namespace mpi {
+// Scope enums but keep weak typing, to make values usable as indices.
+
+// Represents argument schema for MPI point-to-point functions.
+// The existence and type of last argument must be checked dynamically.
+namespace MPIPointToPoint {
+enum { Buf, Count, Datatype, Rank, Tag, Comm, Request };
+}
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.h
@@ -0,0 +1,110 @@
+//===-- MPIFunctionClassifier.h - classifies MPI functions ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines functionality to identify and classify MPI functions.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIFUNCTIONCLASSIFIER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIFUNCTIONCLASSIFIER_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+namespace clang {
+namespace mpi {
+
+class MPIFunctionClassifier {
+public:
+ MPIFunctionClassifier(clang::ento::AnalysisManager &AM) {
+ identifierInit(AM);
+ }
+
+ // general identifiers–––––––––––––––––––––––––––––––––––––––––––––––––
+ bool isMPIType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isBlockingType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isNonBlockingType(const clang::IdentifierInfo *const IdentInfo) const;
+
+ // point-to-point identifiers––––––––––––––––––––––––––––––––––––––––––
+ bool isPointToPointType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isSendType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isRecvType(const clang::IdentifierInfo *const IdentInfo) const;
+
+ // collective identifiers––––––––––––––––––––––––––––––––––––––––––––––
+ bool isCollectiveType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isCollToColl(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isScatterType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isGatherType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isAllgatherType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isAlltoallType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isReduceType(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isBcastType(const clang::IdentifierInfo *const IdentInfo) const;
+
+ // additional identifiers ––––––––––––––––––––––––––––––––––––––––––––––
+ bool isMPI_Comm_rank(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isMPI_Comm_size(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isMPI_Wait(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isMPI_Waitall(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isMPI_Waitany(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isMPI_Waitsome(const clang::IdentifierInfo *const IdentInfo) const;
+ bool isWaitType(const clang::IdentifierInfo *const IdentInfo) const;
+
+private:
+ // Initializes function identifiers, to recognize them during analysis.
+ void identifierInit(clang::ento::AnalysisManager &AM);
+ void initPointToPointIdentifiers(clang::ento::AnalysisManager &AM);
+ void initCollectiveIdentifiers(clang::ento::AnalysisManager &AM);
+ void initAdditionalIdentifiers(clang::ento::AnalysisManager &AM);
+
+ // The containers are used, to enable classification of MPI-functions during
+ // analysis.
+ llvm::SmallVector<clang::IdentifierInfo *, 8> MPISendTypes;
+ llvm::SmallVector<clang::IdentifierInfo *, 2> MPIRecvTypes;
+
+ llvm::SmallVector<clang::IdentifierInfo *, 12> MPIBlockingTypes;
+ llvm::SmallVector<clang::IdentifierInfo *, 12> MPINonBlockingTypes;
+
+ llvm::SmallVector<clang::IdentifierInfo *, 10> MPIPointToPointTypes;
+ llvm::SmallVector<clang::IdentifierInfo *, 16> MPICollectiveTypes;
+
+ llvm::SmallVector<clang::IdentifierInfo *, 4> MPIPointToCollTypes;
+ llvm::SmallVector<clang::IdentifierInfo *, 4> MPICollToPointTypes;
+ llvm::SmallVector<clang::IdentifierInfo *, 6> MPICollToCollTypes;
+
+ llvm::SmallVector<clang::IdentifierInfo *, 32> MPIType;
+
+ // point-to-point functions
+ clang::IdentifierInfo *IdentInfo_MPI_Send{nullptr},
+ *IdentInfo_MPI_Isend{nullptr}, *IdentInfo_MPI_Ssend{nullptr},
+ *IdentInfo_MPI_Issend{nullptr}, *IdentInfo_MPI_Bsend{nullptr},
+ *IdentInfo_MPI_Ibsend{nullptr}, *IdentInfo_MPI_Rsend{nullptr},
+ *IdentInfo_MPI_Irsend{nullptr}, *IdentInfo_MPI_Recv{nullptr},
+ *IdentInfo_MPI_Irecv{nullptr};
+
+ // collective functions
+ clang::IdentifierInfo *IdentInfo_MPI_Scatter{nullptr},
+ *IdentInfo_MPI_Iscatter{nullptr}, *IdentInfo_MPI_Gather{nullptr},
+ *IdentInfo_MPI_Igather{nullptr}, *IdentInfo_MPI_Allgather{nullptr},
+ *IdentInfo_MPI_Iallgather{nullptr}, *IdentInfo_MPI_Bcast{nullptr},
+ *IdentInfo_MPI_Ibcast{nullptr}, *IdentInfo_MPI_Reduce{nullptr},
+ *IdentInfo_MPI_Ireduce{nullptr}, *IdentInfo_MPI_Allreduce{nullptr},
+ *IdentInfo_MPI_Iallreduce{nullptr}, *IdentInfo_MPI_Alltoall{nullptr},
+ *IdentInfo_MPI_Ialltoall{nullptr}, *IdentInfo_MPI_Barrier{nullptr};
+
+ // additional functions
+ clang::IdentifierInfo *IdentInfo_MPI_Comm_rank{nullptr},
+ *IdentInfo_MPI_Comm_size{nullptr}, *IdentInfo_MPI_Wait{nullptr},
+ *IdentInfo_MPI_Waitall{nullptr}, *IdentInfo_MPI_Waitany{nullptr},
+ *IdentInfo_MPI_Waitsome{nullptr};
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIFunctionClassifier.cpp
@@ -0,0 +1,358 @@
+//===-- MPIFunctionClassifier.cpp - classifies MPI functions ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines functionality to identify and classify MPI functions.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "MPIFunctionClassifier.h"
+
+namespace clang {
+namespace mpi {
+
+void MPIFunctionClassifier::identifierInit(clang::ento::AnalysisManager &AM) {
+ // Initialize function identifiers.
+ initPointToPointIdentifiers(AM);
+ initCollectiveIdentifiers(AM);
+ initAdditionalIdentifiers(AM);
+}
+
+void MPIFunctionClassifier::initPointToPointIdentifiers(
+ clang::ento::AnalysisManager &AM) {
+ ASTContext &ASTCtx = AM.getASTContext();
+
+ // Copy identifiers into the correct classification containers.
+ IdentInfo_MPI_Send = &ASTCtx.Idents.get("MPI_Send");
+ MPISendTypes.push_back(IdentInfo_MPI_Send);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Send);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Send);
+ MPIType.push_back(IdentInfo_MPI_Send);
+ assert(IdentInfo_MPI_Send);
+
+ IdentInfo_MPI_Isend = &ASTCtx.Idents.get("MPI_Isend");
+ MPISendTypes.push_back(IdentInfo_MPI_Isend);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Isend);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Isend);
+ MPIType.push_back(IdentInfo_MPI_Isend);
+ assert(IdentInfo_MPI_Isend);
+
+ IdentInfo_MPI_Ssend = &ASTCtx.Idents.get("MPI_Ssend");
+ MPISendTypes.push_back(IdentInfo_MPI_Ssend);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Ssend);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Ssend);
+ MPIType.push_back(IdentInfo_MPI_Ssend);
+ assert(IdentInfo_MPI_Ssend);
+
+ IdentInfo_MPI_Issend = &ASTCtx.Idents.get("MPI_Issend");
+ MPISendTypes.push_back(IdentInfo_MPI_Issend);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Issend);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Issend);
+ MPIType.push_back(IdentInfo_MPI_Issend);
+ assert(IdentInfo_MPI_Issend);
+
+ IdentInfo_MPI_Bsend = &ASTCtx.Idents.get("MPI_Bsend");
+ MPISendTypes.push_back(IdentInfo_MPI_Bsend);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Bsend);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Bsend);
+ MPIType.push_back(IdentInfo_MPI_Bsend);
+ assert(IdentInfo_MPI_Bsend);
+
+ IdentInfo_MPI_Ibsend = &ASTCtx.Idents.get("MPI_Ibsend");
+ MPISendTypes.push_back(IdentInfo_MPI_Ibsend);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Ibsend);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Ibsend);
+ MPIType.push_back(IdentInfo_MPI_Ibsend);
+ assert(IdentInfo_MPI_Ibsend);
+
+ IdentInfo_MPI_Rsend = &ASTCtx.Idents.get("MPI_Rsend");
+ MPISendTypes.push_back(IdentInfo_MPI_Rsend);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Rsend);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Rsend);
+ MPIType.push_back(IdentInfo_MPI_Rsend);
+ assert(IdentInfo_MPI_Rsend);
+
+ IdentInfo_MPI_Irsend = &ASTCtx.Idents.get("MPI_Irsend");
+ MPISendTypes.push_back(IdentInfo_MPI_Irsend);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Irsend);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Irsend);
+ MPIType.push_back(IdentInfo_MPI_Irsend);
+ assert(IdentInfo_MPI_Irsend);
+
+ IdentInfo_MPI_Recv = &ASTCtx.Idents.get("MPI_Recv");
+ MPIRecvTypes.push_back(IdentInfo_MPI_Recv);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Recv);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Recv);
+ MPIType.push_back(IdentInfo_MPI_Recv);
+ assert(IdentInfo_MPI_Recv);
+
+ IdentInfo_MPI_Irecv = &ASTCtx.Idents.get("MPI_Irecv");
+ MPIRecvTypes.push_back(IdentInfo_MPI_Irecv);
+ MPIPointToPointTypes.push_back(IdentInfo_MPI_Irecv);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Irecv);
+ MPIType.push_back(IdentInfo_MPI_Irecv);
+ assert(IdentInfo_MPI_Irecv);
+}
+
+void MPIFunctionClassifier::initCollectiveIdentifiers(
+ clang::ento::AnalysisManager &AM) {
+ ASTContext &ASTCtx = AM.getASTContext();
+
+ // Copy identifiers into the correct classification containers.
+ IdentInfo_MPI_Scatter = &ASTCtx.Idents.get("MPI_Scatter");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Scatter);
+ MPIPointToCollTypes.push_back(IdentInfo_MPI_Scatter);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Scatter);
+ MPIType.push_back(IdentInfo_MPI_Scatter);
+ assert(IdentInfo_MPI_Scatter);
+
+ IdentInfo_MPI_Iscatter = &ASTCtx.Idents.get("MPI_Iscatter");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Iscatter);
+ MPIPointToCollTypes.push_back(IdentInfo_MPI_Iscatter);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Iscatter);
+ MPIType.push_back(IdentInfo_MPI_Iscatter);
+ assert(IdentInfo_MPI_Iscatter);
+
+ IdentInfo_MPI_Gather = &ASTCtx.Idents.get("MPI_Gather");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Gather);
+ MPICollToPointTypes.push_back(IdentInfo_MPI_Gather);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Gather);
+ MPIType.push_back(IdentInfo_MPI_Gather);
+ assert(IdentInfo_MPI_Gather);
+
+ IdentInfo_MPI_Igather = &ASTCtx.Idents.get("MPI_Igather");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Igather);
+ MPICollToPointTypes.push_back(IdentInfo_MPI_Igather);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Igather);
+ MPIType.push_back(IdentInfo_MPI_Igather);
+ assert(IdentInfo_MPI_Igather);
+
+ IdentInfo_MPI_Allgather = &ASTCtx.Idents.get("MPI_Allgather");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Allgather);
+ MPICollToCollTypes.push_back(IdentInfo_MPI_Allgather);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Allgather);
+ MPIType.push_back(IdentInfo_MPI_Allgather);
+ assert(IdentInfo_MPI_Allgather);
+
+ IdentInfo_MPI_Iallgather = &ASTCtx.Idents.get("MPI_Iallgather");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Iallgather);
+ MPICollToCollTypes.push_back(IdentInfo_MPI_Iallgather);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Iallgather);
+ MPIType.push_back(IdentInfo_MPI_Iallgather);
+ assert(IdentInfo_MPI_Iallgather);
+
+ IdentInfo_MPI_Bcast = &ASTCtx.Idents.get("MPI_Bcast");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Bcast);
+ MPIPointToCollTypes.push_back(IdentInfo_MPI_Bcast);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Bcast);
+ MPIType.push_back(IdentInfo_MPI_Bcast);
+ assert(IdentInfo_MPI_Bcast);
+
+ IdentInfo_MPI_Ibcast = &ASTCtx.Idents.get("MPI_Ibcast");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Ibcast);
+ MPIPointToCollTypes.push_back(IdentInfo_MPI_Ibcast);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Ibcast);
+ MPIType.push_back(IdentInfo_MPI_Ibcast);
+ assert(IdentInfo_MPI_Ibcast);
+
+ IdentInfo_MPI_Reduce = &ASTCtx.Idents.get("MPI_Reduce");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Reduce);
+ MPICollToPointTypes.push_back(IdentInfo_MPI_Reduce);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Reduce);
+ MPIType.push_back(IdentInfo_MPI_Reduce);
+ assert(IdentInfo_MPI_Reduce);
+
+ IdentInfo_MPI_Ireduce = &ASTCtx.Idents.get("MPI_Ireduce");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Ireduce);
+ MPICollToPointTypes.push_back(IdentInfo_MPI_Ireduce);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Ireduce);
+ MPIType.push_back(IdentInfo_MPI_Ireduce);
+ assert(IdentInfo_MPI_Ireduce);
+
+ IdentInfo_MPI_Allreduce = &ASTCtx.Idents.get("MPI_Allreduce");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Allreduce);
+ MPICollToCollTypes.push_back(IdentInfo_MPI_Allreduce);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Allreduce);
+ MPIType.push_back(IdentInfo_MPI_Allreduce);
+ assert(IdentInfo_MPI_Allreduce);
+
+ IdentInfo_MPI_Iallreduce = &ASTCtx.Idents.get("MPI_Iallreduce");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Iallreduce);
+ MPICollToCollTypes.push_back(IdentInfo_MPI_Iallreduce);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Iallreduce);
+ MPIType.push_back(IdentInfo_MPI_Iallreduce);
+ assert(IdentInfo_MPI_Iallreduce);
+
+ IdentInfo_MPI_Alltoall = &ASTCtx.Idents.get("MPI_Alltoall");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Alltoall);
+ MPICollToCollTypes.push_back(IdentInfo_MPI_Alltoall);
+ MPIBlockingTypes.push_back(IdentInfo_MPI_Alltoall);
+ MPIType.push_back(IdentInfo_MPI_Alltoall);
+ assert(IdentInfo_MPI_Alltoall);
+
+ IdentInfo_MPI_Ialltoall = &ASTCtx.Idents.get("MPI_Ialltoall");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Ialltoall);
+ MPICollToCollTypes.push_back(IdentInfo_MPI_Ialltoall);
+ MPINonBlockingTypes.push_back(IdentInfo_MPI_Ialltoall);
+ MPIType.push_back(IdentInfo_MPI_Ialltoall);
+ assert(IdentInfo_MPI_Ialltoall);
+}
+
+void MPIFunctionClassifier::initAdditionalIdentifiers(
+ clang::ento::AnalysisManager &AM) {
+ ASTContext &ASTCtx = AM.getASTContext();
+
+ IdentInfo_MPI_Comm_rank = &ASTCtx.Idents.get("MPI_Comm_rank");
+ MPIType.push_back(IdentInfo_MPI_Comm_rank);
+ assert(IdentInfo_MPI_Comm_rank);
+
+ IdentInfo_MPI_Comm_size = &ASTCtx.Idents.get("MPI_Comm_size");
+ MPIType.push_back(IdentInfo_MPI_Comm_size);
+ assert(IdentInfo_MPI_Comm_size);
+
+ IdentInfo_MPI_Wait = &ASTCtx.Idents.get("MPI_Wait");
+ MPIType.push_back(IdentInfo_MPI_Wait);
+ assert(IdentInfo_MPI_Wait);
+
+ IdentInfo_MPI_Waitall = &ASTCtx.Idents.get("MPI_Waitall");
+ MPIType.push_back(IdentInfo_MPI_Waitall);
+ assert(IdentInfo_MPI_Waitall);
+
+ IdentInfo_MPI_Waitany = &ASTCtx.Idents.get("MPI_Waitany");
+ MPIType.push_back(IdentInfo_MPI_Waitany);
+ assert(IdentInfo_MPI_Waitany);
+
+ IdentInfo_MPI_Waitsome = &ASTCtx.Idents.get("MPI_Waitsome");
+ MPIType.push_back(IdentInfo_MPI_Waitsome);
+ assert(IdentInfo_MPI_Waitsome);
+
+ IdentInfo_MPI_Barrier = &ASTCtx.Idents.get("MPI_Barrier");
+ MPICollectiveTypes.push_back(IdentInfo_MPI_Barrier);
+ MPIType.push_back(IdentInfo_MPI_Barrier);
+ assert(IdentInfo_MPI_Barrier);
+}
+
+// general identifiers–––––––––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isMPIType(const IdentifierInfo *IdentInfo) const {
+ return llvm::is_contained(MPIType, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isBlockingType(
+ const IdentifierInfo *IdentInfo) const {
+ return llvm::is_contained(MPIBlockingTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isNonBlockingType(
+ const IdentifierInfo *IdentInfo) const {
+ return llvm::is_contained(MPINonBlockingTypes, IdentInfo);
+}
+
+// point-to-point identifiers––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isPointToPointType(
+ const IdentifierInfo *IdentInfo) const {
+ return llvm::is_contained(MPIPointToPointTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isSendType(const IdentifierInfo *IdentInfo) const {
+ return llvm::is_contained(MPISendTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isRecvType(const IdentifierInfo *IdentInfo) const {
+ return llvm::is_contained(MPIRecvTypes, IdentInfo);
+}
+
+// collective identifiers––––––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isCollectiveType(
+ const IdentifierInfo *IdentInfo) const {
+ return llvm::is_contained(MPICollectiveTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isCollToColl(
+ const IdentifierInfo *IdentInfo) const {
+ return llvm::is_contained(MPICollToCollTypes, IdentInfo);
+}
+
+bool MPIFunctionClassifier::isScatterType(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Scatter ||
+ IdentInfo == IdentInfo_MPI_Iscatter;
+}
+
+bool MPIFunctionClassifier::isGatherType(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Gather ||
+ IdentInfo == IdentInfo_MPI_Igather ||
+ IdentInfo == IdentInfo_MPI_Allgather ||
+ IdentInfo == IdentInfo_MPI_Iallgather;
+}
+
+bool MPIFunctionClassifier::isAllgatherType(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Allgather ||
+ IdentInfo == IdentInfo_MPI_Iallgather;
+}
+
+bool MPIFunctionClassifier::isAlltoallType(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Alltoall ||
+ IdentInfo == IdentInfo_MPI_Ialltoall;
+}
+
+bool MPIFunctionClassifier::isBcastType(const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Bcast || IdentInfo == IdentInfo_MPI_Ibcast;
+}
+
+bool MPIFunctionClassifier::isReduceType(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Reduce ||
+ IdentInfo == IdentInfo_MPI_Ireduce ||
+ IdentInfo == IdentInfo_MPI_Allreduce ||
+ IdentInfo == IdentInfo_MPI_Iallreduce;
+}
+
+// additional identifiers ––––––––––––––––––––––––––––––––––––––––––––––
+bool MPIFunctionClassifier::isMPI_Comm_rank(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Comm_rank;
+}
+
+bool MPIFunctionClassifier::isMPI_Comm_size(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Comm_size;
+}
+
+bool MPIFunctionClassifier::isMPI_Wait(const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Wait;
+}
+
+bool MPIFunctionClassifier::isMPI_Waitall(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Waitall;
+}
+
+bool MPIFunctionClassifier::isMPI_Waitany(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Waitany;
+}
+
+bool MPIFunctionClassifier::isMPI_Waitsome(
+ const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Waitsome;
+}
+
+bool MPIFunctionClassifier::isWaitType(const IdentifierInfo *IdentInfo) const {
+ return IdentInfo == IdentInfo_MPI_Wait ||
+ IdentInfo == IdentInfo_MPI_Waitall ||
+ IdentInfo == IdentInfo_MPI_Waitany ||
+ IdentInfo == IdentInfo_MPI_Waitsome;
+}
+
+} // end of namespace: mpi
+} // end of namespace: clang
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.h
@@ -0,0 +1,93 @@
+//===-- MPICheckerPathSensitive.h - path-sensitive checks -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines path-sensitive checks, to verify correct usage of the
+/// MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKERPATHSENSITIVE_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPICHECKERPATHSENSITIVE_H
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "MPIFunctionClassifier.h"
+#include "MPITypes.h"
+#include "MPIBugReporter.h"
+
+namespace clang {
+namespace mpi {
+
+class MPICheckerPathSensitive {
+public:
+ MPICheckerPathSensitive(clang::ento::AnalysisManager &AM,
+ const clang::ento::CheckerBase *CB,
+ clang::ento::BugReporter &BR)
+ : FuncClassifier{AM}, BugReporter{BR, *CB, AM} {}
+
+ /// Checks if a request is used by nonblocking calls multiple times
+ /// in sequence without intermediate wait. The check contains a guard,
+ /// in order to only inspect nonblocking functions.
+ ///
+ /// \param PreCallEvent MPI call to verify
+ void checkDoubleNonblocking(const clang::ento::CallEvent &PreCallEvent,
+ clang::ento::CheckerContext &Ctx) const;
+
+ /// Checks if a request is used by a wait multiple times in sequence without
+ /// intermediate nonblocking call or if the request used by the wait
+ /// function was not used at all before. The check contains a guard,
+ /// in order to only inspect wait functions.
+ ///
+ /// \param PreCallEvent MPI call to verify
+ void checkWaitUsage(const clang::ento::CallEvent &PreCallEvent,
+ clang::ento::CheckerContext &Ctx) const;
+
+ /// Check if a nonblocking call is not matched by a wait.
+ /// If a memory region is not alive and the last function using the
+ /// request was a nonblocking call, this is rated as a missing wait.
+ void checkMissingWaits(clang::ento::SymbolReaper &SymReaper,
+ clang::ento::CheckerContext &Ctx);
+
+ /// Check if a nonblocking call is not matched by a wait. This function
+ /// invokes the verification based on global request variables. Therefore,
+ /// all end nodes of a graph built for a translation unit are inspected.
+ /// \param G Graph constructed during path-sensitive analysis for the
+ /// analysed translation unit.
+ void checkMissingWaitsGlobals(clang::ento::ExplodedGraph &G);
+
+private:
+ /// Collects all memory regions of a request(array) used by a wait
+ /// function. If the wait function uses a single request, this is a single
+ /// region. For wait functions using multiple requests, multiple regions
+ /// representing elements in the array are collected.
+ ///
+ /// \param ReqRegions vector the regions get pushed into
+ /// \param MR top most region to iterate
+ /// \param CE MPI wait call using the request(s)
+ void allRegionsUsedByWait(
+ llvm::SmallVector<const clang::ento::MemRegion *, 2> &ReqRegions,
+ const clang::ento::MemRegion *const MR, const clang::ento::CallEvent &CE,
+ clang::ento::CheckerContext &Ctx) const;
+
+ /// Returns the memory region used by a wait function.
+ /// Distinguishes between MPI_Wait and MPI_Waitall.
+ ///
+ /// \param CE MPI wait call
+ const clang::ento::MemRegion *
+ topRegionUsedByWait(const clang::ento::CallEvent &CE) const;
+
+ const MPIFunctionClassifier FuncClassifier;
+ MPIBugReporter BugReporter;
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPICheckerPathSensitive.cpp
@@ -0,0 +1,189 @@
+//===-- MPICheckerPathSensitive.cpp - path-sensitive checks -----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines path-sensitive checks, to verify correct usage of the
+/// MPI API.
+///
+//===----------------------------------------------------------------------===//
+
+#include "MPICheckerPathSensitive.h"
+#include "Utility.h"
+
+namespace clang {
+namespace mpi {
+
+using namespace clang::ento;
+using namespace clang::ento::mpi;
+
+void MPICheckerPathSensitive::checkDoubleNonblocking(
+ const clang::ento::CallEvent &PreCallEvent, CheckerContext &Ctx) const {
+ if (!FuncClassifier.isNonBlockingType(PreCallEvent.getCalleeIdentifier())) {
+ return;
+ }
+ const MemRegion *const MR =
+ PreCallEvent.getArgSVal(PreCallEvent.getNumArgs() - 1).getAsRegion();
+ const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
+
+ // The region must be typed, in order to reason about it.
+ if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
+ return;
+
+ ProgramStateRef State = Ctx.getState();
+ const Request *const Req = State->get<RequestMap>(MR);
+ const ExplodedNode *const ExplNode = Ctx.getPredecessor();
+
+ if (Req && Req->CurrentState == Request::State::Nonblocking) {
+ BugReporter.reportDoubleNonblocking(PreCallEvent, *Req, MR, ExplNode);
+ }
+
+ State = State->set<RequestMap>(MR, Request::State::Nonblocking);
+ Ctx.addTransition(State);
+}
+
+void MPICheckerPathSensitive::checkWaitUsage(
+ const clang::ento::CallEvent &PreCallEvent, CheckerContext &Ctx) const {
+ if (!FuncClassifier.isWaitType(PreCallEvent.getCalleeIdentifier()))
+ return;
+ const MemRegion *const MR = topRegionUsedByWait(PreCallEvent);
+ const ElementRegion *const ER = dyn_cast<ElementRegion>(MR);
+ if (!MR)
+ return;
+
+ // The region must be typed, in order to reason about it.
+ if (!isa<TypedRegion>(MR) || (ER && !isa<TypedRegion>(ER->getSuperRegion())))
+ return;
+
+ ProgramStateRef State = Ctx.getState();
+ const ExplodedNode *const ExplNode = Ctx.getPredecessor();
+ llvm::SmallVector<const MemRegion *, 2> ReqRegions;
+ allRegionsUsedByWait(ReqRegions, MR, PreCallEvent, Ctx);
+
+ // Check all request regions used by the wait function.
+ for (const auto &ReqRegion : ReqRegions) {
+ const Request *const Req = State->get<RequestMap>(ReqRegion);
+ State = State->set<RequestMap>(ReqRegion, Request::State::Wait);
+ if (!Req) {
+ // A wait has no matching nonblocking call.
+ BugReporter.reportUnmatchedWait(PreCallEvent, ReqRegion, ExplNode);
+ }
+ }
+
+ if (!ReqRegions.empty()) {
+ Ctx.addTransition(State);
+ }
+}
+
+void MPICheckerPathSensitive::checkMissingWaits(
+ clang::ento::SymbolReaper &SymReaper, clang::ento::CheckerContext &Ctx) {
+ if (!SymReaper.hasDeadSymbols())
+ return;
+
+ ProgramStateRef State = Ctx.getState();
+
+ const auto &Requests = State->get<RequestMap>();
+ if (Requests.isEmpty())
+ return;
+
+ static CheckerProgramPointTag Tag("MPI-Checker", "MissingWait");
+ ExplodedNode *ErrorNode{nullptr};
+
+ auto ReqMap = State->get<RequestMap>();
+ for (const auto &Req : ReqMap) {
+ if (!SymReaper.isLiveRegion(Req.first)) {
+ if (Req.second.CurrentState == Request::State::Nonblocking) {
+
+ if (!ErrorNode) {
+ ErrorNode = Ctx.generateNonFatalErrorNode(State, &Tag);
+ State = ErrorNode->getState();
+ }
+ BugReporter.reportMissingWait(Req.second, Req.first, ErrorNode);
+ }
+ State = State->remove<RequestMap>(Req.first);
+ }
+ }
+
+ // Transition to update the state regarding removed requests.
+ if (ErrorNode) {
+ Ctx.addTransition(State, ErrorNode);
+ } else {
+ Ctx.addTransition(State);
+ }
+}
+
+void MPICheckerPathSensitive::checkMissingWaitsGlobals(ExplodedGraph &G) {
+
+ auto NodeIt = G.eop_begin();
+ const auto NodeEndIt = G.eop_end();
+
+ while (NodeIt != NodeEndIt) {
+ ProgramStateRef State = (*NodeIt)->getState();
+ const auto &ReqMap = State->get<RequestMap>();
+ for (const auto &Req : ReqMap) {
+ if (Req.second.CurrentState ==
+ clang::ento::mpi::Request::State::Nonblocking) {
+ BugReporter.reportMissingWait(Req.second, Req.first, *NodeIt);
+ }
+ }
+ ++NodeIt;
+ }
+}
+
+const MemRegion *MPICheckerPathSensitive::topRegionUsedByWait(
+ const clang::ento::CallEvent &CE) const {
+
+ if (FuncClassifier.isMPI_Wait(CE.getCalleeIdentifier())) {
+ return CE.getArgSVal(0).getAsRegion();
+ } else if (FuncClassifier.isMPI_Waitall(CE.getCalleeIdentifier())) {
+ return CE.getArgSVal(1).getAsRegion();
+ } else {
+ return (const MemRegion *)nullptr;
+ }
+}
+
+void MPICheckerPathSensitive::allRegionsUsedByWait(
+ llvm::SmallVector<const MemRegion *, 2> &ReqRegions,
+ const MemRegion *const MR, const clang::ento::CallEvent &CE,
+ clang::ento::CheckerContext &Ctx) const {
+
+ MemRegionManager *const RegionManager = MR->getMemRegionManager();
+
+ if (FuncClassifier.isMPI_Waitall(CE.getCalleeIdentifier())) {
+ const MemRegion *SuperRegion{nullptr};
+ if (const ElementRegion *const ER = MR->getAs<ElementRegion>()) {
+ SuperRegion = ER->getSuperRegion();
+ }
+
+ // A single request is passed to MPI_Waitall.
+ if (!SuperRegion) {
+ ReqRegions.push_back(MR);
+ return;
+ }
+
+ const auto &size = Ctx.getStoreManager().getSizeInElements(
+ Ctx.getState(), SuperRegion,
+ CE.getArgExpr(1)->getType()->getPointeeType());
+ const llvm::APSInt &arrSize = size.getAs<nonloc::ConcreteInt>()->getValue();
+
+ for (size_t i = 0; i < arrSize; ++i) {
+ const NonLoc Idx = Ctx.getSValBuilder().makeArrayIndex(i);
+
+ const ElementRegion *const ER = RegionManager->getElementRegion(
+ CE.getArgExpr(1)->getType()->getPointeeType(), Idx, SuperRegion,
+ Ctx.getASTContext());
+
+ ReqRegions.push_back(ER->getAs<MemRegion>());
+ }
+ } else if (FuncClassifier.isMPI_Wait(CE.getCalleeIdentifier())) {
+ ReqRegions.push_back(MR);
+ }
+}
+
+} // end of namespace: mpi
+} // end of namespace: clang
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIChecker.cpp
@@ -0,0 +1,60 @@
+//===-- MPIChecker.cpp - Checker Entry Point Class --------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the main class of MPI-Checker which serves as an entry
+/// point. It is created once for each translation unit analysed.
+///
+//===----------------------------------------------------------------------===//
+
+#include "../ClangSACheckers.h"
+#include "MPICheckerPathSensitive.h"
+
+using namespace clang::ento;
+
+namespace clang {
+namespace mpi {
+class MPIChecker
+ : public Checker<check::PreCall, check::DeadSymbols, check::EndAnalysis> {
+public:
+ // path-sensitive callbacks––––––––––––––––––––––––––––––––––––––––––––
+ void checkPreCall(const CallEvent &CE, CheckerContext &Ctx) const {
+ dynamicInit(Ctx);
+ CheckerSens->checkWaitUsage(CE, Ctx);
+ CheckerSens->checkDoubleNonblocking(CE, Ctx);
+ }
+
+ void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &Ctx) const {
+ dynamicInit(Ctx);
+ CheckerSens->checkMissingWaits(SymReaper, Ctx);
+ }
+
+ void checkEndAnalysis(ExplodedGraph &G, BugReporter &, ExprEngine &) const {
+ CheckerSens->checkMissingWaitsGlobals(G);
+ }
+
+private:
+ const std::unique_ptr<MPICheckerPathSensitive> CheckerSens;
+
+ void dynamicInit(CheckerContext &Ctx) const {
+ if (!CheckerSens) {
+ const_cast<std::unique_ptr<MPICheckerPathSensitive> &>(CheckerSens)
+ .reset(new MPICheckerPathSensitive(Ctx.getAnalysisManager(), this,
+ Ctx.getBugReporter()));
+ }
+ }
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+// Registers the checker for static analysis.
+void clang::ento::registerMPIChecker(CheckerManager &MGR) {
+ MGR.registerChecker<clang::mpi::MPIChecker>();
+}
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
@@ -0,0 +1,152 @@
+//===-- MPIBugReporter.h - bug reporter -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines prefabricated reports which are emitted in
+/// case of MPI related bugs, detected by AST-based and path-sensitive analysis.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIBUGREPORTER_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIBUGREPORTER_H
+
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "MPITypes.h"
+#include "MPIFunctionClassifier.h"
+
+namespace clang {
+namespace mpi {
+
+class MPIBugReporter {
+public:
+ MPIBugReporter(clang::ento::BugReporter &BR,
+ const clang::ento::CheckerBase &CB,
+ clang::ento::AnalysisManager &AM)
+ : BugReporter{BR}, CkrBase{CB}, AnalysisManager{AM}, FuncClassifier{AM} {
+ UnmatchedWaitBugType.reset(
+ new clang::ento::BugType(&CB, "Unmatched wait", MPIError));
+ DoubleNonblockingBugType.reset(
+ new clang::ento::BugType(&CB, "Double nonblocking", MPIError));
+ MissingWaitBugType.reset(
+ new clang::ento::BugType(&CB, "Missing wait", MPIError));
+ }
+
+ // ast reports ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
+
+ /// Report mismatch between buffer type and MPI datatype.
+ ///
+ /// \param MPICallExpr MPI call to report the mismatch for
+ /// \param IdxPair buffer type, MPI type index pair of the mismatch
+ /// \param BufferType buffer type
+ /// \param MPIType MPI datatype as string
+ void reportTypeMismatch(const clang::CallExpr *MPICallExpr,
+ const std::pair<size_t, size_t> &IdxPair,
+ const std::string &BufferTypeName,
+ const std::string MPIType) const;
+
+ /// Report if a buffer is not passed as a single pointer.
+ ///
+ /// \param MPICallExpr MPI call to report incorrect buffer referencing for
+ /// \param Idx index of incorrectly referenced buffer
+ /// \param PointerCount pointer count
+ void reportIncorrectBufferReferencing(const clang::CallExpr *MPICallExpr,
+ const size_t Idx,
+ const size_t PointerCount) const;
+
+ /// Report non-integer type usage at indices where not allowed. (e.g. rank)
+ ///
+ /// \param MPICallExpr MPI call to report the invalid argument type for
+ /// \param Idx argument index of invalid argument type
+ void reportInvalidArgumentType(const clang::CallExpr *const MPICallExpr,
+ const size_t Idx) const;
+
+ // path-sensitive reports –––––––––––––––––––––––––––––––––––––––––––––––
+
+ /// Report duplicate request use by nonblocking calls without intermediate
+ /// wait.
+ ///
+ /// \param MPICallEvent MPI call that caused the double nonblocking
+ /// \param Req request that was used by two nonblocking calls in sequence
+ /// \param RequestRegion memory region of the request
+ /// \param ExplNode node in the graph the bug appeared at
+ void reportDoubleNonblocking(
+ const clang::ento::CallEvent &MPICallEvent, const ento::mpi::Request &Req,
+ const clang::ento::MemRegion *const RequestRegion,
+ const clang::ento::ExplodedNode *const ExplNode) const;
+
+ /// Report a missing wait for a nonblocking call. A missing wait report
+ /// is emitted if a nonblocking call is not matched in the scope of a
+ /// function.
+ ///
+ /// \param Req request that is not matched by a wait
+ /// \param RequestRegion memory region of the request
+ /// \param ExplNode node in the graph the bug appeared at
+ void reportMissingWait(const ento::mpi::Request &Req,
+ const clang::ento::MemRegion *const RequestRegion,
+ const clang::ento::ExplodedNode *const ExplNode) const;
+
+ /// Report a wait on a request that has not been used at all before.
+ ///
+ /// \param CE wait call that uses the request
+ /// \param ReqRegion memory region of the request
+ /// \param ExplNode node in the graph the bug appeared at
+ void
+ reportUnmatchedWait(const clang::ento::CallEvent &CE,
+ const clang::ento::MemRegion *const RequestRegion,
+ const clang::ento::ExplodedNode *const ExplNode) const;
+
+ const clang::Decl *CurrentFunctionDecl = nullptr;
+
+private:
+ const std::string MPIError{"MPI Error"};
+
+ // path-sensitive bug types
+ std::unique_ptr<clang::ento::BugType> UnmatchedWaitBugType;
+ std::unique_ptr<clang::ento::BugType> MissingWaitBugType;
+ std::unique_ptr<clang::ento::BugType> DoubleNonblockingBugType;
+
+ clang::ento::BugReporter &BugReporter;
+ const clang::ento::CheckerBase &CkrBase;
+ clang::ento::AnalysisManager &AnalysisManager;
+ const clang::mpi::MPIFunctionClassifier FuncClassifier;
+
+ /// Bug visitor class to find the node where the request region was previously
+ /// used in order to include it into the BugReport path.
+ class RequestNodeVisitor
+ : public clang::ento::BugReporterVisitorImpl<RequestNodeVisitor> {
+ public:
+ RequestNodeVisitor(const clang::ento::MemRegion *const MemoryRegion,
+ std::string ErrText,
+ const clang::mpi::MPIFunctionClassifier &FC)
+ : RequestRegion(MemoryRegion), ErrorText{ErrText}, FuncClassifier{FC} {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ static int X = 0;
+ ID.AddPointer(&X);
+ ID.AddPointer(RequestRegion);
+ }
+
+ clang::ento::PathDiagnosticPiece *
+ VisitNode(const clang::ento::ExplodedNode *N,
+ const clang::ento::ExplodedNode *PrevN,
+ clang::ento::BugReporterContext &BRC,
+ clang::ento::BugReport &BR) override;
+
+ private:
+ const clang::ento::MemRegion *const RequestRegion;
+ bool IsNodeFound{false};
+ std::string ErrorText;
+ const clang::mpi::MPIFunctionClassifier &FuncClassifier;
+ };
+};
+
+} // end of namespace: mpi
+} // end of namespace: clang
+
+#endif
Index: tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
+++ tools/clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
@@ -0,0 +1,148 @@
+//===-- MPIBugReporter.cpp - bug reporter -----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines prefabricated reports which are emitted in
+/// case of MPI related bugs, detected by AST-based and path-sensitive analysis.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "MPIBugReporter.h"
+#include "Utility.h"
+#include "MPICheckerPathSensitive.h"
+
+using namespace clang::ento;
+
+namespace clang {
+namespace mpi {
+
+// bug reports ––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
+// path-sensitive reports –––––––––––––––––––––––––––––––––––––––––––––––––
+
+void MPIBugReporter::reportDoubleNonblocking(
+ const CallEvent &MPICallEvent, const ento::mpi::Request &Req,
+ const MemRegion *const RequestRegion,
+ const ExplodedNode *const ExplNode) const {
+
+ // Check if double nonblocking was caused by the same call.
+ std::string ErrorText;
+ ErrorText = "Double nonblocking on request " +
+ RequestRegion->getVariableName() + ". ";
+
+ auto Report = llvm::make_unique<BugReport>(*DoubleNonblockingBugType,
+ ErrorText, ExplNode);
+
+ Report->addRange(MPICallEvent.getSourceRange());
+ SourceRange Range = util::sourceRange(RequestRegion);
+ if (Range.isValid())
+ Report->addRange(Range);
+
+ Report->addVisitor(llvm::make_unique<RequestNodeVisitor>(
+ RequestRegion, "Request is previously used by nonblocking call here. ",
+ FuncClassifier));
+ Report->markInteresting(RequestRegion);
+
+ BugReporter.emitReport(std::move(Report));
+}
+
+void MPIBugReporter::reportMissingWait(
+ const ento::mpi::Request &Req, const MemRegion *const RequestRegion,
+ const ExplodedNode *const ExplNode) const {
+ std::string ErrorText{"Request " + RequestRegion->getVariableName() +
+ " has no matching wait. "};
+
+ auto Report =
+ llvm::make_unique<BugReport>(*MissingWaitBugType, ErrorText, ExplNode);
+
+ SourceRange Range = util::sourceRange(RequestRegion);
+ if (Range.isValid())
+ Report->addRange(Range);
+ Report->addVisitor(llvm::make_unique<RequestNodeVisitor>(
+ RequestRegion, "Request is previously used by nonblocking call here. ",
+ FuncClassifier));
+ Report->markInteresting(RequestRegion);
+
+ BugReporter.emitReport(std::move(Report));
+}
+
+void MPIBugReporter::reportUnmatchedWait(
+ const CallEvent &CE, const clang::ento::MemRegion *const RequestRegion,
+ const ExplodedNode *const ExplNode) const {
+ std::string ErrorText{"Request " + RequestRegion->getVariableName() +
+ " has no matching nonblocking call. "};
+
+ auto Report =
+ llvm::make_unique<BugReport>(*UnmatchedWaitBugType, ErrorText, ExplNode);
+
+ Report->addRange(CE.getSourceRange());
+ SourceRange Range = util::sourceRange(RequestRegion);
+ if (Range.isValid())
+ Report->addRange(Range);
+
+ BugReporter.emitReport(std::move(Report));
+}
+
+PathDiagnosticPiece *MPIBugReporter::RequestNodeVisitor::VisitNode(
+ const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC,
+ BugReport &BR) {
+
+ if (IsNodeFound)
+ return nullptr;
+
+ if (Optional<PreStmt> SP = N->getLocation().getAs<PreStmt>()) {
+ if (const CallExpr *CE = clang::dyn_cast<CallExpr>(SP->getStmt())) {
+
+ auto FuncIdentifier = CE->getDirectCallee()->getIdentifier();
+ CallEventManager &Mgr =
+ N->getState()->getStateManager().getCallEventManager();
+ // Find previous call that uses the request.
+ CallEventRef<> Call =
+ Mgr.getSimpleCall(CE, N->getState(), N->getLocationContext());
+
+ bool ReqUsedByCall{false};
+ // nonblocking
+ if (FuncClassifier.isNonBlockingType(FuncIdentifier)) {
+ SVal SV = Call->getArgSVal(Call->getNumArgs() - 1);
+ if (SV.getAsRegion() == RequestRegion) {
+ ReqUsedByCall = true;
+ }
+ }
+ // waitall
+ else if (FuncClassifier.isMPI_Waitall(FuncIdentifier)) {
+ const MemRegion *const OtherReqRegion =
+ Call->getArgSVal(1).getAsRegion();
+ if (OtherReqRegion == RequestRegion ||
+ (RequestRegion->isSubRegionOf(OtherReqRegion))) {
+ ReqUsedByCall = true;
+ }
+ }
+ // wait
+ else if (FuncClassifier.isMPI_Wait(FuncIdentifier)) {
+ if (Call->getArgSVal(0).getAsRegion() == RequestRegion) {
+ ReqUsedByCall = true;
+ }
+ }
+
+ if (ReqUsedByCall) {
+ // Do not include further locations.
+ IsNodeFound = true;
+ PathDiagnosticLocation Pos(CE, BRC.getSourceManager(),
+ N->getLocationContext());
+
+ return new PathDiagnosticEventPiece(Pos, ErrorText);
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+} // end of namespace: mpi
+} // end of namespace: clang
Index: tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
+++ tools/clang/lib/StaticAnalyzer/Checkers/Checkers.td
@@ -72,6 +72,8 @@
def LocalizabilityAlpha : Package<"localizability">, InPackage<CocoaAlpha>;
def LocalizabilityOptIn : Package<"localizability">, InPackage<CocoaOptIn>;
+def MPI : Package<"mpi">;
+
def LLVM : Package<"llvm">;
def Debug : Package<"debug">;
@@ -573,6 +575,12 @@
DescFile<"LocalizationChecker.cpp">;
}
+let ParentPackage = MPI in {
+def MPIChecker : Checker<"MPI-Checker">,
+ HelpText<"Checks MPI code">,
+ DescFile<"MPIChecker.cpp">;
+} // end "MPI"
+
//===----------------------------------------------------------------------===//
// Checkers for LLVM development.
//===----------------------------------------------------------------------===//
Index: tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
===================================================================
--- tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ tools/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -46,6 +46,11 @@
MallocChecker.cpp
MallocOverflowSecurityChecker.cpp
MallocSizeofChecker.cpp
+ MPI-Checker/MPIBugReporter.cpp
+ MPI-Checker/MPIChecker.cpp
+ MPI-Checker/MPICheckerPathSensitive.cpp
+ MPI-Checker/MPIFunctionClassifier.cpp
+ MPI-Checker/Utility.cpp
NSAutoreleasePoolChecker.cpp
NSErrorChecker.cpp
NoReturnFunctionChecker.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits