24 using namespace clang;
29 class BlockInCriticalSectionChecker :
public Checker<check::PostCall,
32 CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn,
33 PthreadLockFn, PthreadTryLockFn, PthreadUnlockFn,
34 MtxLock, MtxTimedLock, MtxTryLock, MtxUnlock;
36 std::unique_ptr<BugType> BlockInCritSectionBugType;
38 void reportBlockInCritSection(
SymbolRef FileDescSym,
43 BlockInCriticalSectionChecker();
45 bool isBlockingFunction(
const CallEvent &Call)
const;
46 bool isLockFunction(
const CallEvent &Call)
const;
47 bool isUnlockFunction(
const CallEvent &Call)
const;
62 BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
63 : LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
64 FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"),
65 PthreadLockFn("pthread_mutex_lock"),
66 PthreadTryLockFn("pthread_mutex_trylock"),
67 PthreadUnlockFn("pthread_mutex_unlock"),
69 MtxTimedLock("mtx_timedlock"),
70 MtxTryLock("mtx_trylock"),
71 MtxUnlock("mtx_unlock") {
73 BlockInCritSectionBugType.reset(
74 new BugType(
this,
"Call to blocking function in critical section",
78 bool BlockInCriticalSectionChecker::isBlockingFunction(
const CallEvent &Call)
const {
89 bool BlockInCriticalSectionChecker::isLockFunction(
const CallEvent &Call)
const {
101 bool BlockInCriticalSectionChecker::isUnlockFunction(
const CallEvent &Call)
const {
110 void BlockInCriticalSectionChecker::checkPreCall(
const CallEvent &Call,
114 void BlockInCriticalSectionChecker::checkPostCall(
const CallEvent &Call,
116 if (!isBlockingFunction(Call)
117 && !isLockFunction(Call)
118 && !isUnlockFunction(Call))
122 unsigned mutexCount = State->get<MutexCounter>();
123 if (isUnlockFunction(Call) && mutexCount > 0) {
124 State = State->set<MutexCounter>(--mutexCount);
126 }
else if (isLockFunction(Call)) {
127 State = State->set<MutexCounter>(++mutexCount);
129 }
else if (mutexCount > 0) {
131 reportBlockInCritSection(BlockDesc, Call, C);
135 void BlockInCriticalSectionChecker::reportBlockInCritSection(
142 llvm::raw_string_ostream os(msg);
144 <<
"' inside of critical section";
145 auto R = llvm::make_unique<BugReport>(*BlockInCritSectionBugType, os.str(), ErrNode);
147 R->markInteresting(BlockDescSym);
151 void ento::registerBlockInCriticalSectionChecker(
CheckerManager &mgr) {
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
bool isCalled(const CallDescription &CD) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
StringRef getName() const
Return the actual identifier string.
const ProgramStateRef & getState() const
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.
#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 ...
virtual SourceRange getSourceRange() const
Returns a source range for the entire call, suitable for outputting in diagnostics.
const IdentifierInfo * getCalleeIdentifier() const
Returns the name of the callee, if its name is a simple identifier.
Represents an abstract call to a function or method along a particular path.
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
SVal getReturnValue() const
Returns the return value of the call.