Skip to content
Snippets Groups Projects
Commit ac9bea8b authored by Ted Kremenek's avatar Ted Kremenek
Browse files

Add most of the boilerplate logic for a simple pthread_mutux_lock() ->...

Add most of the boilerplate logic for a simple pthread_mutux_lock() -> pthread_mutex_unlock() checker.  We need to add a visitor method to Checker for handling dead symbols in order to detect locks that are not unlocked.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86958 91177308-0d34-0410-b5e6-96231b3b80d8
parent 1acfe8ee
No related branches found
No related tags found
No related merge requests found
...@@ -16,7 +16,6 @@ add_clang_library(clangAnalysis ...@@ -16,7 +16,6 @@ add_clang_library(clangAnalysis
CallGraph.cpp CallGraph.cpp
CallInliner.cpp CallInliner.cpp
CastToStructChecker.cpp CastToStructChecker.cpp
CheckSizeofPointer.cpp
CheckDeadStores.cpp CheckDeadStores.cpp
CheckObjCDealloc.cpp CheckObjCDealloc.cpp
CheckObjCInstMethSignature.cpp CheckObjCInstMethSignature.cpp
...@@ -41,6 +40,7 @@ add_clang_library(clangAnalysis ...@@ -41,6 +40,7 @@ add_clang_library(clangAnalysis
PathDiagnostic.cpp PathDiagnostic.cpp
PointerArithChecker.cpp PointerArithChecker.cpp
PointerSubChecker.cpp PointerSubChecker.cpp
PthreadLockChecker.cpp
RangeConstraintManager.cpp RangeConstraintManager.cpp
RegionStore.cpp RegionStore.cpp
ReturnPointerRangeChecker.cpp ReturnPointerRangeChecker.cpp
......
//=-- GRExprEngineExperimentalChecks.h ------------------------------*- C++ -*-=
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines functions to instantiate and register experimental
// checks in GRExprEngine.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
#define LLVM_CLANG_GREXPRENGINE_EXPERIMENTAL_CHECKS
namespace clang {
class GRExprEngine;
void RegisterPthreadLockChecker(GRExprEngine &Eng);
} // end clang namespace
#endif
//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually
// this shouldn't be registered with GRExprEngineInternalChecks.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "GRExprEngineExperimentalChecks.h"
#include "llvm/ADT/ImmutableSet.h"
using namespace clang;
namespace {
class VISIBILITY_HIDDEN PthreadLockChecker
: public CheckerVisitor<PthreadLockChecker> {
BugType *BT;
public:
PthreadLockChecker() : BT(0) {}
static void *getTag() {
static int x = 0;
return &x;
}
void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
void AcquireLock(CheckerContext &C, const CallExpr *CE,
SVal lock, bool isTryLock);
void ReleaseLock(CheckerContext &C, const CallExpr *CE,
SVal lock);
};
} // end anonymous namespace
// GDM Entry for tracking lock state.
namespace { class VISIBILITY_HIDDEN LockSet {}; }
namespace clang {
template <> struct GRStateTrait<LockSet> :
public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
static void* GDMIndex() { return PthreadLockChecker::getTag(); }
};
} // end clang namespace
void clang::RegisterPthreadLockChecker(GRExprEngine &Eng) {
Eng.registerCheck(new PthreadLockChecker());
}
void PthreadLockChecker::PreVisitCallExpr(CheckerContext &C,
const CallExpr *CE) {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
const CodeTextRegion *R =
dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion());
if (!R)
return;
llvm::StringRef FName = R->getDecl()->getName();
if (FName == "pthread_mutex_lock") {
if (CE->getNumArgs() != 1)
return;
AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
}
else if (FName == "pthread_mutex_trylock") {
if (CE->getNumArgs() != 1)
return;
AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
}
}
void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
const CallExpr *CE) {
const GRState *state = C.getState();
const Expr *Callee = CE->getCallee();
const CodeTextRegion *R =
dyn_cast_or_null<CodeTextRegion>(state->getSVal(Callee).getAsRegion());
if (!R)
return;
llvm::StringRef FName = R->getDecl()->getName();
if (FName == "pthread_mutex_unlock") {
if (CE->getNumArgs() != 1)
return;
ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
}
}
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
SVal lock, bool isTryLock) {
const MemRegion *lockR = lock.getAsRegion();
if (!lockR)
return;
const GRState *state = C.getState();
SVal X = state->getSVal(CE);
if (X.isUnknownOrUndef())
return;
DefinedSVal retVal = cast<DefinedSVal>(X);
const GRState *lockSucc = state;
if (isTryLock) {
// Bifurcate the state, and allow a mode where the lock acquisition fails.
const GRState *lockFail;
llvm::tie(lockFail, lockSucc) = state->Assume(retVal);
assert(lockFail && lockSucc);
C.addTransition(C.GenerateNode(CE, lockFail));
}
else {
// Assume that the return value was 0.
lockSucc = state->Assume(retVal, false);
assert(lockSucc);
}
// Record that the lock was acquired.
lockSucc = lockSucc->add<LockSet>(lockR);
C.addTransition(lockSucc != state ? C.GenerateNode(CE, lockSucc) :
C.getPredecessor());
}
void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
SVal lock) {
const MemRegion *lockR = lock.getAsRegion();
if (!lockR)
return;
const GRState *state = C.getState();
// Record that the lock was released.
// FIXME: Handle unlocking locks that were never acquired. This may
// require IPA for wrappers.
const GRState *unlockState = state->remove<LockSet>(lockR);
if (state == unlockState)
return;
C.addTransition(C.GenerateNode(CE, unlockState));
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment