Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[analyzer] Add checker for correct usage of MPI API in C and C++.
This commit adds a static analysis checker to check for the correct usage of the MPI API in C and C++. 3 path-sensitive checks are included: - Double nonblocking: Double request usage by nonblocking calls without intermediate wait. - Missing wait: Nonblocking call without matching wait. - Unmatched wait: Waiting for a request that was never used by a nonblocking call. Examples of how to use the checker can be found at https://github.com/0ax1/MPI-Checker Reviewers: zaks.anna A patch by Alexander Droste! Differential Revision: http://reviews.llvm.org/D12761 llvm-svn: 271907
- Loading branch information
1 parent
cdf3492
commit 83ccd1a
Showing
15 changed files
with
1,546 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
//===-- 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 path-sensitive analysis. | ||
/// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "MPIBugReporter.h" | ||
#include "MPIChecker.h" | ||
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" | ||
|
||
namespace clang { | ||
namespace ento { | ||
namespace mpi { | ||
|
||
void MPIBugReporter::reportDoubleNonblocking( | ||
const CallEvent &MPICallEvent, const ento::mpi::Request &Req, | ||
const MemRegion *const RequestRegion, | ||
const ExplodedNode *const ExplNode) const { | ||
|
||
std::string ErrorText; | ||
ErrorText = "Double nonblocking on request " + | ||
RequestRegion->getDescriptiveName() + ". "; | ||
|
||
auto Report = llvm::make_unique<BugReport>(*DoubleNonblockingBugType, | ||
ErrorText, ExplNode); | ||
|
||
Report->addRange(MPICallEvent.getSourceRange()); | ||
SourceRange Range = RequestRegion->sourceRange(); | ||
|
||
if (Range.isValid()) | ||
Report->addRange(Range); | ||
|
||
Report->addVisitor(llvm::make_unique<RequestNodeVisitor>( | ||
RequestRegion, "Request is previously used by nonblocking call here. ")); | ||
Report->markInteresting(RequestRegion); | ||
|
||
BReporter.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->getDescriptiveName() + | ||
" has no matching wait. "}; | ||
|
||
auto Report = | ||
llvm::make_unique<BugReport>(*MissingWaitBugType, ErrorText, ExplNode); | ||
|
||
SourceRange Range = RequestRegion->sourceRange(); | ||
if (Range.isValid()) | ||
Report->addRange(Range); | ||
Report->addVisitor(llvm::make_unique<RequestNodeVisitor>( | ||
RequestRegion, "Request is previously used by nonblocking call here. ")); | ||
Report->markInteresting(RequestRegion); | ||
|
||
BReporter.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->getDescriptiveName() + | ||
" has no matching nonblocking call. "}; | ||
|
||
auto Report = | ||
llvm::make_unique<BugReport>(*UnmatchedWaitBugType, ErrorText, ExplNode); | ||
|
||
Report->addRange(CE.getSourceRange()); | ||
SourceRange Range = RequestRegion->sourceRange(); | ||
if (Range.isValid()) | ||
Report->addRange(Range); | ||
|
||
BReporter.emitReport(std::move(Report)); | ||
} | ||
|
||
PathDiagnosticPiece *MPIBugReporter::RequestNodeVisitor::VisitNode( | ||
const ExplodedNode *N, const ExplodedNode *PrevN, BugReporterContext &BRC, | ||
BugReport &BR) { | ||
|
||
if (IsNodeFound) | ||
return nullptr; | ||
|
||
const Request *const Req = N->getState()->get<RequestMap>(RequestRegion); | ||
const Request *const PrevReq = | ||
PrevN->getState()->get<RequestMap>(RequestRegion); | ||
|
||
// Check if request was previously unused or in a different state. | ||
if ((Req && !PrevReq) || (Req->CurrentState != PrevReq->CurrentState)) { | ||
IsNodeFound = true; | ||
|
||
ProgramPoint P = PrevN->getLocation(); | ||
PathDiagnosticLocation L = | ||
PathDiagnosticLocation::create(P, BRC.getSourceManager()); | ||
|
||
return new PathDiagnosticEventPiece(L, ErrorText); | ||
} | ||
|
||
return nullptr; | ||
} | ||
|
||
} // end of namespace: mpi | ||
} // end of namespace: ento | ||
} // end of namespace: clang |
110 changes: 110 additions & 0 deletions
110
clang/lib/StaticAnalyzer/Checkers/MPI-Checker/MPIBugReporter.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
//===-- 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 path-sensitive analysis. | ||
/// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIBUGREPORTER_H | ||
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_MPICHECKER_MPIBUGREPORTER_H | ||
|
||
#include "MPIFunctionClassifier.h" | ||
#include "MPITypes.h" | ||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" | ||
|
||
namespace clang { | ||
namespace ento { | ||
namespace mpi { | ||
|
||
class MPIBugReporter { | ||
public: | ||
MPIBugReporter(BugReporter &BR, const CheckerBase &CB, | ||
const MPIFunctionClassifier &FC) | ||
: BReporter{BR} { | ||
UnmatchedWaitBugType.reset(new BugType(&CB, "Unmatched wait", MPIError)); | ||
DoubleNonblockingBugType.reset( | ||
new BugType(&CB, "Double nonblocking", MPIError)); | ||
MissingWaitBugType.reset(new BugType(&CB, "Missing wait", MPIError)); | ||
} | ||
|
||
/// 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 CallEvent &MPICallEvent, | ||
const Request &Req, | ||
const MemRegion *const RequestRegion, | ||
const 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 Request &Req, | ||
const MemRegion *const RequestRegion, | ||
const 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 CallEvent &CE, | ||
const MemRegion *const RequestRegion, | ||
const ExplodedNode *const ExplNode) const; | ||
|
||
private: | ||
const std::string MPIError{"MPI Error"}; | ||
|
||
// path-sensitive bug types | ||
std::unique_ptr<BugType> UnmatchedWaitBugType; | ||
std::unique_ptr<BugType> MissingWaitBugType; | ||
std::unique_ptr<BugType> DoubleNonblockingBugType; | ||
|
||
BugReporter &BReporter; | ||
|
||
/// 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 BugReporterVisitorImpl<RequestNodeVisitor> { | ||
public: | ||
RequestNodeVisitor(const MemRegion *const MemoryRegion, | ||
const std::string &ErrText) | ||
: RequestRegion(MemoryRegion), ErrorText{ErrText} {} | ||
|
||
void Profile(llvm::FoldingSetNodeID &ID) const override { | ||
static int X = 0; | ||
ID.AddPointer(&X); | ||
ID.AddPointer(RequestRegion); | ||
} | ||
|
||
PathDiagnosticPiece *VisitNode(const ExplodedNode *N, | ||
const ExplodedNode *PrevN, | ||
BugReporterContext &BRC, | ||
BugReport &BR) override; | ||
|
||
private: | ||
const MemRegion *const RequestRegion; | ||
bool IsNodeFound{false}; | ||
std::string ErrorText; | ||
}; | ||
}; | ||
|
||
} // end of namespace: mpi | ||
} // end of namespace: ento | ||
} // end of namespace: clang | ||
|
||
#endif |
Oops, something went wrong.