24 using namespace clang;
29 class BlockInCriticalSectionChecker :
public Checker<check::PostCall> {
33 CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn,
34 PthreadLockFn, PthreadTryLockFn, PthreadUnlockFn,
35 MtxLock, MtxTimedLock, MtxTryLock, MtxUnlock;
37 StringRef ClassLockGuard, ClassUniqueLock;
39 mutable bool IdentifierInfoInitialized;
41 std::unique_ptr<BugType> BlockInCritSectionBugType;
43 void initIdentifierInfo(
ASTContext &Ctx)
const;
45 void reportBlockInCritSection(
SymbolRef FileDescSym,
50 BlockInCriticalSectionChecker();
52 bool isBlockingFunction(
const CallEvent &Call)
const;
53 bool isLockFunction(
const CallEvent &Call)
const;
54 bool isUnlockFunction(
const CallEvent &Call)
const;
66 BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
67 : IILockGuard(nullptr), IIUniqueLock(nullptr),
68 LockFn(
"lock"), UnlockFn(
"unlock"), SleepFn(
"sleep"), GetcFn(
"getc"),
69 FgetsFn(
"fgets"), ReadFn(
"read"), RecvFn(
"recv"),
70 PthreadLockFn(
"pthread_mutex_lock"),
71 PthreadTryLockFn(
"pthread_mutex_trylock"),
72 PthreadUnlockFn(
"pthread_mutex_unlock"),
74 MtxTimedLock(
"mtx_timedlock"),
75 MtxTryLock(
"mtx_trylock"),
76 MtxUnlock(
"mtx_unlock"),
77 ClassLockGuard(
"lock_guard"),
78 ClassUniqueLock(
"unique_lock"),
79 IdentifierInfoInitialized(
false) {
81 BlockInCritSectionBugType.reset(
82 new BugType(
this,
"Call to blocking function in critical section",
86 void BlockInCriticalSectionChecker::initIdentifierInfo(
ASTContext &Ctx)
const {
87 if (!IdentifierInfoInitialized) {
93 IILockGuard = &Ctx.
Idents.
get(ClassLockGuard);
94 IIUniqueLock = &Ctx.
Idents.
get(ClassUniqueLock);
95 IdentifierInfoInitialized =
true;
99 bool BlockInCriticalSectionChecker::isBlockingFunction(
const CallEvent &Call)
const {
110 bool BlockInCriticalSectionChecker::isLockFunction(
const CallEvent &Call)
const {
111 if (
const auto *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
112 auto IdentifierInfo = Ctor->getDecl()->getParent()->getIdentifier();
128 bool BlockInCriticalSectionChecker::isUnlockFunction(
const CallEvent &Call)
const {
129 if (
const auto *Dtor = dyn_cast<CXXDestructorCall>(&Call)) {
130 const auto *DRecordDecl = dyn_cast<
CXXRecordDecl>(Dtor->getDecl()->getParent());
132 if (IdentifierInfo == IILockGuard || IdentifierInfo == IIUniqueLock)
144 void BlockInCriticalSectionChecker::checkPostCall(
const CallEvent &Call,
148 if (!isBlockingFunction(Call)
149 && !isLockFunction(Call)
150 && !isUnlockFunction(Call))
154 unsigned mutexCount = State->get<MutexCounter>();
155 if (isUnlockFunction(Call) && mutexCount > 0) {
156 State = State->set<MutexCounter>(--mutexCount);
158 }
else if (isLockFunction(Call)) {
159 State = State->set<MutexCounter>(++mutexCount);
161 }
else if (mutexCount > 0) {
163 reportBlockInCritSection(BlockDesc, Call, C);
167 void BlockInCriticalSectionChecker::reportBlockInCritSection(
174 llvm::raw_string_ostream os(msg);
176 <<
"' inside of critical section";
177 auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType, os.str(), ErrNode);
179 R->markInteresting(BlockDescSym);
183 void ento::registerBlockInCriticalSectionChecker(
CheckerManager &mgr) {
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
SVal getReturnValue() const
Returns the return value of the call.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
const IdentifierInfo * getCalleeIdentifier() const
Returns the name of the callee, if its name is a simple identifier.
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
virtual SourceRange getSourceRange() const
Returns a source range for the entire call, suitable for outputting in diagnostics.
#define REGISTER_TRAIT_WITH_PROGRAMSTATE(Name, Type)
Declares a program state trait for type Type called Name, and introduce a typedef named NameTy...
CHECKER * registerChecker()
Used to register checkers.
This class represents a description of a function call using the number of arguments and the name of ...
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
StringRef getName() const
Return the actual identifier string.
Dataflow Directional Tag Classes.
ASTContext & getASTContext()
Represents an abstract call to a function or method along a particular path.
const ProgramStateRef & getState() const
Represents a C++ struct/union/class.
bool isCalled(const CallDescription &CD) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.