[analyzer] Apply whitespace cleanups by Honggyu Kim.

llvm-svn: 246978
This commit is contained in:
Ted Kremenek 2015-09-08 03:50:52 +00:00
parent 21dfbfb426
commit 3a0678e33c
85 changed files with 983 additions and 985 deletions

View File

@ -101,7 +101,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
else if (isa<BlockDecl>(D)) { else if (isa<BlockDecl>(D)) {
output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn(); output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
} }
NumBlocksUnreachable += unreachable; NumBlocksUnreachable += unreachable;
NumBlocks += total; NumBlocks += total;
std::string NameOfRootFunction = output.str(); std::string NameOfRootFunction = output.str();

View File

@ -23,7 +23,7 @@ using namespace clang;
using namespace ento; using namespace ento;
namespace { namespace {
class ArrayBoundChecker : class ArrayBoundChecker :
public Checker<check::Location> { public Checker<check::Location> {
mutable std::unique_ptr<BuiltinBug> BT; mutable std::unique_ptr<BuiltinBug> BT;
@ -55,8 +55,8 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
// Get the size of the array. // Get the size of the array.
DefinedOrUnknownSVal NumElements DefinedOrUnknownSVal NumElements
= C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(), = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
ER->getValueType()); ER->getValueType());
ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true); ProgramStateRef StInBound = state->assumeInBound(Idx, NumElements, true);
@ -65,7 +65,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
ExplodedNode *N = C.generateSink(StOutBound); ExplodedNode *N = C.generateSink(StOutBound);
if (!N) if (!N)
return; return;
if (!BT) if (!BT)
BT.reset(new BuiltinBug( BT.reset(new BuiltinBug(
this, "Out-of-bound array access", this, "Out-of-bound array access",
@ -82,7 +82,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
C.emitReport(std::move(report)); C.emitReport(std::move(report));
return; return;
} }
// Array bound check succeeded. From this point forward the array bound // Array bound check succeeded. From this point forward the array bound
// should always succeed. // should always succeed.
C.addTransition(StInBound); C.addTransition(StInBound);

View File

@ -26,15 +26,15 @@ using namespace clang;
using namespace ento; using namespace ento;
namespace { namespace {
class ArrayBoundCheckerV2 : class ArrayBoundCheckerV2 :
public Checker<check::Location> { public Checker<check::Location> {
mutable std::unique_ptr<BuiltinBug> BT; mutable std::unique_ptr<BuiltinBug> BT;
enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted }; enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted };
void reportOOB(CheckerContext &C, ProgramStateRef errorState, void reportOOB(CheckerContext &C, ProgramStateRef errorState,
OOB_Kind kind) const; OOB_Kind kind) const;
public: public:
void checkLocation(SVal l, bool isLoad, const Stmt*S, void checkLocation(SVal l, bool isLoad, const Stmt*S,
CheckerContext &C) const; CheckerContext &C) const;
@ -55,7 +55,7 @@ public:
NonLoc getByteOffset() const { return byteOffset.castAs<NonLoc>(); } NonLoc getByteOffset() const { return byteOffset.castAs<NonLoc>(); }
const SubRegion *getRegion() const { return baseRegion; } const SubRegion *getRegion() const { return baseRegion; }
static RegionRawOffsetV2 computeOffset(ProgramStateRef state, static RegionRawOffsetV2 computeOffset(ProgramStateRef state,
SValBuilder &svalBuilder, SValBuilder &svalBuilder,
SVal location); SVal location);
@ -65,12 +65,12 @@ public:
}; };
} }
static SVal computeExtentBegin(SValBuilder &svalBuilder, static SVal computeExtentBegin(SValBuilder &svalBuilder,
const MemRegion *region) { const MemRegion *region) {
while (true) while (true)
switch (region->getKind()) { switch (region->getKind()) {
default: default:
return svalBuilder.makeZeroArrayIndex(); return svalBuilder.makeZeroArrayIndex();
case MemRegion::SymbolicRegionKind: case MemRegion::SymbolicRegionKind:
// FIXME: improve this later by tracking symbolic lower bounds // FIXME: improve this later by tracking symbolic lower bounds
// for symbolic regions. // for symbolic regions.
@ -94,22 +94,22 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
// memory access is within the extent of the base region. Since we // memory access is within the extent of the base region. Since we
// have some flexibility in defining the base region, we can achieve // have some flexibility in defining the base region, we can achieve
// various levels of conservatism in our buffer overflow checking. // various levels of conservatism in our buffer overflow checking.
ProgramStateRef state = checkerContext.getState(); ProgramStateRef state = checkerContext.getState();
ProgramStateRef originalState = state; ProgramStateRef originalState = state;
SValBuilder &svalBuilder = checkerContext.getSValBuilder(); SValBuilder &svalBuilder = checkerContext.getSValBuilder();
const RegionRawOffsetV2 &rawOffset = const RegionRawOffsetV2 &rawOffset =
RegionRawOffsetV2::computeOffset(state, svalBuilder, location); RegionRawOffsetV2::computeOffset(state, svalBuilder, location);
if (!rawOffset.getRegion()) if (!rawOffset.getRegion())
return; return;
// CHECK LOWER BOUND: Is byteOffset < extent begin? // CHECK LOWER BOUND: Is byteOffset < extent begin?
// If so, we are doing a load/store // If so, we are doing a load/store
// before the first valid offset in the memory region. // before the first valid offset in the memory region.
SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion()); SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion());
if (Optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) { if (Optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) {
SVal lowerBound = SVal lowerBound =
svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(), *NV, svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(), *NV,
@ -118,7 +118,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
Optional<NonLoc> lowerBoundToCheck = lowerBound.getAs<NonLoc>(); Optional<NonLoc> lowerBoundToCheck = lowerBound.getAs<NonLoc>();
if (!lowerBoundToCheck) if (!lowerBoundToCheck)
return; return;
ProgramStateRef state_precedesLowerBound, state_withinLowerBound; ProgramStateRef state_precedesLowerBound, state_withinLowerBound;
std::tie(state_precedesLowerBound, state_withinLowerBound) = std::tie(state_precedesLowerBound, state_withinLowerBound) =
state->assume(*lowerBoundToCheck); state->assume(*lowerBoundToCheck);
@ -128,12 +128,12 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes); reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
return; return;
} }
// Otherwise, assume the constraint of the lower bound. // Otherwise, assume the constraint of the lower bound.
assert(state_withinLowerBound); assert(state_withinLowerBound);
state = state_withinLowerBound; state = state_withinLowerBound;
} }
do { do {
// CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)? If so, // CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)? If so,
// we are doing a load/store after the last valid offset. // we are doing a load/store after the last valid offset.
@ -146,11 +146,11 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
= svalBuilder.evalBinOpNN(state, BO_GE, rawOffset.getByteOffset(), = svalBuilder.evalBinOpNN(state, BO_GE, rawOffset.getByteOffset(),
extentVal.castAs<NonLoc>(), extentVal.castAs<NonLoc>(),
svalBuilder.getConditionType()); svalBuilder.getConditionType());
Optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>(); Optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>();
if (!upperboundToCheck) if (!upperboundToCheck)
break; break;
ProgramStateRef state_exceedsUpperBound, state_withinUpperBound; ProgramStateRef state_exceedsUpperBound, state_withinUpperBound;
std::tie(state_exceedsUpperBound, state_withinUpperBound) = std::tie(state_exceedsUpperBound, state_withinUpperBound) =
state->assume(*upperboundToCheck); state->assume(*upperboundToCheck);
@ -161,19 +161,19 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted); reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted);
return; return;
} }
// If we are constrained enough to definitely exceed the upper bound, report. // If we are constrained enough to definitely exceed the upper bound, report.
if (state_exceedsUpperBound) { if (state_exceedsUpperBound) {
assert(!state_withinUpperBound); assert(!state_withinUpperBound);
reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes); reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
return; return;
} }
assert(state_withinUpperBound); assert(state_withinUpperBound);
state = state_withinUpperBound; state = state_withinUpperBound;
} }
while (false); while (false);
if (state != originalState) if (state != originalState)
checkerContext.addTransition(state); checkerContext.addTransition(state);
} }
@ -181,7 +181,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
ProgramStateRef errorState, ProgramStateRef errorState,
OOB_Kind kind) const { OOB_Kind kind) const {
ExplodedNode *errorNode = checkerContext.generateSink(errorState); ExplodedNode *errorNode = checkerContext.generateSink(errorState);
if (!errorNode) if (!errorNode)
return; return;
@ -259,7 +259,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
{ {
const MemRegion *region = location.getAsRegion(); const MemRegion *region = location.getAsRegion();
SVal offset = UndefinedVal(); SVal offset = UndefinedVal();
while (region) { while (region) {
switch (region->getKind()) { switch (region->getKind()) {
default: { default: {
@ -280,7 +280,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
ASTContext &astContext = svalBuilder.getContext(); ASTContext &astContext = svalBuilder.getContext();
if (elemType->isIncompleteType()) if (elemType->isIncompleteType())
return RegionRawOffsetV2(); return RegionRawOffsetV2();
// Update the offset. // Update the offset.
offset = addValue(state, offset = addValue(state,
getValue(offset, svalBuilder), getValue(offset, svalBuilder),

View File

@ -143,7 +143,7 @@ void NilArgChecker::warnIfNilExpr(const Expr *E,
if (ExplodedNode *N = C.generateSink()) { if (ExplodedNode *N = C.generateSink()) {
generateBugReport(N, Msg, E->getSourceRange(), E, C); generateBugReport(N, Msg, E->getSourceRange(), E, C);
} }
} }
} }
@ -156,7 +156,7 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C,
ProgramStateRef State = C.getState(); ProgramStateRef State = C.getState();
if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue()) if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
return; return;
if (ExplodedNode *N = C.generateSink()) { if (ExplodedNode *N = C.generateSink()) {
SmallString<128> sbuf; SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf); llvm::raw_svector_ostream os(sbuf);
@ -193,7 +193,7 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C,
os << "' cannot be nil"; os << "' cannot be nil";
} }
} }
generateBugReport(N, os.str(), msg.getArgSourceRange(Arg), generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
msg.getArgExpr(Arg), C); msg.getArgExpr(Arg), C);
} }
@ -224,7 +224,7 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
static const unsigned InvalidArgIndex = UINT_MAX; static const unsigned InvalidArgIndex = UINT_MAX;
unsigned Arg = InvalidArgIndex; unsigned Arg = InvalidArgIndex;
bool CanBeSubscript = false; bool CanBeSubscript = false;
if (Class == FC_NSString) { if (Class == FC_NSString) {
Selector S = msg.getSelector(); Selector S = msg.getSelector();
@ -433,7 +433,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
const FunctionDecl *FD = C.getCalleeDecl(CE); const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD) if (!FD)
return; return;
ASTContext &Ctx = C.getASTContext(); ASTContext &Ctx = C.getASTContext();
if (!II) if (!II)
II = &Ctx.Idents.get("CFNumberCreate"); II = &Ctx.Idents.get("CFNumberCreate");
@ -495,17 +495,17 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
// FIXME: We can actually create an abstract "CFNumber" object that has // FIXME: We can actually create an abstract "CFNumber" object that has
// the bits initialized to the provided values. // the bits initialized to the provided values.
// //
if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink() if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
: C.addTransition()) { : C.addTransition()) {
SmallString<128> sbuf; SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf); llvm::raw_svector_ostream os(sbuf);
os << (SourceSize == 8 ? "An " : "A ") os << (SourceSize == 8 ? "An " : "A ")
<< SourceSize << " bit integer is used to initialize a CFNumber " << SourceSize << " bit integer is used to initialize a CFNumber "
"object that represents " "object that represents "
<< (TargetSize == 8 ? "an " : "a ") << (TargetSize == 8 ? "an " : "a ")
<< TargetSize << " bit integer. "; << TargetSize << " bit integer. ";
if (SourceSize < TargetSize) if (SourceSize < TargetSize)
os << (TargetSize - SourceSize) os << (TargetSize - SourceSize)
<< " bits of the CFNumber value will be garbage." ; << " bits of the CFNumber value will be garbage." ;
@ -549,7 +549,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
const FunctionDecl *FD = C.getCalleeDecl(CE); const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD) if (!FD)
return; return;
if (!BT) { if (!BT) {
ASTContext &Ctx = C.getASTContext(); ASTContext &Ctx = C.getASTContext();
Retain = &Ctx.Idents.get("CFRetain"); Retain = &Ctx.Idents.get("CFRetain");
@ -635,7 +635,7 @@ public:
void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
CheckerContext &C) const { CheckerContext &C) const {
if (!BT) { if (!BT) {
BT.reset(new APIMisuse( BT.reset(new APIMisuse(
this, "message incorrectly sent to class instead of class instance")); this, "message incorrectly sent to class instead of class instance"));
@ -646,7 +646,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
autoreleaseS = GetNullarySelector("autorelease", Ctx); autoreleaseS = GetNullarySelector("autorelease", Ctx);
drainS = GetNullarySelector("drain", Ctx); drainS = GetNullarySelector("drain", Ctx);
} }
if (msg.isInstanceMessage()) if (msg.isInstanceMessage())
return; return;
const ObjCInterfaceDecl *Class = msg.getReceiverInterface(); const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
@ -655,7 +655,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
Selector S = msg.getSelector(); Selector S = msg.getSelector();
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS)) if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
return; return;
if (ExplodedNode *N = C.addTransition()) { if (ExplodedNode *N = C.addTransition()) {
SmallString<200> buf; SmallString<200> buf;
llvm::raw_svector_ostream os(buf); llvm::raw_svector_ostream os(buf);
@ -665,7 +665,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
os << "' message should be sent to instances " os << "' message should be sent to instances "
"of class '" << Class->getName() "of class '" << Class->getName()
<< "' and not the class directly"; << "' and not the class directly";
auto report = llvm::make_unique<BugReport>(*BT, os.str(), N); auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
report->addRange(msg.getSourceRange()); report->addRange(msg.getSourceRange());
C.emitReport(std::move(report)); C.emitReport(std::move(report));
@ -699,12 +699,12 @@ public:
bool bool
VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const { VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
const ObjCMethodDecl *MD = msg.getDecl(); const ObjCMethodDecl *MD = msg.getDecl();
if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext())) if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
return false; return false;
Selector S = msg.getSelector(); Selector S = msg.getSelector();
if (msg.isInstanceMessage()) { if (msg.isInstanceMessage()) {
// FIXME: Ideally we'd look at the receiver interface here, but that's not // FIXME: Ideally we'd look at the receiver interface here, but that's not
// useful for init, because alloc returns 'id'. In theory, this could lead // useful for init, because alloc returns 'id'. In theory, this could lead
@ -751,7 +751,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
ASTContext &Ctx = C.getASTContext(); ASTContext &Ctx = C.getASTContext();
arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx); arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
dictionaryWithObjectsAndKeysS = dictionaryWithObjectsAndKeysS =
GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx); GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
setWithObjectsS = GetUnarySelector("setWithObjects", Ctx); setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx); orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
@ -789,11 +789,11 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// Ignore pointer constants. // Ignore pointer constants.
if (msg.getArgSVal(I).getAs<loc::ConcreteInt>()) if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
continue; continue;
// Ignore pointer types annotated with 'NSObject' attribute. // Ignore pointer types annotated with 'NSObject' attribute.
if (C.getASTContext().isObjCNSObjectType(ArgTy)) if (C.getASTContext().isObjCNSObjectType(ArgTy))
continue; continue;
// Ignore CF references, which can be toll-free bridged. // Ignore CF references, which can be toll-free bridged.
if (coreFoundation::isCFObjectRef(ArgTy)) if (coreFoundation::isCFObjectRef(ArgTy))
continue; continue;
@ -861,7 +861,7 @@ static bool isKnownNonNilCollectionType(QualType T) {
const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>(); const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
if (!PT) if (!PT)
return false; return false;
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
if (!ID) if (!ID)
return false; return false;
@ -1023,7 +1023,7 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
State = checkElementNonNil(C, State, FCS); State = checkElementNonNil(C, State, FCS);
State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true); State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
} }
if (!State) if (!State)
C.generateSink(); C.generateSink();
else if (State != C.getState()) else if (State != C.getState())
@ -1041,7 +1041,7 @@ bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
if (S.isUnarySelector() && if (S.isUnarySelector() &&
(S.getIdentifierInfoForSlot(0) == CountSelectorII)) (S.getIdentifierInfoForSlot(0) == CountSelectorII))
return true; return true;
return false; return false;
} }
@ -1069,7 +1069,7 @@ void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
// a call to "count" and add it to the map. // a call to "count" and add it to the map.
if (!isCollectionCountMethod(M, C)) if (!isCollectionCountMethod(M, C))
return; return;
const Expr *MsgExpr = M.getOriginExpr(); const Expr *MsgExpr = M.getOriginExpr();
SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol(); SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
if (CountS) { if (CountS) {

View File

@ -42,45 +42,45 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state,
static bool isBooleanType(QualType Ty) { static bool isBooleanType(QualType Ty) {
if (Ty->isBooleanType()) // C++ or C99 if (Ty->isBooleanType()) // C++ or C99
return true; return true;
if (const TypedefType *TT = Ty->getAs<TypedefType>()) if (const TypedefType *TT = Ty->getAs<TypedefType>())
return TT->getDecl()->getName() == "BOOL" || // Objective-C return TT->getDecl()->getName() == "BOOL" || // Objective-C
TT->getDecl()->getName() == "_Bool" || // stdbool.h < C99 TT->getDecl()->getName() == "_Bool" || // stdbool.h < C99
TT->getDecl()->getName() == "Boolean"; // MacTypes.h TT->getDecl()->getName() == "Boolean"; // MacTypes.h
return false; return false;
} }
void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S, void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
CheckerContext &C) const { CheckerContext &C) const {
// We are only interested in stores into Booleans. // We are only interested in stores into Booleans.
const TypedValueRegion *TR = const TypedValueRegion *TR =
dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion()); dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion());
if (!TR) if (!TR)
return; return;
QualType valTy = TR->getValueType(); QualType valTy = TR->getValueType();
if (!isBooleanType(valTy)) if (!isBooleanType(valTy))
return; return;
// Get the value of the right-hand side. We only care about values // Get the value of the right-hand side. We only care about values
// that are defined (UnknownVals and UndefinedVals are handled by other // that are defined (UnknownVals and UndefinedVals are handled by other
// checkers). // checkers).
Optional<DefinedSVal> DV = val.getAs<DefinedSVal>(); Optional<DefinedSVal> DV = val.getAs<DefinedSVal>();
if (!DV) if (!DV)
return; return;
// Check if the assigned value meets our criteria for correctness. It must // Check if the assigned value meets our criteria for correctness. It must
// be a value that is either 0 or 1. One way to check this is to see if // be a value that is either 0 or 1. One way to check this is to see if
// the value is possibly < 0 (for a negative value) or greater than 1. // the value is possibly < 0 (for a negative value) or greater than 1.
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
SValBuilder &svalBuilder = C.getSValBuilder(); SValBuilder &svalBuilder = C.getSValBuilder();
ConstraintManager &CM = C.getConstraintManager(); ConstraintManager &CM = C.getConstraintManager();
// First, ensure that the value is >= 0. // First, ensure that the value is >= 0.
DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy); DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy);
SVal greaterThanOrEqualToZeroVal = SVal greaterThanOrEqualToZeroVal =
svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal, svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal,
@ -91,13 +91,13 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
if (!greaterThanEqualToZero) { if (!greaterThanEqualToZero) {
// The SValBuilder cannot construct a valid SVal for this condition. // The SValBuilder cannot construct a valid SVal for this condition.
// This means we cannot properly reason about it. // This means we cannot properly reason about it.
return; return;
} }
ProgramStateRef stateLT, stateGE; ProgramStateRef stateLT, stateGE;
std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero); std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
// Is it possible for the value to be less than zero? // Is it possible for the value to be less than zero?
if (stateLT) { if (stateLT) {
// It is possible for the value to be less than zero. We only // It is possible for the value to be less than zero. We only
@ -106,15 +106,15 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// value is underconstrained and there is nothing left to be done. // value is underconstrained and there is nothing left to be done.
if (!stateGE) if (!stateGE)
emitReport(stateLT, C); emitReport(stateLT, C);
// In either case, we are done. // In either case, we are done.
return; return;
} }
// If we reach here, it must be the case that the value is constrained // If we reach here, it must be the case that the value is constrained
// to only be >= 0. // to only be >= 0.
assert(stateGE == state); assert(stateGE == state);
// At this point we know that the value is >= 0. // At this point we know that the value is >= 0.
// Now check to ensure that the value is <= 1. // Now check to ensure that the value is <= 1.
DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy); DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy);
@ -127,13 +127,13 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
if (!lessThanEqToOne) { if (!lessThanEqToOne) {
// The SValBuilder cannot construct a valid SVal for this condition. // The SValBuilder cannot construct a valid SVal for this condition.
// This means we cannot properly reason about it. // This means we cannot properly reason about it.
return; return;
} }
ProgramStateRef stateGT, stateLE; ProgramStateRef stateGT, stateLE;
std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne); std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne);
// Is it possible for the value to be greater than one? // Is it possible for the value to be greater than one?
if (stateGT) { if (stateGT) {
// It is possible for the value to be greater than one. We only // It is possible for the value to be greater than one. We only
@ -142,11 +142,11 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// value is underconstrained and there is nothing left to be done. // value is underconstrained and there is nothing left to be done.
if (!stateLE) if (!stateLE)
emitReport(stateGT, C); emitReport(stateGT, C);
// In either case, we are done. // In either case, we are done.
return; return;
} }
// If we reach here, it must be the case that the value is constrained // If we reach here, it must be the case that the value is constrained
// to only be <= 1. // to only be <= 1.
assert(stateLE == state); assert(stateLE == state);

View File

@ -65,7 +65,7 @@ public:
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
bool wantsRegionChangeUpdate(ProgramStateRef state) const; bool wantsRegionChangeUpdate(ProgramStateRef state) const;
ProgramStateRef ProgramStateRef
checkRegionChanges(ProgramStateRef state, checkRegionChanges(ProgramStateRef state,
const InvalidatedSymbols *, const InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> ExplicitRegions,
@ -92,7 +92,7 @@ public:
void evalstrLength(CheckerContext &C, const CallExpr *CE) const; void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
void evalstrnLength(CheckerContext &C, const CallExpr *CE) const; void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
void evalstrLengthCommon(CheckerContext &C, void evalstrLengthCommon(CheckerContext &C,
const CallExpr *CE, const CallExpr *CE,
bool IsStrnlen = false) const; bool IsStrnlen = false) const;
void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; void evalStrcpy(CheckerContext &C, const CallExpr *CE) const;
@ -137,9 +137,9 @@ public:
SVal Buf, SVal Buf,
bool hypothetical = false) const; bool hypothetical = false) const;
const StringLiteral *getCStringLiteral(CheckerContext &C, const StringLiteral *getCStringLiteral(CheckerContext &C,
ProgramStateRef &state, ProgramStateRef &state,
const Expr *expr, const Expr *expr,
SVal val) const; SVal val) const;
static ProgramStateRef InvalidateBuffer(CheckerContext &C, static ProgramStateRef InvalidateBuffer(CheckerContext &C,
@ -282,7 +282,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
// Get the size of the array. // Get the size of the array.
const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
SValBuilder &svalBuilder = C.getSValBuilder(); SValBuilder &svalBuilder = C.getSValBuilder();
SVal Extent = SVal Extent =
svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>(); DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>();
@ -327,7 +327,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
C.emitReport(std::move(report)); C.emitReport(std::move(report));
return nullptr; return nullptr;
} }
// Array bound check succeeded. From this point forward the array bound // Array bound check succeeded. From this point forward the array bound
// should always succeed. // should always succeed.
return StInBound; return StInBound;
@ -442,7 +442,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
return state; return state;
// Are the two values the same? // Are the two values the same?
SValBuilder &svalBuilder = C.getSValBuilder(); SValBuilder &svalBuilder = C.getSValBuilder();
std::tie(stateTrue, stateFalse) = std::tie(stateTrue, stateFalse) =
state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc)); state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc));
@ -489,7 +489,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
// Bail out if the cast fails. // Bail out if the cast fails.
ASTContext &Ctx = svalBuilder.getContext(); ASTContext &Ctx = svalBuilder.getContext();
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy, SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy,
First->getType()); First->getType());
Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>(); Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
if (!FirstStartLoc) if (!FirstStartLoc)
@ -568,7 +568,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
} else { } else {
// Try switching the operands. (The order of these two assignments is // Try switching the operands. (The order of these two assignments is
// important!) // important!)
maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left, maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left,
sizeTy); sizeTy);
left = right; left = right;
} }
@ -723,7 +723,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
auto report = llvm::make_unique<BugReport>(*BT_NotCString, os.str(), N); auto report = llvm::make_unique<BugReport>(*BT_NotCString, os.str(), N);
report->addRange(Ex->getSourceRange()); report->addRange(Ex->getSourceRange());
C.emitReport(std::move(report)); C.emitReport(std::move(report));
} }
return UndefinedVal(); return UndefinedVal();
@ -787,7 +787,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
auto report = llvm::make_unique<BugReport>(*BT_NotCString, os.str(), N); auto report = llvm::make_unique<BugReport>(*BT_NotCString, os.str(), N);
report->addRange(Ex->getSourceRange()); report->addRange(Ex->getSourceRange());
C.emitReport(std::move(report)); C.emitReport(std::move(report));
} }
return UndefinedVal(); return UndefinedVal();
@ -843,13 +843,13 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
// Invalidate and escape only indirect regions accessible through the source // Invalidate and escape only indirect regions accessible through the source
// buffer. // buffer.
if (IsSourceBuffer) { if (IsSourceBuffer) {
ITraits.setTrait(R, ITraits.setTrait(R,
RegionAndSymbolInvalidationTraits::TK_PreserveContents); RegionAndSymbolInvalidationTraits::TK_PreserveContents);
ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
CausesPointerEscape = true; CausesPointerEscape = true;
} }
return state->invalidateRegions(R, E, C.blockCount(), LCtx, return state->invalidateRegions(R, E, C.blockCount(), LCtx,
CausesPointerEscape, nullptr, nullptr, CausesPointerEscape, nullptr, nullptr,
&ITraits); &ITraits);
} }
@ -901,7 +901,7 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
// evaluation of individual function calls. // evaluation of individual function calls.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
void CStringChecker::evalCopyCommon(CheckerContext &C, void CStringChecker::evalCopyCommon(CheckerContext &C,
const CallExpr *CE, const CallExpr *CE,
ProgramStateRef state, ProgramStateRef state,
const Expr *Size, const Expr *Dest, const Expr *Size, const Expr *Dest,
@ -941,7 +941,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// Get the value of the Src. // Get the value of the Src.
SVal srcVal = state->getSVal(Source, LCtx); SVal srcVal = state->getSVal(Source, LCtx);
// Ensure the source is not null. If it is NULL there will be a // Ensure the source is not null. If it is NULL there will be a
// NULL pointer dereference. // NULL pointer dereference.
state = checkNonNull(C, state, Source, srcVal); state = checkNonNull(C, state, Source, srcVal);
@ -959,11 +959,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
if (!state) if (!state)
return; return;
// If this is mempcpy, get the byte after the last byte copied and // If this is mempcpy, get the byte after the last byte copied and
// bind the expr. // bind the expr.
if (IsMempcpy) { if (IsMempcpy) {
loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>(); loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>();
// Get the length to copy. // Get the length to copy.
if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) { if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) {
// Get the byte after the last byte copied. // Get the byte after the last byte copied.
@ -972,11 +972,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
loc::MemRegionVal DestRegCharVal = SvalBuilder.evalCast(destRegVal, loc::MemRegionVal DestRegCharVal = SvalBuilder.evalCast(destRegVal,
CharPtrTy, Dest->getType()).castAs<loc::MemRegionVal>(); CharPtrTy, Dest->getType()).castAs<loc::MemRegionVal>();
SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add, SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
DestRegCharVal, DestRegCharVal,
*lenValNonLoc, *lenValNonLoc,
Dest->getType()); Dest->getType());
// The byte after the last byte copied is the return value. // The byte after the last byte copied is the return value.
state = state->BindExpr(CE, LCtx, lastElement); state = state->BindExpr(CE, LCtx, lastElement);
} else { } else {
@ -999,12 +999,12 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
// can use LazyCompoundVals to copy the source values into the destination. // can use LazyCompoundVals to copy the source values into the destination.
// This would probably remove any existing bindings past the end of the // This would probably remove any existing bindings past the end of the
// copied region, but that's still an improvement over blank invalidation. // copied region, but that's still an improvement over blank invalidation.
state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest), state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest),
/*IsSourceBuffer*/false); /*IsSourceBuffer*/false);
// Invalidate the source (const-invalidation without const-pointer-escaping // Invalidate the source (const-invalidation without const-pointer-escaping
// the address of the top-level region). // the address of the top-level region).
state = InvalidateBuffer(C, state, Source, C.getSVal(Source), state = InvalidateBuffer(C, state, Source, C.getSVal(Source),
/*IsSourceBuffer*/true); /*IsSourceBuffer*/true);
C.addTransition(state); C.addTransition(state);
@ -1032,7 +1032,7 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
// The return value is a pointer to the byte following the last written byte. // The return value is a pointer to the byte following the last written byte.
const Expr *Dest = CE->getArg(0); const Expr *Dest = CE->getArg(0);
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true); evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true);
} }
@ -1053,7 +1053,7 @@ void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
return; return;
// void bcopy(const void *src, void *dst, size_t n); // void bcopy(const void *src, void *dst, size_t n);
evalCopyCommon(C, CE, C.getState(), evalCopyCommon(C, CE, C.getState(),
CE->getArg(2), CE->getArg(1), CE->getArg(0)); CE->getArg(2), CE->getArg(1), CE->getArg(0));
} }
@ -1244,7 +1244,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
state, BO_LE, resultNL, *strLengthNL, cmpTy) state, BO_LE, resultNL, *strLengthNL, cmpTy)
.castAs<DefinedOrUnknownSVal>(), true); .castAs<DefinedOrUnknownSVal>(), true);
} }
if (maxlenValNL) { if (maxlenValNL) {
state = state->assume(C.getSValBuilder().evalBinOpNN( state = state->assume(C.getSValBuilder().evalBinOpNN(
state, BO_LE, resultNL, *maxlenValNL, cmpTy) state, BO_LE, resultNL, *maxlenValNL, cmpTy)
@ -1275,8 +1275,8 @@ void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
return; return;
// char *strcpy(char *restrict dst, const char *restrict src); // char *strcpy(char *restrict dst, const char *restrict src);
evalStrcpyCommon(C, CE, evalStrcpyCommon(C, CE,
/* returnEnd = */ false, /* returnEnd = */ false,
/* isBounded = */ false, /* isBounded = */ false,
/* isAppending = */ false); /* isAppending = */ false);
} }
@ -1286,8 +1286,8 @@ void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
return; return;
// char *strncpy(char *restrict dst, const char *restrict src, size_t n); // char *strncpy(char *restrict dst, const char *restrict src, size_t n);
evalStrcpyCommon(C, CE, evalStrcpyCommon(C, CE,
/* returnEnd = */ false, /* returnEnd = */ false,
/* isBounded = */ true, /* isBounded = */ true,
/* isAppending = */ false); /* isAppending = */ false);
} }
@ -1297,8 +1297,8 @@ void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
return; return;
// char *stpcpy(char *restrict dst, const char *restrict src); // char *stpcpy(char *restrict dst, const char *restrict src);
evalStrcpyCommon(C, CE, evalStrcpyCommon(C, CE,
/* returnEnd = */ true, /* returnEnd = */ true,
/* isBounded = */ false, /* isBounded = */ false,
/* isAppending = */ false); /* isAppending = */ false);
} }
@ -1308,8 +1308,8 @@ void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
return; return;
//char *strcat(char *restrict s1, const char *restrict s2); //char *strcat(char *restrict s1, const char *restrict s2);
evalStrcpyCommon(C, CE, evalStrcpyCommon(C, CE,
/* returnEnd = */ false, /* returnEnd = */ false,
/* isBounded = */ false, /* isBounded = */ false,
/* isAppending = */ true); /* isAppending = */ true);
} }
@ -1319,8 +1319,8 @@ void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
return; return;
//char *strncat(char *restrict s1, const char *restrict s2, size_t n); //char *strncat(char *restrict s1, const char *restrict s2, size_t n);
evalStrcpyCommon(C, CE, evalStrcpyCommon(C, CE,
/* returnEnd = */ false, /* returnEnd = */ false,
/* isBounded = */ true, /* isBounded = */ true,
/* isAppending = */ true); /* isAppending = */ true);
} }
@ -1515,7 +1515,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
Optional<NonLoc> srcStrLengthNL = amountCopied.getAs<NonLoc>(); Optional<NonLoc> srcStrLengthNL = amountCopied.getAs<NonLoc>();
Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
// If we know both string lengths, we might know the final string length. // If we know both string lengths, we might know the final string length.
if (srcStrLengthNL && dstStrLengthNL) { if (srcStrLengthNL && dstStrLengthNL) {
// Make sure the two lengths together don't overflow a size_t. // Make sure the two lengths together don't overflow a size_t.
@ -1523,7 +1523,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (!state) if (!state)
return; return;
finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *srcStrLengthNL, finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *srcStrLengthNL,
*dstStrLengthNL, sizeTy); *dstStrLengthNL, sizeTy);
} }
@ -1586,7 +1586,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) { if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
*maxLastNL, ptrTy); *maxLastNL, ptrTy);
state = CheckLocation(C, state, CE->getArg(2), maxLastElement, state = CheckLocation(C, state, CE->getArg(2), maxLastElement,
boundWarning); boundWarning);
if (!state) if (!state)
return; return;
@ -1667,7 +1667,7 @@ void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const {
evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false); evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false);
} }
void CStringChecker::evalStrcasecmp(CheckerContext &C, void CStringChecker::evalStrcasecmp(CheckerContext &C,
const CallExpr *CE) const { const CallExpr *CE) const {
if (CE->getNumArgs() < 2) if (CE->getNumArgs() < 2)
return; return;
@ -1676,7 +1676,7 @@ void CStringChecker::evalStrcasecmp(CheckerContext &C,
evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true); evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true);
} }
void CStringChecker::evalStrncasecmp(CheckerContext &C, void CStringChecker::evalStrncasecmp(CheckerContext &C,
const CallExpr *CE) const { const CallExpr *CE) const {
if (CE->getNumArgs() < 3) if (CE->getNumArgs() < 3)
return; return;
@ -1915,7 +1915,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
evalFunction = &CStringChecker::evalBcopy; evalFunction = &CStringChecker::evalBcopy;
else if (C.isCLibraryFunction(FDecl, "bcmp")) else if (C.isCLibraryFunction(FDecl, "bcmp"))
evalFunction = &CStringChecker::evalMemcmp; evalFunction = &CStringChecker::evalMemcmp;
// If the callee isn't a string function, let another checker handle it. // If the callee isn't a string function, let another checker handle it.
if (!evalFunction) if (!evalFunction)
return false; return false;
@ -1975,7 +1975,7 @@ bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const {
return !Entries.isEmpty(); return !Entries.isEmpty();
} }
ProgramStateRef ProgramStateRef
CStringChecker::checkRegionChanges(ProgramStateRef state, CStringChecker::checkRegionChanges(ProgramStateRef state,
const InvalidatedSymbols *, const InvalidatedSymbols *,
ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> ExplicitRegions,

View File

@ -51,7 +51,7 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
if (E->getDecl()->getIdentifier() == SelfII) if (E->getDecl()->getIdentifier() == SelfII)
if (ME->getMethodDecl() == PD->getSetterMethodDecl() && if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
ME->getNumArgs() == 1 && ME->getNumArgs() == 1 &&
ME->getArg(0)->isNullPointerConstant(Ctx, ME->getArg(0)->isNullPointerConstant(Ctx,
Expr::NPC_ValueDependentIsNull)) Expr::NPC_ValueDependentIsNull))
return true; return true;
@ -61,7 +61,7 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
if (ObjCPropertyRefExpr *PRE = if (ObjCPropertyRefExpr *PRE =
dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts())) dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
if (PRE->isExplicitProperty() && PRE->getExplicitProperty() == PD) if (PRE->isExplicitProperty() && PRE->getExplicitProperty() == PD)
if (BO->getRHS()->isNullPointerConstant(Ctx, if (BO->getRHS()->isNullPointerConstant(Ctx,
Expr::NPC_ValueDependentIsNull)) { Expr::NPC_ValueDependentIsNull)) {
// This is only a 'release' if the property kind is not // This is only a 'release' if the property kind is not
// 'assign'. // 'assign'.

View File

@ -115,7 +115,7 @@ void WalkAST::VisitChildren(Stmt *S) {
} }
void WalkAST::VisitCallExpr(CallExpr *CE) { void WalkAST::VisitCallExpr(CallExpr *CE) {
// Get the callee. // Get the callee.
const FunctionDecl *FD = CE->getDirectCallee(); const FunctionDecl *FD = CE->getDirectCallee();
if (!FD) if (!FD)
@ -307,7 +307,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) { void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
if (!filter.check_gets) if (!filter.check_gets)
return; return;
const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>(); const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
if (!FPT) if (!FPT)
return; return;
@ -434,18 +434,18 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
.Case("mkdtemp", std::make_pair(0,-1)) .Case("mkdtemp", std::make_pair(0,-1))
.Case("mkstemps", std::make_pair(0,1)) .Case("mkstemps", std::make_pair(0,1))
.Default(std::make_pair(-1, -1)); .Default(std::make_pair(-1, -1));
assert(ArgSuffix.first >= 0 && "Unsupported function"); assert(ArgSuffix.first >= 0 && "Unsupported function");
// Check if the number of arguments is consistent with out expectations. // Check if the number of arguments is consistent with out expectations.
unsigned numArgs = CE->getNumArgs(); unsigned numArgs = CE->getNumArgs();
if ((signed) numArgs <= ArgSuffix.first) if ((signed) numArgs <= ArgSuffix.first)
return; return;
const StringLiteral *strArg = const StringLiteral *strArg =
dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first) dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
->IgnoreParenImpCasts()); ->IgnoreParenImpCasts());
// Currently we only handle string literals. It is possible to do better, // Currently we only handle string literals. It is possible to do better,
// either by looking at references to const variables, or by doing real // either by looking at references to const variables, or by doing real
// flow analysis. // flow analysis.
@ -470,13 +470,13 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
suffix = (unsigned) Result.getZExtValue(); suffix = (unsigned) Result.getZExtValue();
n = (n > suffix) ? n - suffix : 0; n = (n > suffix) ? n - suffix : 0;
} }
for (unsigned i = 0; i < n; ++i) for (unsigned i = 0; i < n; ++i)
if (str[i] == 'X') ++numX; if (str[i] == 'X') ++numX;
if (numX >= 6) if (numX >= 6)
return; return;
// Issue a warning. // Issue a warning.
PathDiagnosticLocation CELoc = PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
@ -502,13 +502,13 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Check: Any use of 'strcpy' is insecure. // Check: Any use of 'strcpy' is insecure.
// //
// CWE-119: Improper Restriction of Operations within // CWE-119: Improper Restriction of Operations within
// the Bounds of a Memory Buffer // the Bounds of a Memory Buffer
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) { void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
if (!filter.check_strcpy) if (!filter.check_strcpy)
return; return;
if (!checkCall_strCommon(CE, FD)) if (!checkCall_strCommon(CE, FD))
return; return;
@ -529,8 +529,8 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Check: Any use of 'strcat' is insecure. // Check: Any use of 'strcat' is insecure.
// //
// CWE-119: Improper Restriction of Operations within // CWE-119: Improper Restriction of Operations within
// the Bounds of a Memory Buffer // the Bounds of a Memory Buffer
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) { void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
if (!filter.check_strcpy) if (!filter.check_strcpy)
@ -684,7 +684,7 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
void WalkAST::checkUncheckedReturnValue(CallExpr *CE) { void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
if (!filter.check_UncheckedReturn) if (!filter.check_UncheckedReturn)
return; return;
const FunctionDecl *FD = CE->getDirectCallee(); const FunctionDecl *FD = CE->getDirectCallee();
if (!FD) if (!FD)
return; return;
@ -749,7 +749,7 @@ namespace {
class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> { class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
public: public:
ChecksFilter filter; ChecksFilter filter;
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
BugReporter &BR) const { BugReporter &BR) const {
WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter); WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);

View File

@ -55,8 +55,8 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
QualType T = E->getTypeOfArgument(); QualType T = E->getTypeOfArgument();
if (T->isPointerType()) { if (T->isPointerType()) {
// Many false positives have the form 'sizeof *p'. This is reasonable // Many false positives have the form 'sizeof *p'. This is reasonable
// because people know what they are doing when they intentionally // because people know what they are doing when they intentionally
// dereference the pointer. // dereference the pointer.
Expr *ArgEx = E->getArgumentExpr(); Expr *ArgEx = E->getArgumentExpr();
if (!isa<DeclRefExpr>(ArgEx->IgnoreParens())) if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))

View File

@ -222,7 +222,7 @@ public:
/// changed, this allows the analyzer core to skip the more expensive /// changed, this allows the analyzer core to skip the more expensive
/// #checkRegionChanges when no checkers are tracking any state. /// #checkRegionChanges when no checkers are tracking any state.
bool wantsRegionChangeUpdate(ProgramStateRef St) const { return true; } bool wantsRegionChangeUpdate(ProgramStateRef St) const { return true; }
/// \brief Called when the contents of one or more regions change. /// \brief Called when the contents of one or more regions change.
/// ///
/// This can occur in many different ways: an explicit bind, a blanket /// This can occur in many different ways: an explicit bind, a blanket
@ -246,7 +246,7 @@ public:
/// #wantsRegionChangeUpdate returns \c true. /// #wantsRegionChangeUpdate returns \c true.
/// ///
/// check::RegionChanges /// check::RegionChanges
ProgramStateRef ProgramStateRef
checkRegionChanges(ProgramStateRef State, checkRegionChanges(ProgramStateRef State,
const InvalidatedSymbols *Invalidated, const InvalidatedSymbols *Invalidated,
ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> ExplicitRegions,
@ -259,12 +259,12 @@ public:
/// ///
/// This notifies the checkers about pointer escape, which occurs whenever /// This notifies the checkers about pointer escape, which occurs whenever
/// the analyzer cannot track the symbol any more. For example, as a /// the analyzer cannot track the symbol any more. For example, as a
/// result of assigning a pointer into a global or when it's passed to a /// result of assigning a pointer into a global or when it's passed to a
/// function call the analyzer cannot model. /// function call the analyzer cannot model.
/// ///
/// \param State The state at the point of escape. /// \param State The state at the point of escape.
/// \param Escaped The list of escaped symbols. /// \param Escaped The list of escaped symbols.
/// \param Call The corresponding CallEvent, if the symbols escape as /// \param Call The corresponding CallEvent, if the symbols escape as
/// parameters to the given call. /// parameters to the given call.
/// \param Kind How the symbols have escaped. /// \param Kind How the symbols have escaped.
/// \returns Checkers can modify the state by returning a new state. /// \returns Checkers can modify the state by returning a new state.
@ -285,7 +285,7 @@ public:
PointerEscapeKind Kind) const { PointerEscapeKind Kind) const {
return State; return State;
} }
/// check::Event<ImplicitNullDerefEvent> /// check::Event<ImplicitNullDerefEvent>
void checkEvent(ImplicitNullDerefEvent Event) const {} void checkEvent(ImplicitNullDerefEvent Event) const {}

View File

@ -30,7 +30,7 @@ def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
def Security : Package <"security">; def Security : Package <"security">;
def InsecureAPI : Package<"insecureAPI">, InPackage<Security>; def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden; def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden;
def Taint : Package<"taint">, InPackage<SecurityAlpha>, Hidden; def Taint : Package<"taint">, InPackage<SecurityAlpha>, Hidden;
def Unix : Package<"unix">; def Unix : Package<"unix">;
def UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden; def UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden;
@ -192,7 +192,7 @@ def UndefBranchChecker : Checker<"Branch">,
def UndefCapturedBlockVarChecker : Checker<"CapturedBlockVariable">, def UndefCapturedBlockVarChecker : Checker<"CapturedBlockVariable">,
HelpText<"Check for blocks that capture uninitialized values">, HelpText<"Check for blocks that capture uninitialized values">,
DescFile<"UndefCapturedBlockVarChecker.cpp">; DescFile<"UndefCapturedBlockVarChecker.cpp">;
def ReturnUndefChecker : Checker<"UndefReturn">, def ReturnUndefChecker : Checker<"UndefReturn">,
HelpText<"Check for uninitialized values being returned to the caller">, HelpText<"Check for uninitialized values being returned to the caller">,
DescFile<"ReturnUndefChecker.cpp">; DescFile<"ReturnUndefChecker.cpp">;
@ -206,11 +206,11 @@ def ReturnUndefChecker : Checker<"UndefReturn">,
let ParentPackage = Cplusplus in { let ParentPackage = Cplusplus in {
def NewDeleteChecker : Checker<"NewDelete">, def NewDeleteChecker : Checker<"NewDelete">,
HelpText<"Check for double-free and use-after-free problems. Traces memory managed by new/delete.">, HelpText<"Check for double-free and use-after-free problems. Traces memory managed by new/delete.">,
DescFile<"MallocChecker.cpp">; DescFile<"MallocChecker.cpp">;
def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">, def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
HelpText<"Check for memory leaks. Traces memory managed by new/delete.">, HelpText<"Check for memory leaks. Traces memory managed by new/delete.">,
DescFile<"MallocChecker.cpp">; DescFile<"MallocChecker.cpp">;
} // end: "cplusplus" } // end: "cplusplus"
@ -218,7 +218,7 @@ def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
let ParentPackage = CplusplusAlpha in { let ParentPackage = CplusplusAlpha in {
def VirtualCallChecker : Checker<"VirtualCall">, def VirtualCallChecker : Checker<"VirtualCall">,
HelpText<"Check virtual function calls during construction or destruction">, HelpText<"Check virtual function calls during construction or destruction">,
DescFile<"VirtualCallChecker.cpp">; DescFile<"VirtualCallChecker.cpp">;
} // end: "alpha.cplusplus" } // end: "alpha.cplusplus"
@ -282,7 +282,7 @@ let ParentPackage = SecurityAlpha in {
def ArrayBoundChecker : Checker<"ArrayBound">, def ArrayBoundChecker : Checker<"ArrayBound">,
HelpText<"Warn about buffer overflows (older checker)">, HelpText<"Warn about buffer overflows (older checker)">,
DescFile<"ArrayBoundChecker.cpp">; DescFile<"ArrayBoundChecker.cpp">;
def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">, def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">,
HelpText<"Warn about buffer overflows (newer checker)">, HelpText<"Warn about buffer overflows (newer checker)">,
@ -323,7 +323,7 @@ def UnixAPIChecker : Checker<"API">,
def MallocChecker: Checker<"Malloc">, def MallocChecker: Checker<"Malloc">,
HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">, HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">,
DescFile<"MallocChecker.cpp">; DescFile<"MallocChecker.cpp">;
def MallocSizeofChecker : Checker<"MallocSizeof">, def MallocSizeofChecker : Checker<"MallocSizeof">,
HelpText<"Check for dubious malloc arguments involving sizeof">, HelpText<"Check for dubious malloc arguments involving sizeof">,
DescFile<"MallocSizeofChecker.cpp">; DescFile<"MallocSizeofChecker.cpp">;
@ -331,7 +331,7 @@ def MallocSizeofChecker : Checker<"MallocSizeof">,
def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">, def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">,
HelpText<"Check for mismatched deallocators.">, HelpText<"Check for mismatched deallocators.">,
DescFile<"MallocChecker.cpp">; DescFile<"MallocChecker.cpp">;
} // end "unix" } // end "unix"
let ParentPackage = UnixAlpha in { let ParentPackage = UnixAlpha in {
@ -362,7 +362,7 @@ def CStringNullArg : Checker<"NullArg">,
def CStringSyntaxChecker : Checker<"BadSizeArg">, def CStringSyntaxChecker : Checker<"BadSizeArg">,
HelpText<"Check the size argument passed into C string functions for common erroneous patterns">, HelpText<"Check the size argument passed into C string functions for common erroneous patterns">,
DescFile<"CStringSyntaxChecker.cpp">; DescFile<"CStringSyntaxChecker.cpp">;
} }
let ParentPackage = CStringAlpha in { let ParentPackage = CStringAlpha in {
@ -514,7 +514,7 @@ def ObjCContainersASTChecker : Checker<"PointerSizedValues">,
def ObjCContainersChecker : Checker<"OutOfBounds">, def ObjCContainersChecker : Checker<"OutOfBounds">,
HelpText<"Checks for index out-of-bounds when using 'CFArray' API">, HelpText<"Checks for index out-of-bounds when using 'CFArray' API">,
DescFile<"ObjCContainersChecker.cpp">; DescFile<"ObjCContainersChecker.cpp">;
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Checkers for LLVM development. // Checkers for LLVM development.

View File

@ -27,7 +27,7 @@ namespace {
// enum value that represent the jail state // enum value that represent the jail state
enum Kind { NO_CHROOT, ROOT_CHANGED, JAIL_ENTERED }; enum Kind { NO_CHROOT, ROOT_CHANGED, JAIL_ENTERED };
bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; } bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
//bool isJailEntered(intptr_t k) { return k == JAIL_ENTERED; } //bool isJailEntered(intptr_t k) { return k == JAIL_ENTERED; }
@ -50,7 +50,7 @@ public:
static int x; static int x;
return &x; return &x;
} }
bool evalCall(const CallExpr *CE, CheckerContext &C) const; bool evalCall(const CallExpr *CE, CheckerContext &C) const;
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@ -87,8 +87,8 @@ bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const { void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
ProgramStateManager &Mgr = state->getStateManager(); ProgramStateManager &Mgr = state->getStateManager();
// Once encouter a chroot(), set the enum value ROOT_CHANGED directly in // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in
// the GDM. // the GDM.
state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED); state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
C.addTransition(state); C.addTransition(state);
@ -106,7 +106,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
// After chdir("/"), enter the jail, set the enum value JAIL_ENTERED. // After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
const Expr *ArgExpr = CE->getArg(0); const Expr *ArgExpr = CE->getArg(0);
SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext()); SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
if (const MemRegion *R = ArgVal.getAsRegion()) { if (const MemRegion *R = ArgVal.getAsRegion()) {
R = R->StripCasts(); R = R->StripCasts();
if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) { if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) {
@ -135,7 +135,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
// Ingnore chroot and chdir. // Ingnore chroot and chdir.
if (FD->getIdentifier() == II_chroot || FD->getIdentifier() == II_chdir) if (FD->getIdentifier() == II_chroot || FD->getIdentifier() == II_chdir)
return; return;
// If jail state is ROOT_CHANGED, generate BugReport. // If jail state is ROOT_CHANGED, generate BugReport.
void *const* k = C.getState()->FindGDM(ChrootChecker::getTag()); void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
if (k) if (k)

View File

@ -28,36 +28,36 @@
using namespace clang; using namespace clang;
using namespace ento; using namespace ento;
namespace { namespace {
/// A simple visitor to record what VarDecls occur in EH-handling code. /// A simple visitor to record what VarDecls occur in EH-handling code.
class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> { class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
public: public:
bool inEH; bool inEH;
llvm::DenseSet<const VarDecl *> &S; llvm::DenseSet<const VarDecl *> &S;
bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
SaveAndRestore<bool> inFinally(inEH, true); SaveAndRestore<bool> inFinally(inEH, true);
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S); return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
} }
bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) { bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
SaveAndRestore<bool> inCatch(inEH, true); SaveAndRestore<bool> inCatch(inEH, true);
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S); return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
} }
bool TraverseCXXCatchStmt(CXXCatchStmt *S) { bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
SaveAndRestore<bool> inCatch(inEH, true); SaveAndRestore<bool> inCatch(inEH, true);
return TraverseStmt(S->getHandlerBlock()); return TraverseStmt(S->getHandlerBlock());
} }
bool VisitDeclRefExpr(DeclRefExpr *DR) { bool VisitDeclRefExpr(DeclRefExpr *DR) {
if (inEH) if (inEH)
if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl())) if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
S.insert(D); S.insert(D);
return true; return true;
} }
EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) : EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
inEH(false), S(S) {} inEH(false), S(S) {}
}; };
@ -70,9 +70,9 @@ class ReachableCode {
public: public:
ReachableCode(const CFG &cfg) ReachableCode(const CFG &cfg)
: cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {} : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
void computeReachableBlocks(); void computeReachableBlocks();
bool isReachable(const CFGBlock *block) const { bool isReachable(const CFGBlock *block) const {
return reachable[block->getBlockID()]; return reachable[block->getBlockID()];
} }
@ -82,7 +82,7 @@ public:
void ReachableCode::computeReachableBlocks() { void ReachableCode::computeReachableBlocks() {
if (!cfg.getNumBlockIDs()) if (!cfg.getNumBlockIDs())
return; return;
SmallVector<const CFGBlock*, 10> worklist; SmallVector<const CFGBlock*, 10> worklist;
worklist.push_back(&cfg.getEntry()); worklist.push_back(&cfg.getEntry());
@ -160,19 +160,19 @@ public:
// to analyze that yet. // to analyze that yet.
return InEH->count(D); return InEH->count(D);
} }
void Report(const VarDecl *V, DeadStoreKind dsk, void Report(const VarDecl *V, DeadStoreKind dsk,
PathDiagnosticLocation L, SourceRange R) { PathDiagnosticLocation L, SourceRange R) {
if (Escaped.count(V)) if (Escaped.count(V))
return; return;
// Compute reachable blocks within the CFG for trivial cases // Compute reachable blocks within the CFG for trivial cases
// where a bogus dead store can be reported because itself is unreachable. // where a bogus dead store can be reported because itself is unreachable.
if (!reachableCode.get()) { if (!reachableCode.get()) {
reachableCode.reset(new ReachableCode(cfg)); reachableCode.reset(new ReachableCode(cfg));
reachableCode->computeReachableBlocks(); reachableCode->computeReachableBlocks();
} }
if (!reachableCode->isReachable(currentBlock)) if (!reachableCode->isReachable(currentBlock))
return; return;
@ -196,7 +196,7 @@ public:
case Enclosing: case Enclosing:
// Don't report issues in this case, e.g.: "if (x = foo())", // Don't report issues in this case, e.g.: "if (x = foo())",
// where 'x' is unused later. We have yet to see a case where // where 'x' is unused later. We have yet to see a case where
// this is a real bug. // this is a real bug.
return; return;
} }
@ -259,7 +259,7 @@ public:
const LiveVariables::LivenessValues &Live) override { const LiveVariables::LivenessValues &Live) override {
currentBlock = block; currentBlock = block;
// Skip statements in macros. // Skip statements in macros.
if (S->getLocStart().isMacroID()) if (S->getLocStart().isMacroID())
return; return;
@ -276,7 +276,7 @@ public:
const Expr *RHS = const Expr *RHS =
LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS()); LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
RHS = RHS->IgnoreParenCasts(); RHS = RHS->IgnoreParenCasts();
QualType T = VD->getType(); QualType T = VD->getType();
if (T->isPointerType() || T->isObjCObjectPointerType()) { if (T->isPointerType() || T->isObjCObjectPointerType()) {
if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull)) if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
@ -318,27 +318,27 @@ public:
if (!V) if (!V)
continue; continue;
if (V->hasLocalStorage()) { if (V->hasLocalStorage()) {
// Reference types confuse the dead stores checker. Skip them // Reference types confuse the dead stores checker. Skip them
// for now. // for now.
if (V->getType()->getAs<ReferenceType>()) if (V->getType()->getAs<ReferenceType>())
return; return;
if (const Expr *E = V->getInit()) { if (const Expr *E = V->getInit()) {
while (const ExprWithCleanups *exprClean = while (const ExprWithCleanups *exprClean =
dyn_cast<ExprWithCleanups>(E)) dyn_cast<ExprWithCleanups>(E))
E = exprClean->getSubExpr(); E = exprClean->getSubExpr();
// Look through transitive assignments, e.g.: // Look through transitive assignments, e.g.:
// int x = y = 0; // int x = y = 0;
E = LookThroughTransitiveAssignmentsAndCommaOperators(E); E = LookThroughTransitiveAssignmentsAndCommaOperators(E);
// Don't warn on C++ objects (yet) until we can show that their // Don't warn on C++ objects (yet) until we can show that their
// constructors/destructors don't have side effects. // constructors/destructors don't have side effects.
if (isa<CXXConstructExpr>(E)) if (isa<CXXConstructExpr>(E))
return; return;
// A dead initialization is a variable that is dead after it // A dead initialization is a variable that is dead after it
// is initialized. We don't flag warnings for those variables // is initialized. We don't flag warnings for those variables
// marked 'unused' or 'objc_precise_lifetime'. // marked 'unused' or 'objc_precise_lifetime'.

View File

@ -84,7 +84,7 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
SourceLocation L = IV->getLocation(); SourceLocation L = IV->getLocation();
Ranges.push_back(SourceRange(L, L)); Ranges.push_back(SourceRange(L, L));
break; break;
} }
} }
} }

View File

@ -29,7 +29,7 @@ class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
CheckerContext &C) const ; CheckerContext &C) const ;
public: public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const; void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
}; };
} // end anonymous namespace } // end anonymous namespace
void DivZeroChecker::reportBug(const char *Msg, void DivZeroChecker::reportBug(const char *Msg,

View File

@ -113,7 +113,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
ProgramStateRef State = C.getState(); ProgramStateRef State = C.getState();
const ObjCMethodDecl *D = Msg->getDecl(); const ObjCMethodDecl *D = Msg->getDecl();
if (D && D->hasRelatedResultType()) { if (D && D->hasRelatedResultType()) {
switch (Msg->getMethodFamily()) { switch (Msg->getMethodFamily()) {
default: default:
@ -201,7 +201,7 @@ void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE,
const MemRegion *MR = C.getSVal(NewE).getAsRegion(); const MemRegion *MR = C.getSVal(NewE).getAsRegion();
if (!MR) if (!MR)
return; return;
C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(), C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(),
/*CanBeSubclass=*/false)); /*CanBeSubclass=*/false));
} }

View File

@ -23,7 +23,7 @@ using namespace clang;
using namespace ento; using namespace ento;
namespace { namespace {
class FixedAddressChecker class FixedAddressChecker
: public Checker< check::PreStmt<BinaryOperator> > { : public Checker< check::PreStmt<BinaryOperator> > {
mutable std::unique_ptr<BuiltinBug> BT; mutable std::unique_ptr<BuiltinBug> BT;

View File

@ -100,8 +100,8 @@ private:
/// Generate a report if the expression is tainted or points to tainted data. /// Generate a report if the expression is tainted or points to tainted data.
bool generateReportIfTainted(const Expr *E, const char Msg[], bool generateReportIfTainted(const Expr *E, const char Msg[],
CheckerContext &C) const; CheckerContext &C) const;
typedef SmallVector<unsigned, 2> ArgVector; typedef SmallVector<unsigned, 2> ArgVector;
/// \brief A struct used to specify taint propagation rules for a function. /// \brief A struct used to specify taint propagation rules for a function.
@ -441,7 +441,7 @@ SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
return Val.getAsSymbol(); return Val.getAsSymbol();
} }
ProgramStateRef ProgramStateRef
GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE, GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
CheckerContext &C) const { CheckerContext &C) const {
ProgramStateRef State = C.getState(); ProgramStateRef State = C.getState();
@ -667,8 +667,8 @@ bool GenericTaintChecker::checkUncontrolledFormatString(const CallExpr *CE,
bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, bool GenericTaintChecker::checkSystemCall(const CallExpr *CE,
StringRef Name, StringRef Name,
CheckerContext &C) const { CheckerContext &C) const {
// TODO: It might make sense to run this check on demand. In some cases, // TODO: It might make sense to run this check on demand. In some cases,
// we should check if the environment has been cleansed here. We also might // we should check if the environment has been cleansed here. We also might
// need to know if the user was reset before these calls(seteuid). // need to know if the user was reset before these calls(seteuid).
unsigned ArgNum = llvm::StringSwitch<unsigned>(Name) unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
.Case("system", 0) .Case("system", 0)

View File

@ -96,7 +96,7 @@ void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
} }
LHS = B2->getLHS(); LHS = B2->getLHS();
} }
if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) { if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
Sr[0] = RHS->getSourceRange(); Sr[0] = RHS->getSourceRange();
Sr[1] = LHS->getSourceRange(); Sr[1] = LHS->getSourceRange();

View File

@ -20,8 +20,8 @@
// been called on them. An invalidation method should either invalidate all // been called on them. An invalidation method should either invalidate all
// the ivars or call another invalidation method (on self). // the ivars or call another invalidation method (on self).
// //
// Partial invalidor annotation allows to addess cases when ivars are // Partial invalidor annotation allows to addess cases when ivars are
// invalidated by other methods, which might or might not be called from // invalidated by other methods, which might or might not be called from
// the invalidation method. The checker checks that each invalidation // the invalidation method. The checker checks that each invalidation
// method and all the partial methods cumulatively invalidate all ivars. // method and all the partial methods cumulatively invalidate all ivars.
// __attribute__((annotate("objc_instance_variable_invalidator_partial"))); // __attribute__((annotate("objc_instance_variable_invalidator_partial")));
@ -310,7 +310,7 @@ const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar(
// Lookup for the synthesized case. // Lookup for the synthesized case.
IvarD = Prop->getPropertyIvarDecl(); IvarD = Prop->getPropertyIvarDecl();
// We only track the ivars/properties that are defined in the current // We only track the ivars/properties that are defined in the current
// class (not the parent). // class (not the parent).
if (IvarD && IvarD->getContainingInterface() == InterfaceD) { if (IvarD && IvarD->getContainingInterface() == InterfaceD) {
if (TrackedIvars.count(IvarD)) { if (TrackedIvars.count(IvarD)) {

View File

@ -118,7 +118,7 @@ private:
SValBuilder &Builder) const { SValBuilder &Builder) const {
return definitelyReturnedError(RetSym, State, Builder, true); return definitelyReturnedError(RetSym, State, Builder, true);
} }
/// Mark an AllocationPair interesting for diagnostic reporting. /// Mark an AllocationPair interesting for diagnostic reporting.
void markInteresting(BugReport *R, const AllocationPair &AP) const { void markInteresting(BugReport *R, const AllocationPair &AP) const {
R->markInteresting(AP.first); R->markInteresting(AP.first);
@ -282,7 +282,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
const FunctionDecl *FD = C.getCalleeDecl(CE); const FunctionDecl *FD = C.getCalleeDecl(CE);
if (!FD || FD->getKind() != Decl::Function) if (!FD || FD->getKind() != Decl::Function)
return; return;
StringRef funName = C.getCalleeName(FD); StringRef funName = C.getCalleeName(FD);
if (funName.empty()) if (funName.empty())
return; return;

View File

@ -79,7 +79,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (TrimmedFName != FName) if (TrimmedFName != FName)
FName = TrimmedFName; FName = TrimmedFName;
} }
SmallString<256> S; SmallString<256> S;
llvm::raw_svector_ostream os(S); llvm::raw_svector_ostream os(S);
os << "Call to '" << FName << "' uses"; os << "Call to '" << FName << "' uses";

View File

@ -1,13 +1,13 @@
##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===## ##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===##
# #
# The LLVM Compiler Infrastructure # The LLVM Compiler Infrastructure
# #
# This file is distributed under the University of Illinois Open Source # This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details. # License. See LICENSE.TXT for details.
# #
##===----------------------------------------------------------------------===## ##===----------------------------------------------------------------------===##
# #
# This implements analyses built on top of source-level CFGs. # This implements analyses built on top of source-level CFGs.
# #
##===----------------------------------------------------------------------===## ##===----------------------------------------------------------------------===##

View File

@ -65,10 +65,10 @@ class RefState {
const Stmt *S; const Stmt *S;
unsigned K : 3; // Kind enum, but stored as a bitfield. unsigned K : 3; // Kind enum, but stored as a bitfield.
unsigned Family : 29; // Rest of 32-bit word, currently just an allocation unsigned Family : 29; // Rest of 32-bit word, currently just an allocation
// family. // family.
RefState(Kind k, const Stmt *s, unsigned family) RefState(Kind k, const Stmt *s, unsigned family)
: S(s), K(k), Family(family) { : S(s), K(k), Family(family) {
assert(family != AF_None); assert(family != AF_None);
} }
@ -94,7 +94,7 @@ public:
return RefState(AllocatedOfSizeZero, RS->getStmt(), return RefState(AllocatedOfSizeZero, RS->getStmt(),
RS->getAllocationFamily()); RS->getAllocationFamily());
} }
static RefState getReleased(unsigned family, const Stmt *s) { static RefState getReleased(unsigned family, const Stmt *s) {
return RefState(Released, s, family); return RefState(Released, s, family);
} }
static RefState getRelinquished(unsigned family, const Stmt *s) { static RefState getRelinquished(unsigned family, const Stmt *s) {
@ -169,9 +169,9 @@ class MallocChecker : public Checker<check::DeadSymbols,
{ {
public: public:
MallocChecker() MallocChecker()
: II_alloca(nullptr), II_malloc(nullptr), II_free(nullptr), : II_alloca(nullptr), II_malloc(nullptr), II_free(nullptr),
II_realloc(nullptr), II_calloc(nullptr), II_valloc(nullptr), II_realloc(nullptr), II_calloc(nullptr), II_valloc(nullptr),
II_reallocf(nullptr), II_strndup(nullptr), II_strdup(nullptr), II_reallocf(nullptr), II_strndup(nullptr), II_strdup(nullptr),
II_kmalloc(nullptr), II_if_nameindex(nullptr), II_kmalloc(nullptr), II_if_nameindex(nullptr),
II_if_freenameindex(nullptr) {} II_if_freenameindex(nullptr) {}
@ -185,7 +185,7 @@ public:
CK_NumCheckKinds CK_NumCheckKinds
}; };
enum class MemoryOperationKind { enum class MemoryOperationKind {
MOK_Allocate, MOK_Allocate,
MOK_Free, MOK_Free,
MOK_Any MOK_Any
@ -245,19 +245,19 @@ private:
/// \brief Print names of allocators and deallocators. /// \brief Print names of allocators and deallocators.
/// ///
/// \returns true on success. /// \returns true on success.
bool printAllocDeallocName(raw_ostream &os, CheckerContext &C, bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
const Expr *E) const; const Expr *E) const;
/// \brief Print expected name of an allocator based on the deallocator's /// \brief Print expected name of an allocator based on the deallocator's
/// family derived from the DeallocExpr. /// family derived from the DeallocExpr.
void printExpectedAllocName(raw_ostream &os, CheckerContext &C, void printExpectedAllocName(raw_ostream &os, CheckerContext &C,
const Expr *DeallocExpr) const; const Expr *DeallocExpr) const;
/// \brief Print expected name of a deallocator based on the allocator's /// \brief Print expected name of a deallocator based on the allocator's
/// family. /// family.
void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) const; void printExpectedDeallocName(raw_ostream &os, AllocationFamily Family) const;
///@{ ///@{
/// Check if this is one of the functions which can allocate/reallocate memory /// Check if this is one of the functions which can allocate/reallocate memory
/// pointed to by one of its arguments. /// pointed to by one of its arguments.
bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const; bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
bool isCMemFunction(const FunctionDecl *FD, bool isCMemFunction(const FunctionDecl *FD,
@ -292,7 +292,7 @@ private:
const ProgramStateRef &State) const; const ProgramStateRef &State) const;
/// Update the RefState to reflect the new memory allocation. /// Update the RefState to reflect the new memory allocation.
static ProgramStateRef static ProgramStateRef
MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State, MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
AllocationFamily Family = AF_Malloc); AllocationFamily Family = AF_Malloc);
@ -312,17 +312,17 @@ private:
bool ReturnsNullOnFailure = false) const; bool ReturnsNullOnFailure = false) const;
ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE, ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
bool FreesMemOnFailure, bool FreesMemOnFailure,
ProgramStateRef State) const; ProgramStateRef State) const;
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE, static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State); ProgramStateRef State);
///\brief Check if the memory associated with this symbol was released. ///\brief Check if the memory associated with this symbol was released.
bool isReleased(SymbolRef Sym, CheckerContext &C) const; bool isReleased(SymbolRef Sym, CheckerContext &C) const;
bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const; bool checkUseAfterFree(SymbolRef Sym, CheckerContext &C, const Stmt *S) const;
void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C, void checkUseZeroAllocated(SymbolRef Sym, CheckerContext &C,
const Stmt *S) const; const Stmt *S) const;
bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const; bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const;
@ -330,7 +330,7 @@ private:
/// Check if the function is known free memory, or if it is /// Check if the function is known free memory, or if it is
/// "interesting" and should be modeled explicitly. /// "interesting" and should be modeled explicitly.
/// ///
/// \param [out] EscapingSymbol A function might not free memory in general, /// \param [out] EscapingSymbol A function might not free memory in general,
/// but could be known to free a particular symbol. In this case, false is /// but could be known to free a particular symbol. In this case, false is
/// returned and the single escaping symbol is returned through the out /// returned and the single escaping symbol is returned through the out
/// parameter. /// parameter.
@ -357,20 +357,20 @@ private:
Optional<CheckKind> getCheckIfTracked(CheckerContext &C, Optional<CheckKind> getCheckIfTracked(CheckerContext &C,
const Stmt *AllocDeallocStmt, const Stmt *AllocDeallocStmt,
bool IsALeakCheck = false) const; bool IsALeakCheck = false) const;
Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym, Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
bool IsALeakCheck = false) const; bool IsALeakCheck = false) const;
///@} ///@}
static bool SummarizeValue(raw_ostream &os, SVal V); static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR); static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range, void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
const Expr *DeallocExpr) const; const Expr *DeallocExpr) const;
void ReportFreeAlloca(CheckerContext &C, SVal ArgVal, void ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
SourceRange Range) const; SourceRange Range) const;
void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range, void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range,
const Expr *DeallocExpr, const RefState *RS, const Expr *DeallocExpr, const RefState *RS,
SymbolRef Sym, bool OwnershipTransferred) const; SymbolRef Sym, bool OwnershipTransferred) const;
void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range, void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
const Expr *DeallocExpr, const Expr *DeallocExpr,
const Expr *AllocExpr = nullptr) const; const Expr *AllocExpr = nullptr) const;
void ReportUseAfterFree(CheckerContext &C, SourceRange Range, void ReportUseAfterFree(CheckerContext &C, SourceRange Range,
SymbolRef Sym) const; SymbolRef Sym) const;
@ -425,8 +425,8 @@ private:
const Stmt *Stmt) { const Stmt *Stmt) {
// Did not track -> allocated. Other state (released) -> allocated. // Did not track -> allocated. Other state (released) -> allocated.
return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) && return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
(S && (S->isAllocated() || S->isAllocatedOfSizeZero())) && (S && (S->isAllocated() || S->isAllocatedOfSizeZero())) &&
(!SPrev || !(SPrev->isAllocated() || (!SPrev || !(SPrev->isAllocated() ||
SPrev->isAllocatedOfSizeZero()))); SPrev->isAllocatedOfSizeZero())));
} }
@ -509,7 +509,7 @@ private:
REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState) REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair) REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair)
// A map from the freed symbol to the symbol representing the return value of // A map from the freed symbol to the symbol representing the return value of
// the free function. // the free function.
REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef) REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef)
@ -633,7 +633,7 @@ bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD,
return false; return false;
OverloadedOperatorKind Kind = FD->getOverloadedOperator(); OverloadedOperatorKind Kind = FD->getOverloadedOperator();
if (Kind != OO_New && Kind != OO_Array_New && if (Kind != OO_New && Kind != OO_Array_New &&
Kind != OO_Delete && Kind != OO_Array_Delete) Kind != OO_Delete && Kind != OO_Array_Delete)
return false; return false;
@ -798,8 +798,8 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
State = ProcessZeroAllocation(C, CE, 0, State); State = ProcessZeroAllocation(C, CE, 0, State);
} else if (isStandardNewDelete(FD, C.getASTContext())) { } else if (isStandardNewDelete(FD, C.getASTContext())) {
// Process direct calls to operator new/new[]/delete/delete[] functions // Process direct calls to operator new/new[]/delete/delete[] functions
// as distinct from new/new[]/delete/delete[] expressions that are // as distinct from new/new[]/delete/delete[] expressions that are
// processed by the checkPostStmt callbacks for CXXNewExpr and // processed by the checkPostStmt callbacks for CXXNewExpr and
// CXXDeleteExpr. // CXXDeleteExpr.
OverloadedOperatorKind K = FD->getOverloadedOperator(); OverloadedOperatorKind K = FD->getOverloadedOperator();
if (K == OO_New) { if (K == OO_New) {
@ -869,7 +869,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
assert(Arg); assert(Arg);
Optional<DefinedSVal> DefArgVal = Optional<DefinedSVal> DefArgVal =
State->getSVal(Arg, C.getLocationContext()).getAs<DefinedSVal>(); State->getSVal(Arg, C.getLocationContext()).getAs<DefinedSVal>();
if (!DefArgVal) if (!DefArgVal)
@ -881,7 +881,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
DefinedSVal Zero = DefinedSVal Zero =
SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>(); SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
std::tie(TrueState, FalseState) = std::tie(TrueState, FalseState) =
State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero)); State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
if (TrueState && !FalseState) { if (TrueState && !FalseState) {
@ -892,7 +892,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
const RefState *RS = State->get<RegionState>(Sym); const RefState *RS = State->get<RegionState>(Sym);
if (!RS) if (!RS)
return State; // TODO: change to assert(RS); after realloc() will return State; // TODO: change to assert(RS); after realloc() will
// guarantee have a RegionState attached. // guarantee have a RegionState attached.
if (!RS->isAllocated()) if (!RS->isAllocated())
@ -943,7 +943,7 @@ static bool treatUnusedNewEscaped(const CXXNewExpr *NE) {
return false; return false;
} }
void MallocChecker::checkPostStmt(const CXXNewExpr *NE, void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
CheckerContext &C) const { CheckerContext &C) const {
if (NE->getNumPlacementArgs()) if (NE->getNumPlacementArgs())
@ -960,17 +960,17 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
return; return;
ProgramStateRef State = C.getState(); ProgramStateRef State = C.getState();
// The return value from operator new is bound to a specified initialization // The return value from operator new is bound to a specified initialization
// value (if any) and we don't want to loose this value. So we call // value (if any) and we don't want to loose this value. So we call
// MallocUpdateRefState() instead of MallocMemAux() which breakes the // MallocUpdateRefState() instead of MallocMemAux() which breakes the
// existing binding. // existing binding.
State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
: AF_CXXNew); : AF_CXXNew);
State = ProcessZeroAllocation(C, NE, 0, State); State = ProcessZeroAllocation(C, NE, 0, State);
C.addTransition(State); C.addTransition(State);
} }
void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE, void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
CheckerContext &C) const { CheckerContext &C) const {
if (!ChecksEnabled[CK_NewDeleteChecker]) if (!ChecksEnabled[CK_NewDeleteChecker])
@ -1037,7 +1037,7 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
ProgramStateRef ProgramStateRef
MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE, MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr *Att, const OwnershipAttr *Att,
ProgramStateRef State) const { ProgramStateRef State) const {
if (!State) if (!State)
return nullptr; return nullptr;
@ -1104,7 +1104,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
State = State->assume(extentMatchesSize, true); State = State->assume(extentMatchesSize, true);
assert(State); assert(State);
} }
return MallocUpdateRefState(C, CE, State, Family); return MallocUpdateRefState(C, CE, State, Family);
} }
@ -1131,7 +1131,7 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C, ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
const CallExpr *CE, const CallExpr *CE,
const OwnershipAttr *Att, const OwnershipAttr *Att,
ProgramStateRef State) const { ProgramStateRef State) const {
if (!State) if (!State)
return nullptr; return nullptr;
@ -1183,7 +1183,7 @@ static bool didPreviousFreeFail(ProgramStateRef State,
return false; return false;
} }
AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C, AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
const Stmt *S) const { const Stmt *S) const {
if (!S) if (!S)
return AF_None; return AF_None;
@ -1228,14 +1228,14 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
return AF_None; return AF_None;
} }
bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C, bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
const Expr *E) const { const Expr *E) const {
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
// FIXME: This doesn't handle indirect calls. // FIXME: This doesn't handle indirect calls.
const FunctionDecl *FD = CE->getDirectCallee(); const FunctionDecl *FD = CE->getDirectCallee();
if (!FD) if (!FD)
return false; return false;
os << *FD; os << *FD;
if (!FD->isOverloadedOperator()) if (!FD->isOverloadedOperator())
os << "()"; os << "()";
@ -1252,14 +1252,14 @@ bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
} }
if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) { if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
os << "'" os << "'"
<< getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator()) << getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())
<< "'"; << "'";
return true; return true;
} }
if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) { if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {
os << "'" os << "'"
<< getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator()) << getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
<< "'"; << "'";
return true; return true;
@ -1282,7 +1282,7 @@ void MallocChecker::printExpectedAllocName(raw_ostream &os, CheckerContext &C,
} }
} }
void MallocChecker::printExpectedDeallocName(raw_ostream &os, void MallocChecker::printExpectedDeallocName(raw_ostream &os,
AllocationFamily Family) const { AllocationFamily Family) const {
switch(Family) { switch(Family) {
case AF_Malloc: os << "free()"; return; case AF_Malloc: os << "free()"; return;
@ -1326,25 +1326,25 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
return nullptr; return nullptr;
const MemRegion *R = ArgVal.getAsRegion(); const MemRegion *R = ArgVal.getAsRegion();
// Nonlocs can't be freed, of course. // Nonlocs can't be freed, of course.
// Non-region locations (labels and fixed addresses) also shouldn't be freed. // Non-region locations (labels and fixed addresses) also shouldn't be freed.
if (!R) { if (!R) {
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
return nullptr; return nullptr;
} }
R = R->StripCasts(); R = R->StripCasts();
// Blocks might show up as heap data, but should not be free()d // Blocks might show up as heap data, but should not be free()d
if (isa<BlockDataRegion>(R)) { if (isa<BlockDataRegion>(R)) {
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr); ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
return nullptr; return nullptr;
} }
const MemSpaceRegion *MS = R->getMemorySpace(); const MemSpaceRegion *MS = R->getMemorySpace();
// Parameters, locals, statics, globals, and memory returned by // Parameters, locals, statics, globals, and memory returned by
// __builtin_alloca() shouldn't be freed. // __builtin_alloca() shouldn't be freed.
if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) { if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) {
// FIXME: at the time this code was written, malloc() regions were // FIXME: at the time this code was written, malloc() regions were
@ -1390,7 +1390,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
// If the pointer is allocated or escaped, but we are now trying to free it, // If the pointer is allocated or escaped, but we are now trying to free it,
// check that the call to free is proper. // check that the call to free is proper.
} else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() || } else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
RsBase->isEscaped()) { RsBase->isEscaped()) {
// Check if an expected deallocation function matches the real one. // Check if an expected deallocation function matches the real one.
@ -1409,20 +1409,20 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
!Offset.hasSymbolicOffset() && !Offset.hasSymbolicOffset() &&
Offset.getOffset() != 0) { Offset.getOffset() != 0) {
const Expr *AllocExpr = cast<Expr>(RsBase->getStmt()); const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr, ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
AllocExpr); AllocExpr);
return nullptr; return nullptr;
} }
} }
} }
ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() || ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
RsBase->isAllocatedOfSizeZero()); RsBase->isAllocatedOfSizeZero());
// Clean out the info on previous call to free return info. // Clean out the info on previous call to free return info.
State = State->remove<FreeReturnValue>(SymBase); State = State->remove<FreeReturnValue>(SymBase);
// Keep track of the return value. If it is NULL, we will know that free // Keep track of the return value. If it is NULL, we will know that free
// failed. // failed.
if (ReturnsNullOnFailure) { if (ReturnsNullOnFailure) {
SVal RetVal = C.getSVal(ParentExpr); SVal RetVal = C.getSVal(ParentExpr);
@ -1462,7 +1462,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
if (IsALeakCheck) { if (IsALeakCheck) {
if (ChecksEnabled[CK_NewDeleteLeaksChecker]) if (ChecksEnabled[CK_NewDeleteLeaksChecker])
return CK_NewDeleteLeaksChecker; return CK_NewDeleteLeaksChecker;
} }
else { else {
if (ChecksEnabled[CK_NewDeleteChecker]) if (ChecksEnabled[CK_NewDeleteChecker])
return CK_NewDeleteChecker; return CK_NewDeleteChecker;
@ -1501,7 +1501,7 @@ bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
os << "the address of the label '" << Label->getLabel()->getName() << "'"; os << "the address of the label '" << Label->getLabel()->getName() << "'";
else else
return false; return false;
return true; return true;
} }
@ -1525,7 +1525,7 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
return true; return true;
default: { default: {
const MemSpaceRegion *MS = MR->getMemorySpace(); const MemSpaceRegion *MS = MR->getMemorySpace();
if (isa<StackLocalsSpaceRegion>(MS)) { if (isa<StackLocalsSpaceRegion>(MS)) {
const VarRegion *VR = dyn_cast<VarRegion>(MR); const VarRegion *VR = dyn_cast<VarRegion>(MR);
const VarDecl *VD; const VarDecl *VD;
@ -1579,8 +1579,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
} }
} }
void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
SourceRange Range, SourceRange Range,
const Expr *DeallocExpr) const { const Expr *DeallocExpr) const {
if (!ChecksEnabled[CK_MallocChecker] && if (!ChecksEnabled[CK_MallocChecker] &&
@ -1609,7 +1609,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
os << "deallocator"; os << "deallocator";
os << " is "; os << " is ";
bool Summarized = MR ? SummarizeRegion(os, MR) bool Summarized = MR ? SummarizeRegion(os, MR)
: SummarizeValue(os, ArgVal); : SummarizeValue(os, ArgVal);
if (Summarized) if (Summarized)
os << ", which is not memory allocated by "; os << ", which is not memory allocated by ";
@ -1625,7 +1625,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
} }
} }
void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal, void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
SourceRange Range) const { SourceRange Range) const {
Optional<MallocChecker::CheckKind> CheckKind; Optional<MallocChecker::CheckKind> CheckKind;
@ -1651,11 +1651,11 @@ void MallocChecker::ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
} }
} }
void MallocChecker::ReportMismatchedDealloc(CheckerContext &C, void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
SourceRange Range, SourceRange Range,
const Expr *DeallocExpr, const Expr *DeallocExpr,
const RefState *RS, const RefState *RS,
SymbolRef Sym, SymbolRef Sym,
bool OwnershipTransferred) const { bool OwnershipTransferred) const {
if (!ChecksEnabled[CK_MismatchedDeallocatorChecker]) if (!ChecksEnabled[CK_MismatchedDeallocatorChecker])
@ -1679,7 +1679,7 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
if (OwnershipTransferred) { if (OwnershipTransferred) {
if (printAllocDeallocName(DeallocOs, C, DeallocExpr)) if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
os << DeallocOs.str() << " cannot"; os << DeallocOs.str() << " cannot";
else else
os << "Cannot"; os << "Cannot";
os << " take ownership of memory"; os << " take ownership of memory";
@ -1790,7 +1790,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
} }
void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range, void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
bool Released, SymbolRef Sym, bool Released, SymbolRef Sym,
SymbolRef PrevSym) const { SymbolRef PrevSym) const {
if (!ChecksEnabled[CK_MallocChecker] && if (!ChecksEnabled[CK_MallocChecker] &&
@ -1920,7 +1920,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull; bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero; bool SizeIsZero = StateSizeIsZero && !StateSizeNotZero;
// If the ptr is NULL and the size is not 0, the call is equivalent to // If the ptr is NULL and the size is not 0, the call is equivalent to
// malloc(size). // malloc(size).
if ( PrtIsNull && !SizeIsZero) { if ( PrtIsNull && !SizeIsZero) {
ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1), ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
@ -1978,7 +1978,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
return nullptr; return nullptr;
} }
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE, ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
ProgramStateRef State) { ProgramStateRef State) {
if (!State) if (!State)
return nullptr; return nullptr;
@ -1991,7 +1991,7 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
SVal count = State->getSVal(CE->getArg(0), LCtx); SVal count = State->getSVal(CE->getArg(0), LCtx);
SVal elementSize = State->getSVal(CE->getArg(1), LCtx); SVal elementSize = State->getSVal(CE->getArg(1), LCtx);
SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize, SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize,
svalBuilder.getContext().getSizeType()); svalBuilder.getContext().getSizeType());
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy); SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
return MallocMemAux(C, CE, TotalSize, zeroVal, State); return MallocMemAux(C, CE, TotalSize, zeroVal, State);
@ -2078,7 +2078,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
const ExplodedNode *AllocNode = nullptr; const ExplodedNode *AllocNode = nullptr;
const MemRegion *Region = nullptr; const MemRegion *Region = nullptr;
std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C); std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
ProgramPoint P = AllocNode->getLocation(); ProgramPoint P = AllocNode->getLocation();
const Stmt *AllocationStmt = nullptr; const Stmt *AllocationStmt = nullptr;
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>()) if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
@ -2127,7 +2127,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
} }
} }
// Cleanup the Realloc Pairs Map. // Cleanup the Realloc Pairs Map.
ReallocPairsTy RP = state->get<ReallocPairs>(); ReallocPairsTy RP = state->get<ReallocPairs>();
for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) { for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) {
@ -2232,7 +2232,7 @@ void MallocChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const {
} }
// TODO: Blocks should be either inlined or should call invalidate regions // TODO: Blocks should be either inlined or should call invalidate regions
// upon invocation. After that's in place, special casing here will not be // upon invocation. After that's in place, special casing here will not be
// needed. // needed.
void MallocChecker::checkPostStmt(const BlockExpr *BE, void MallocChecker::checkPostStmt(const BlockExpr *BE,
CheckerContext &C) const { CheckerContext &C) const {
@ -2446,7 +2446,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
StringRef FName = II->getName(); StringRef FName = II->getName();
// White list the 'XXXNoCopy' CoreFoundation functions. // White list the 'XXXNoCopy' CoreFoundation functions.
// We specifically check these before // We specifically check these before
if (FName.endswith("NoCopy")) { if (FName.endswith("NoCopy")) {
// Look for the deallocator argument. We know that the memory ownership // Look for the deallocator argument. We know that the memory ownership
// is not transferred only if the deallocator argument is // is not transferred only if the deallocator argument is
@ -2555,7 +2555,7 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
if (EscapingSymbol && EscapingSymbol != sym) if (EscapingSymbol && EscapingSymbol != sym)
continue; continue;
if (const RefState *RS = State->get<RegionState>(sym)) { if (const RefState *RS = State->get<RegionState>(sym)) {
if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) && if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) &&
CheckRefState(RS)) { CheckRefState(RS)) {
@ -2702,7 +2702,7 @@ void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true; checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] = checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
mgr.getCurrentCheckName(); mgr.getCurrentCheckName();
// We currently treat NewDeleteLeaks checker as a subchecker of NewDelete // We currently treat NewDeleteLeaks checker as a subchecker of NewDelete
// checker. // checker.
if (!checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker]) if (!checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker])
checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker] = true; checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker] = true;

View File

@ -33,7 +33,7 @@ struct MallocOverflowCheck {
const BinaryOperator *mulop; const BinaryOperator *mulop;
const Expr *variable; const Expr *variable;
MallocOverflowCheck (const BinaryOperator *m, const Expr *v) MallocOverflowCheck (const BinaryOperator *m, const Expr *v)
: mulop(m), variable (v) : mulop(m), variable (v)
{} {}
}; };

View File

@ -143,20 +143,20 @@ static bool typesCompatible(ASTContext &C, QualType A, QualType B) {
while (true) { while (true) {
A = A.getCanonicalType(); A = A.getCanonicalType();
B = B.getCanonicalType(); B = B.getCanonicalType();
if (A.getTypePtr() == B.getTypePtr()) if (A.getTypePtr() == B.getTypePtr())
return true; return true;
if (const PointerType *ptrA = A->getAs<PointerType>()) if (const PointerType *ptrA = A->getAs<PointerType>())
if (const PointerType *ptrB = B->getAs<PointerType>()) { if (const PointerType *ptrB = B->getAs<PointerType>()) {
A = ptrA->getPointeeType(); A = ptrA->getPointeeType();
B = ptrB->getPointeeType(); B = ptrB->getPointeeType();
continue; continue;
} }
break; break;
} }
return false; return false;
} }

View File

@ -11,7 +11,7 @@
// about subpar uses of NSAutoreleasePool. Note that while the check itself // about subpar uses of NSAutoreleasePool. Note that while the check itself
// (in its current form) could be written as a flow-insensitive check, in // (in its current form) could be written as a flow-insensitive check, in
// can be potentially enhanced in the future with flow-sensitive information. // can be potentially enhanced in the future with flow-sensitive information.
// It is also a good example of the CheckerVisitor interface. // It is also a good example of the CheckerVisitor interface.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -48,7 +48,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
const ObjCInterfaceDecl *OD = msg.getReceiverInterface(); const ObjCInterfaceDecl *OD = msg.getReceiverInterface();
if (!OD) if (!OD)
return; return;
if (!OD->getIdentifier()->isStr("NSAutoreleasePool")) if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
return; return;

View File

@ -58,7 +58,7 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
return; return;
if (!II) if (!II)
II = &D->getASTContext().Idents.get("NSError"); II = &D->getASTContext().Idents.get("NSError");
bool hasNSError = false; bool hasNSError = false;
for (const auto *I : D->params()) { for (const auto *I : D->params()) {
@ -105,7 +105,7 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
return; return;
if (!II) if (!II)
II = &D->getASTContext().Idents.get("CFErrorRef"); II = &D->getASTContext().Idents.get("CFErrorRef");
bool hasCFError = false; bool hasCFError = false;
for (auto I : D->params()) { for (auto I : D->params()) {

View File

@ -133,7 +133,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
if (IdxVal.isUnknownOrUndef()) if (IdxVal.isUnknownOrUndef())
return; return;
DefinedSVal Idx = IdxVal.castAs<DefinedSVal>(); DefinedSVal Idx = IdxVal.castAs<DefinedSVal>();
// Now, check if 'Idx in [0, Size-1]'. // Now, check if 'Idx in [0, Size-1]'.
const QualType T = IdxExpr->getType(); const QualType T = IdxExpr->getType();
ProgramStateRef StInBound = State->assumeInBound(Idx, *Size, true, T); ProgramStateRef StInBound = State->assumeInBound(Idx, *Size, true, T);

View File

@ -49,7 +49,7 @@ public:
DoesCallSuper = true; DoesCallSuper = true;
// Recurse if we didn't find the super call yet. // Recurse if we didn't find the super call yet.
return !DoesCallSuper; return !DoesCallSuper;
} }
bool DoesCallSuper; bool DoesCallSuper;
@ -59,7 +59,7 @@ private:
}; };
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// ObjCSuperCallChecker // ObjCSuperCallChecker
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
class ObjCSuperCallChecker : public Checker< class ObjCSuperCallChecker : public Checker<
@ -202,7 +202,7 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
SmallString<320> Buf; SmallString<320> Buf;
llvm::raw_svector_ostream os(Buf); llvm::raw_svector_ostream os(Buf);
os << "The '" << S.getAsString() os << "The '" << S.getAsString()
<< "' instance method in " << SuperclassName.str() << " subclass '" << "' instance method in " << SuperclassName.str() << " subclass '"
<< *D << "' is missing a [super " << S.getAsString() << "] call"; << *D << "' is missing a [super " << S.getAsString() << "] call";

View File

@ -145,13 +145,13 @@ void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,
const char *errorStr) const { const char *errorStr) const {
if (!E) if (!E)
return; return;
if (!C.getState()->get<CalledInit>()) if (!C.getState()->get<CalledInit>())
return; return;
if (!isInvalidSelf(E, C)) if (!isInvalidSelf(E, C))
return; return;
// Generate an error node. // Generate an error node.
ExplodedNode *N = C.generateSink(); ExplodedNode *N = C.generateSink();
if (!N) if (!N)
@ -177,12 +177,12 @@ void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
if (isInitMessage(Msg)) { if (isInitMessage(Msg)) {
// Tag the return value as the result of an initializer. // Tag the return value as the result of an initializer.
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
// FIXME this really should be context sensitive, where we record // FIXME this really should be context sensitive, where we record
// the current stack frame (for IPA). Also, we need to clean this // the current stack frame (for IPA). Also, we need to clean this
// value out when we return from this method. // value out when we return from this method.
state = state->set<CalledInit>(true); state = state->set<CalledInit>(true);
SVal V = state->getSVal(Msg.getOriginExpr(), C.getLocationContext()); SVal V = state->getSVal(Msg.getOriginExpr(), C.getLocationContext());
addSelfFlag(state, V, SelfFlag_InitRes, C); addSelfFlag(state, V, SelfFlag_InitRes, C);
return; return;
@ -318,7 +318,7 @@ void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S,
CheckerContext &C) const { CheckerContext &C) const {
// Allow assignment of anything to self. Self is a local variable in the // Allow assignment of anything to self. Self is a local variable in the
// initializer, so it is legal to assign anything to it, like results of // initializer, so it is legal to assign anything to it, like results of
// static functions/method calls. After self is assigned something we cannot // static functions/method calls. After self is assigned something we cannot
// reason about, stop enforcing the rules. // reason about, stop enforcing the rules.
// (Only continue checking if the assigned value should be treated as self.) // (Only continue checking if the assigned value should be treated as self.)
if ((isSelfVar(loc, C)) && if ((isSelfVar(loc, C)) &&
@ -412,7 +412,7 @@ static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
/// \brief Returns true if the location is 'self'. /// \brief Returns true if the location is 'self'.
static bool isSelfVar(SVal location, CheckerContext &C) { static bool isSelfVar(SVal location, CheckerContext &C) {
AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext(); AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext();
if (!analCtx->getSelfDecl()) if (!analCtx->getSelfDecl())
return false; return false;
if (!location.getAs<loc::MemRegionVal>()) if (!location.getAs<loc::MemRegionVal>())

View File

@ -22,7 +22,7 @@ using namespace clang;
using namespace ento; using namespace ento;
namespace { namespace {
class PointerArithChecker class PointerArithChecker
: public Checker< check::PreStmt<BinaryOperator> > { : public Checker< check::PreStmt<BinaryOperator> > {
mutable std::unique_ptr<BuiltinBug> BT; mutable std::unique_ptr<BuiltinBug> BT;
@ -48,7 +48,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B,
// If pointer arithmetic is done on variables of non-array type, this often // If pointer arithmetic is done on variables of non-array type, this often
// means behavior rely on memory organization, which is dangerous. // means behavior rely on memory organization, which is dangerous.
if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) || if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
isa<CompoundLiteralRegion>(LR)) { isa<CompoundLiteralRegion>(LR)) {
if (ExplodedNode *N = C.addTransition()) { if (ExplodedNode *N = C.addTransition()) {

View File

@ -8,7 +8,7 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This files defines PointerSubChecker, a builtin checker that checks for // This files defines PointerSubChecker, a builtin checker that checks for
// pointer subtractions on two pointers pointing to different memory chunks. // pointer subtractions on two pointers pointing to different memory chunks.
// This check corresponds to CWE-469. // This check corresponds to CWE-469.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -23,7 +23,7 @@ using namespace clang;
using namespace ento; using namespace ento;
namespace { namespace {
class PointerSubChecker class PointerSubChecker
: public Checker< check::PreStmt<BinaryOperator> > { : public Checker< check::PreStmt<BinaryOperator> > {
mutable std::unique_ptr<BuiltinBug> BT; mutable std::unique_ptr<BuiltinBug> BT;

View File

@ -62,10 +62,10 @@ class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
}; };
public: public:
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock, void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock,
bool isTryLock, enum LockingSemantics semantics) const; bool isTryLock, enum LockingSemantics semantics) const;
void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const; void ReleaseLock(CheckerContext &C, const CallExpr *CE, SVal lock) const;
void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const; void DestroyLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const; void InitLock(CheckerContext &C, const CallExpr *CE, SVal Lock) const;
@ -96,7 +96,7 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
false, PthreadSemantics); false, PthreadSemantics);
else if (FName == "lck_mtx_lock" || else if (FName == "lck_mtx_lock" ||
FName == "lck_rw_lock_exclusive" || FName == "lck_rw_lock_exclusive" ||
FName == "lck_rw_lock_shared") FName == "lck_rw_lock_shared")
AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx), AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
false, XNUSemantics); false, XNUSemantics);
else if (FName == "pthread_mutex_trylock" || else if (FName == "pthread_mutex_trylock" ||
@ -124,17 +124,17 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
SVal lock, bool isTryLock, SVal lock, bool isTryLock,
enum LockingSemantics semantics) const { enum LockingSemantics semantics) const {
const MemRegion *lockR = lock.getAsRegion(); const MemRegion *lockR = lock.getAsRegion();
if (!lockR) if (!lockR)
return; return;
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
SVal X = state->getSVal(CE, C.getLocationContext()); SVal X = state->getSVal(CE, C.getLocationContext());
if (X.isUnknownOrUndef()) if (X.isUnknownOrUndef())
return; return;
DefinedSVal retVal = X.castAs<DefinedSVal>(); DefinedSVal retVal = X.castAs<DefinedSVal>();
if (const LockState *LState = state->get<LockMap>(lockR)) { if (const LockState *LState = state->get<LockMap>(lockR)) {
@ -183,8 +183,8 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
assert((semantics == XNUSemantics) && "Unknown locking semantics"); assert((semantics == XNUSemantics) && "Unknown locking semantics");
lockSucc = state; lockSucc = state;
} }
// Record that the lock was acquired. // Record that the lock was acquired.
lockSucc = lockSucc->add<LockSet>(lockR); lockSucc = lockSucc->add<LockSet>(lockR);
lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked()); lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked());
C.addTransition(lockSucc); C.addTransition(lockSucc);
@ -196,7 +196,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
const MemRegion *lockR = lock.getAsRegion(); const MemRegion *lockR = lock.getAsRegion();
if (!lockR) if (!lockR)
return; return;
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
if (const LockState *LState = state->get<LockMap>(lockR)) { if (const LockState *LState = state->get<LockMap>(lockR)) {

View File

@ -250,7 +250,7 @@ public:
bool operator==(const RefVal& X) const { bool operator==(const RefVal& X) const {
return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind(); return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind();
} }
void Profile(llvm::FoldingSetNodeID& ID) const { void Profile(llvm::FoldingSetNodeID& ID) const {
ID.Add(T); ID.Add(T);
ID.AddInteger(RawKind); ID.AddInteger(RawKind);
@ -426,16 +426,16 @@ public:
/// setRetEffect - Set the effect of the return value of the call. /// setRetEffect - Set the effect of the return value of the call.
void setRetEffect(RetEffect E) { Ret = E; } void setRetEffect(RetEffect E) { Ret = E; }
/// Sets the effect on the receiver of the message. /// Sets the effect on the receiver of the message.
void setReceiverEffect(ArgEffect e) { Receiver = e; } void setReceiverEffect(ArgEffect e) { Receiver = e; }
/// getReceiverEffect - Returns the effect on the receiver of the call. /// getReceiverEffect - Returns the effect on the receiver of the call.
/// This is only meaningful if the summary applies to an ObjCMessageExpr*. /// This is only meaningful if the summary applies to an ObjCMessageExpr*.
ArgEffect getReceiverEffect() const { return Receiver; } ArgEffect getReceiverEffect() const { return Receiver; }
/// Test if two retain summaries are identical. Note that merely equivalent /// Test if two retain summaries are identical. Note that merely equivalent
/// summaries are not necessarily identical (for example, if an explicit /// summaries are not necessarily identical (for example, if an explicit
/// argument effect matches the default effect). /// argument effect matches the default effect).
bool operator==(const RetainSummary &Other) const { bool operator==(const RetainSummary &Other) const {
return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect && return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect &&
@ -621,7 +621,7 @@ class RetainSummaryManager {
ArgEffects::Factory AF; ArgEffects::Factory AF;
/// ScratchArgs - A holding buffer for construct ArgEffects. /// ScratchArgs - A holding buffer for construct ArgEffects.
ArgEffects ScratchArgs; ArgEffects ScratchArgs;
/// ObjCAllocRetE - Default return effect for methods returning Objective-C /// ObjCAllocRetE - Default return effect for methods returning Objective-C
/// objects. /// objects.
@ -644,7 +644,7 @@ class RetainSummaryManager {
ArgEffects getArgEffects(); ArgEffects getArgEffects();
enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable }; enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable };
const RetainSummary *getUnarySummary(const FunctionType* FT, const RetainSummary *getUnarySummary(const FunctionType* FT,
UnaryFuncKind func); UnaryFuncKind func);
@ -664,7 +664,7 @@ class RetainSummaryManager {
const RetainSummary *getDoNothingSummary() { const RetainSummary *getDoNothingSummary() {
return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
} }
const RetainSummary *getDefaultSummary() { const RetainSummary *getDefaultSummary() {
return getPersistentSummary(RetEffect::MakeNoRet(), return getPersistentSummary(RetEffect::MakeNoRet(),
DoNothing, MayEscape); DoNothing, MayEscape);
@ -689,7 +689,7 @@ private:
void addClassMethSummary(const char* Cls, const char* name, void addClassMethSummary(const char* Cls, const char* name,
const RetainSummary *Summ, bool isNullary = true) { const RetainSummary *Summ, bool isNullary = true) {
IdentifierInfo* ClsII = &Ctx.Idents.get(Cls); IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
Selector S = isNullary ? GetNullarySelector(name, Ctx) Selector S = isNullary ? GetNullarySelector(name, Ctx)
: GetUnarySelector(name, Ctx); : GetUnarySelector(name, Ctx);
ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ; ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
} }
@ -739,7 +739,7 @@ public:
? RetEffect::MakeGCNotOwned() ? RetEffect::MakeGCNotOwned()
: (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
: RetEffect::MakeOwned(RetEffect::ObjC, true))), : RetEffect::MakeOwned(RetEffect::ObjC, true))),
ObjCInitRetE(gcenabled ObjCInitRetE(gcenabled
? RetEffect::MakeGCNotOwned() ? RetEffect::MakeGCNotOwned()
: (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC) : (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
: RetEffect::MakeOwnedWhenTrackedReceiver())) { : RetEffect::MakeOwnedWhenTrackedReceiver())) {
@ -803,7 +803,7 @@ public:
bool isGCEnabled() const { return GCEnabled; } bool isGCEnabled() const { return GCEnabled; }
bool isARCEnabled() const { return ARCEnabled; } bool isARCEnabled() const { return ARCEnabled; }
bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; } bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; } RetEffect getObjAllocRetEffect() const { return ObjCAllocRetE; }
@ -966,7 +966,7 @@ void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S,
// Additionally, our Self Init checker already warns about it. To avoid // Additionally, our Self Init checker already warns about it. To avoid
// overwhelming the user with messages from both checkers, we model the case // overwhelming the user with messages from both checkers, we model the case
// of '[super init]' in cases when it is not consumed by another expression // of '[super init]' in cases when it is not consumed by another expression
// as if the call preserves the value of 'self'; essentially, assuming it can // as if the call preserves the value of 'self'; essentially, assuming it can
// never fail and return 'nil'. // never fail and return 'nil'.
// Note, we don't want to just stop tracking the value since we want the // Note, we don't want to just stop tracking the value since we want the
// RetainCount checker to report leaks and use-after-free if SelfInit checker // RetainCount checker to report leaks and use-after-free if SelfInit checker
@ -1150,7 +1150,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
if (S) if (S)
break; break;
if (RetTy->isPointerType()) { if (RetTy->isPointerType()) {
// For CoreFoundation ('CF') types. // For CoreFoundation ('CF') types.
if (cocoa::isRefType(RetTy, "CF", FName)) { if (cocoa::isRefType(RetTy, "CF", FName)) {
if (isRetain(FD, FName)) { if (isRetain(FD, FName)) {
@ -1278,14 +1278,14 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing); return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
} }
const RetainSummary * const RetainSummary *
RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) { RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
assert (ScratchArgs.isEmpty()); assert (ScratchArgs.isEmpty());
return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true)); return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
} }
const RetainSummary * const RetainSummary *
RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) { RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
assert (ScratchArgs.isEmpty()); assert (ScratchArgs.isEmpty());
return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF), return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF),
@ -1331,7 +1331,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
// Effects on the parameters. // Effects on the parameters.
unsigned parm_idx = 0; unsigned parm_idx = 0;
for (FunctionDecl::param_const_iterator pi = FD->param_begin(), for (FunctionDecl::param_const_iterator pi = FD->param_begin(),
pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) { pe = FD->param_end(); pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi; const ParmVarDecl *pd = *pi;
if (pd->hasAttr<NSConsumedAttr>()) if (pd->hasAttr<NSConsumedAttr>())
@ -1367,8 +1367,8 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
// Effects on the receiver. // Effects on the receiver.
if (MD->hasAttr<NSConsumesSelfAttr>()) if (MD->hasAttr<NSConsumesSelfAttr>())
Template->setReceiverEffect(DecRefMsg); Template->setReceiverEffect(DecRefMsg);
// Effects on the parameters. // Effects on the parameters.
unsigned parm_idx = 0; unsigned parm_idx = 0;
for (ObjCMethodDecl::param_const_iterator for (ObjCMethodDecl::param_const_iterator
@ -1376,9 +1376,9 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
pi != pe; ++pi, ++parm_idx) { pi != pe; ++pi, ++parm_idx) {
const ParmVarDecl *pd = *pi; const ParmVarDecl *pd = *pi;
if (pd->hasAttr<NSConsumedAttr>()) if (pd->hasAttr<NSConsumedAttr>())
Template->addArg(AF, parm_idx, DecRefMsg); Template->addArg(AF, parm_idx, DecRefMsg);
else if (pd->hasAttr<CFConsumedAttr>()) { else if (pd->hasAttr<CFConsumedAttr>()) {
Template->addArg(AF, parm_idx, DecRef); Template->addArg(AF, parm_idx, DecRef);
} else if (pd->hasAttr<CFReturnsRetainedAttr>()) { } else if (pd->hasAttr<CFReturnsRetainedAttr>()) {
QualType PointeeTy = pd->getType()->getPointeeType(); QualType PointeeTy = pd->getType()->getPointeeType();
if (!PointeeTy.isNull()) if (!PointeeTy.isNull())
@ -1415,7 +1415,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
if (cocoa::isCocoaObjectRef(RetTy)) if (cocoa::isCocoaObjectRef(RetTy))
ResultEff = RetEffect::MakeNotOwned(RetEffect::ObjC); ResultEff = RetEffect::MakeNotOwned(RetEffect::ObjC);
else if (coreFoundation::isCFObjectRef(RetTy)) { else if (coreFoundation::isCFObjectRef(RetTy)) {
// ObjCMethodDecl currently doesn't consider CF objects as valid return // ObjCMethodDecl currently doesn't consider CF objects as valid return
// values for alloc, new, copy, or mutableCopy, so we have to // values for alloc, new, copy, or mutableCopy, so we have to
// double-check with the selector. This is ugly, but there aren't that // double-check with the selector. This is ugly, but there aren't that
// many Objective-C methods that return CF objects, right? // many Objective-C methods that return CF objects, right?
@ -1428,11 +1428,11 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
ResultEff = RetEffect::MakeOwned(RetEffect::CF, true); ResultEff = RetEffect::MakeOwned(RetEffect::CF, true);
break; break;
default: default:
ResultEff = RetEffect::MakeNotOwned(RetEffect::CF); ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
break; break;
} }
} else { } else {
ResultEff = RetEffect::MakeNotOwned(RetEffect::CF); ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
} }
} }
break; break;
@ -1749,7 +1749,7 @@ namespace {
SymbolRef Sym; SymbolRef Sym;
const SummaryLogTy &SummaryLog; const SummaryLogTy &SummaryLog;
bool GCEnabled; bool GCEnabled;
public: public:
CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log) CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log)
: Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {} : Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {}
@ -1869,7 +1869,7 @@ void CFRefReport::addGCModeDescription(const LangOptions &LOpts,
static bool isNumericLiteralExpression(const Expr *E) { static bool isNumericLiteralExpression(const Expr *E) {
// FIXME: This set of cases was copied from SemaExprObjC. // FIXME: This set of cases was copied from SemaExprObjC.
return isa<IntegerLiteral>(E) || return isa<IntegerLiteral>(E) ||
isa<CharacterLiteral>(E) || isa<CharacterLiteral>(E) ||
isa<FloatingLiteral>(E) || isa<FloatingLiteral>(E) ||
isa<ObjCBoolLiteralExpr>(E) || isa<ObjCBoolLiteralExpr>(E) ||
@ -1948,7 +1948,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
else if (isa<ObjCIvarRefExpr>(S)) { else if (isa<ObjCIvarRefExpr>(S)) {
os << "Object loaded from instance variable"; os << "Object loaded from instance variable";
} }
else { else {
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
// Get the name of the callee (if it is available). // Get the name of the callee (if it is available).
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx); SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
@ -2228,7 +2228,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
StoreManager::FindUniqueBinding FB(Sym); StoreManager::FindUniqueBinding FB(Sym);
StateMgr.iterBindings(St, FB); StateMgr.iterBindings(St, FB);
if (FB) { if (FB) {
const MemRegion *R = FB.getRegion(); const MemRegion *R = FB.getRegion();
const VarRegion *VR = R->getBaseRegion()->getAs<VarRegion>(); const VarRegion *VR = R->getBaseRegion()->getAs<VarRegion>();
@ -2345,10 +2345,10 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
// objects. Only "copy", "alloc", "retain" and "new" transfer ownership // objects. Only "copy", "alloc", "retain" and "new" transfer ownership
// to the caller for NS objects. // to the caller for NS objects.
const Decl *D = &EndN->getCodeDecl(); const Decl *D = &EndN->getCodeDecl();
os << (isa<ObjCMethodDecl>(D) ? " is returned from a method " os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
: " is returned from a function "); : " is returned from a function ");
if (D->hasAttr<CFReturnsNotRetainedAttr>()) if (D->hasAttr<CFReturnsNotRetainedAttr>())
os << "that is annotated as CF_RETURNS_NOT_RETAINED"; os << "that is annotated as CF_RETURNS_NOT_RETAINED";
else if (D->hasAttr<NSReturnsNotRetainedAttr>()) else if (D->hasAttr<NSReturnsNotRetainedAttr>())
@ -2385,7 +2385,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
} }
CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts, CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
bool GCEnabled, const SummaryLogTy &Log, bool GCEnabled, const SummaryLogTy &Log,
ExplodedNode *n, SymbolRef sym, ExplodedNode *n, SymbolRef sym,
CheckerContext &Ctx, CheckerContext &Ctx,
bool IncludeAllocationLine) bool IncludeAllocationLine)
@ -2492,7 +2492,7 @@ class RetainCountChecker
/// the allocation line. /// the allocation line.
mutable bool IncludeAllocationLine; mutable bool IncludeAllocationLine;
public: public:
RetainCountChecker(AnalyzerOptions &AO) RetainCountChecker(AnalyzerOptions &AO)
: ShouldResetSummaryLog(false), : ShouldResetSummaryLog(false),
IncludeAllocationLine(shouldIncludeAllocationSiteInLeakDiagnostics(AO)) {} IncludeAllocationLine(shouldIncludeAllocationSiteInLeakDiagnostics(AO)) {}
@ -2617,7 +2617,7 @@ public:
void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const; void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
void checkSummary(const RetainSummary &Summ, const CallEvent &Call, void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
CheckerContext &C) const; CheckerContext &C) const;
@ -2630,13 +2630,13 @@ public:
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
bool Assumption) const; bool Assumption) const;
ProgramStateRef ProgramStateRef
checkRegionChanges(ProgramStateRef state, checkRegionChanges(ProgramStateRef state,
const InvalidatedSymbols *invalidated, const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions, ArrayRef<const MemRegion *> Regions,
const CallEvent *Call) const; const CallEvent *Call) const;
bool wantsRegionChangeUpdate(ProgramStateRef state) const { bool wantsRegionChangeUpdate(ProgramStateRef state) const {
return true; return true;
} }
@ -2645,7 +2645,7 @@ public:
void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C, void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C,
ExplodedNode *Pred, RetEffect RE, RefVal X, ExplodedNode *Pred, RetEffect RE, RefVal X,
SymbolRef Sym, ProgramStateRef state) const; SymbolRef Sym, ProgramStateRef state) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
void checkEndFunction(CheckerContext &C) const; void checkEndFunction(CheckerContext &C) const;
@ -2656,7 +2656,7 @@ public:
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange, void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
RefVal::Kind ErrorKind, SymbolRef Sym, RefVal::Kind ErrorKind, SymbolRef Sym,
CheckerContext &C) const; CheckerContext &C) const;
void processObjCLiterals(CheckerContext &C, const Expr *Ex) const; void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const; const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const;
@ -2740,21 +2740,21 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE); const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
if (!BE) if (!BE)
return; return;
ArgEffect AE = IncRef; ArgEffect AE = IncRef;
switch (BE->getBridgeKind()) { switch (BE->getBridgeKind()) {
case clang::OBC_Bridge: case clang::OBC_Bridge:
// Do nothing. // Do nothing.
return; return;
case clang::OBC_BridgeRetained: case clang::OBC_BridgeRetained:
AE = IncRef; AE = IncRef;
break; break;
case clang::OBC_BridgeTransfer: case clang::OBC_BridgeTransfer:
AE = DecRefBridgedTransferred; AE = DecRefBridgedTransferred;
break; break;
} }
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
SymbolRef Sym = state->getSVal(CE, C.getLocationContext()).getAsLocSymbol(); SymbolRef Sym = state->getSVal(CE, C.getLocationContext()).getAsLocSymbol();
if (!Sym) if (!Sym)
@ -2765,7 +2765,7 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
RefVal::Kind hasErr = (RefVal::Kind) 0; RefVal::Kind hasErr = (RefVal::Kind) 0;
state = updateSymbol(state, Sym, *T, AE, hasErr, C); state = updateSymbol(state, Sym, *T, AE, hasErr, C);
if (hasErr) { if (hasErr) {
// FIXME: If we get an error during a bridge cast, should we report it? // FIXME: If we get an error during a bridge cast, should we report it?
return; return;
@ -2777,7 +2777,7 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
void RetainCountChecker::processObjCLiterals(CheckerContext &C, void RetainCountChecker::processObjCLiterals(CheckerContext &C,
const Expr *Ex) const { const Expr *Ex) const {
ProgramStateRef state = C.getState(); ProgramStateRef state = C.getState();
const ExplodedNode *pred = C.getPredecessor(); const ExplodedNode *pred = C.getPredecessor();
for (const Stmt *Child : Ex->children()) { for (const Stmt *Child : Ex->children()) {
SVal V = state->getSVal(Child, pred->getLocationContext()); SVal V = state->getSVal(Child, pred->getLocationContext());
if (SymbolRef sym = V.getAsSymbol()) if (SymbolRef sym = V.getAsSymbol())
@ -2790,17 +2790,17 @@ void RetainCountChecker::processObjCLiterals(CheckerContext &C,
} }
} }
} }
// Return the object as autoreleased. // Return the object as autoreleased.
// RetEffect RE = RetEffect::MakeNotOwned(RetEffect::ObjC); // RetEffect RE = RetEffect::MakeNotOwned(RetEffect::ObjC);
if (SymbolRef sym = if (SymbolRef sym =
state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) { state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
QualType ResultTy = Ex->getType(); QualType ResultTy = Ex->getType();
state = setRefBinding(state, sym, state = setRefBinding(state, sym,
RefVal::makeNotOwned(RetEffect::ObjC, ResultTy)); RefVal::makeNotOwned(RetEffect::ObjC, ResultTy));
} }
C.addTransition(state); C.addTransition(state);
} }
void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL, void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
@ -2817,7 +2817,7 @@ void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex, void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
CheckerContext &C) const { CheckerContext &C) const {
const ExplodedNode *Pred = C.getPredecessor(); const ExplodedNode *Pred = C.getPredecessor();
const LocationContext *LCtx = Pred->getLocationContext(); const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState(); ProgramStateRef State = Pred->getState();
@ -2966,7 +2966,7 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
if (Sym) if (Sym)
state = removeRefBinding(state, Sym); state = removeRefBinding(state, Sym);
} }
C.addTransition(state); C.addTransition(state);
} }
@ -3062,7 +3062,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) { if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
if (ReceiverIsTracked) if (ReceiverIsTracked)
RE = getSummaryManager(C).getObjAllocRetEffect(); RE = getSummaryManager(C).getObjAllocRetEffect();
else else
RE = RetEffect::MakeNoRet(); RE = RetEffect::MakeNoRet();
} }
@ -3130,7 +3130,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
} }
ProgramStateRef ProgramStateRef
RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
RefVal V, ArgEffect E, RefVal::Kind &hasErr, RefVal V, ArgEffect E, RefVal::Kind &hasErr,
CheckerContext &C) const { CheckerContext &C) const {
@ -3388,7 +3388,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
isMakeCollectable(FD, FName); isMakeCollectable(FD, FName);
} }
} }
if (!canEval) if (!canEval)
return false; return false;
@ -3700,7 +3700,7 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
return state; return state;
} }
ProgramStateRef ProgramStateRef
RetainCountChecker::checkRegionChanges(ProgramStateRef state, RetainCountChecker::checkRegionChanges(ProgramStateRef state,
const InvalidatedSymbols *invalidated, const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> ExplicitRegions,
@ -3810,7 +3810,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
return nullptr; return nullptr;
} }
ProgramStateRef ProgramStateRef
RetainCountChecker::handleSymbolDeath(ProgramStateRef state, RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
SymbolRef sid, RefVal V, SymbolRef sid, RefVal V,
SmallVectorImpl<SymbolRef> &Leaked) const { SmallVectorImpl<SymbolRef> &Leaked) const {
@ -3890,7 +3890,7 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
// and suggest annotations. // and suggest annotations.
if (LCtx->getParent()) if (LCtx->getParent())
return; return;
B = state->get<RefBindings>(); B = state->get<RefBindings>();
SmallVector<SymbolRef, 10> Leaked; SmallVector<SymbolRef, 10> Leaked;
@ -3910,7 +3910,7 @@ RetainCountChecker::getDeadSymbolTag(SymbolRef sym) const {
sym->dumpToStream(out); sym->dumpToStream(out);
tag = new CheckerProgramPointTag(this, out.str()); tag = new CheckerProgramPointTag(this, out.str());
} }
return tag; return tag;
} }
void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,

View File

@ -23,7 +23,7 @@ using namespace clang;
using namespace ento; using namespace ento;
namespace { namespace {
class ReturnPointerRangeChecker : class ReturnPointerRangeChecker :
public Checker< check::PreStmt<ReturnStmt> > { public Checker< check::PreStmt<ReturnStmt> > {
mutable std::unique_ptr<BuiltinBug> BT; mutable std::unique_ptr<BuiltinBug> BT;
@ -39,7 +39,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
const Expr *RetE = RS->getRetValue(); const Expr *RetE = RS->getRetValue();
if (!RetE) if (!RetE)
return; return;
SVal V = state->getSVal(RetE, C.getLocationContext()); SVal V = state->getSVal(RetE, C.getLocationContext());
const MemRegion *R = V.getAsRegion(); const MemRegion *R = V.getAsRegion();
@ -66,7 +66,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
if (!N) if (!N)
return; return;
// FIXME: This bug correspond to CWE-466. Eventually we should have bug // FIXME: This bug correspond to CWE-466. Eventually we should have bug
// types explicitly reference such exploit categories (when applicable). // types explicitly reference such exploit categories (when applicable).
if (!BT) if (!BT)

View File

@ -7,7 +7,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This file defines stack address leak checker, which checks if an invalid // This file defines stack address leak checker, which checks if an invalid
// stack address is stored into a global or heap location. See CERT DCL30-C. // stack address is stored into a global or heap location. See CERT DCL30-C.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -49,20 +49,20 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
SourceManager &SM = Ctx.getSourceManager(); SourceManager &SM = Ctx.getSourceManager();
SourceRange range; SourceRange range;
os << "Address of "; os << "Address of ";
// Check if the region is a compound literal. // Check if the region is a compound literal.
if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) { if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
const CompoundLiteralExpr *CL = CR->getLiteralExpr(); const CompoundLiteralExpr *CL = CR->getLiteralExpr();
os << "stack memory associated with a compound literal " os << "stack memory associated with a compound literal "
"declared on line " "declared on line "
<< SM.getExpansionLineNumber(CL->getLocStart()) << SM.getExpansionLineNumber(CL->getLocStart())
<< " returned to caller"; << " returned to caller";
range = CL->getSourceRange(); range = CL->getSourceRange();
} }
else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) { else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
const Expr *ARE = AR->getExpr(); const Expr *ARE = AR->getExpr();
SourceLocation L = ARE->getLocStart(); SourceLocation L = ARE->getLocStart();
range = ARE->getSourceRange(); range = ARE->getSourceRange();
os << "stack memory allocated by call to alloca() on line " os << "stack memory allocated by call to alloca() on line "
<< SM.getExpansionLineNumber(L); << SM.getExpansionLineNumber(L);
} }
@ -87,8 +87,8 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
} }
else { else {
llvm_unreachable("Invalid region in ReturnStackAddressChecker."); llvm_unreachable("Invalid region in ReturnStackAddressChecker.");
} }
return range; return range;
} }
@ -118,7 +118,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
CheckerContext &C) const { CheckerContext &C) const {
const Expr *RetE = RS->getRetValue(); const Expr *RetE = RS->getRetValue();
if (!RetE) if (!RetE)
return; return;
@ -130,10 +130,10 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
if (!R) if (!R)
return; return;
const StackSpaceRegion *SS = const StackSpaceRegion *SS =
dyn_cast_or_null<StackSpaceRegion>(R->getMemorySpace()); dyn_cast_or_null<StackSpaceRegion>(R->getMemorySpace());
if (!SS) if (!SS)
return; return;
@ -175,35 +175,35 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
Ctx(CC), Ctx(CC),
CurSFC(CC.getLocationContext()->getCurrentStackFrame()) CurSFC(CC.getLocationContext()->getCurrentStackFrame())
{} {}
bool HandleBinding(StoreManager &SMgr, Store store, bool HandleBinding(StoreManager &SMgr, Store store,
const MemRegion *region, SVal val) override { const MemRegion *region, SVal val) override {
if (!isa<GlobalsSpaceRegion>(region->getMemorySpace())) if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
return true; return true;
const MemRegion *vR = val.getAsRegion(); const MemRegion *vR = val.getAsRegion();
if (!vR) if (!vR)
return true; return true;
// Under automated retain release, it is okay to assign a block // Under automated retain release, it is okay to assign a block
// directly to a global variable. // directly to a global variable.
if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount && if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount &&
isa<BlockDataRegion>(vR)) isa<BlockDataRegion>(vR))
return true; return true;
if (const StackSpaceRegion *SSR = if (const StackSpaceRegion *SSR =
dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) { dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
// If the global variable holds a location in the current stack frame, // If the global variable holds a location in the current stack frame,
// record the binding to emit a warning. // record the binding to emit a warning.
if (SSR->getStackFrame() == CurSFC) if (SSR->getStackFrame() == CurSFC)
V.push_back(std::make_pair(region, vR)); V.push_back(std::make_pair(region, vR));
} }
return true; return true;
} }
}; };
CallBack cb(Ctx); CallBack cb(Ctx);
state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb); state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);

View File

@ -43,8 +43,8 @@ struct StreamState {
static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); } static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); }
static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); } static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); }
static StreamState getOpenFailed(const Stmt *s) { static StreamState getOpenFailed(const Stmt *s) {
return StreamState(OpenFailed, s); return StreamState(OpenFailed, s);
} }
static StreamState getEscaped(const Stmt *s) { static StreamState getEscaped(const Stmt *s) {
return StreamState(Escaped, s); return StreamState(Escaped, s);
@ -59,14 +59,14 @@ struct StreamState {
class StreamChecker : public Checker<eval::Call, class StreamChecker : public Checker<eval::Call,
check::DeadSymbols > { check::DeadSymbols > {
mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
*II_fwrite, *II_fwrite,
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos, *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
*II_clearerr, *II_feof, *II_ferror, *II_fileno; *II_clearerr, *II_feof, *II_ferror, *II_fileno;
mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence, mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence,
BT_doubleclose, BT_ResourceLeak; BT_doubleclose, BT_ResourceLeak;
public: public:
StreamChecker() StreamChecker()
: II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr), : II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr),
II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr), II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr),
II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr), II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr),
@ -93,10 +93,10 @@ private:
void Fileno(CheckerContext &C, const CallExpr *CE) const; void Fileno(CheckerContext &C, const CallExpr *CE) const;
void OpenFileAux(CheckerContext &C, const CallExpr *CE) const; void OpenFileAux(CheckerContext &C, const CallExpr *CE) const;
ProgramStateRef CheckNullStream(SVal SV, ProgramStateRef state, ProgramStateRef CheckNullStream(SVal SV, ProgramStateRef state,
CheckerContext &C) const; CheckerContext &C) const;
ProgramStateRef CheckDoubleClose(const CallExpr *CE, ProgramStateRef state, ProgramStateRef CheckDoubleClose(const CallExpr *CE, ProgramStateRef state,
CheckerContext &C) const; CheckerContext &C) const;
}; };
@ -216,13 +216,13 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
C.blockCount()) C.blockCount())
.castAs<DefinedSVal>(); .castAs<DefinedSVal>();
state = state->BindExpr(CE, C.getLocationContext(), RetVal); state = state->BindExpr(CE, C.getLocationContext(), RetVal);
ConstraintManager &CM = C.getConstraintManager(); ConstraintManager &CM = C.getConstraintManager();
// Bifurcate the state into two: one with a valid FILE* pointer, the other // Bifurcate the state into two: one with a valid FILE* pointer, the other
// with a NULL. // with a NULL.
ProgramStateRef stateNotNull, stateNull; ProgramStateRef stateNotNull, stateNull;
std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal); std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
if (SymbolRef Sym = RetVal.getAsSymbol()) { if (SymbolRef Sym = RetVal.getAsSymbol()) {
// if RetVal is not NULL, set the symbol's state to Opened. // if RetVal is not NULL, set the symbol's state to Opened.
stateNotNull = stateNotNull =
@ -368,13 +368,13 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
state->getSVal(CE->getArg(0), C.getLocationContext()).getAsSymbol(); state->getSVal(CE->getArg(0), C.getLocationContext()).getAsSymbol();
if (!Sym) if (!Sym)
return state; return state;
const StreamState *SS = state->get<StreamMap>(Sym); const StreamState *SS = state->get<StreamMap>(Sym);
// If the file stream is not tracked, return. // If the file stream is not tracked, return.
if (!SS) if (!SS)
return state; return state;
// Check: Double close a File Descriptor could cause undefined behaviour. // Check: Double close a File Descriptor could cause undefined behaviour.
// Conforming to man-pages // Conforming to man-pages
if (SS->isClosed()) { if (SS->isClosed()) {
@ -389,7 +389,7 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
} }
return nullptr; return nullptr;
} }
// Close the File Descriptor. // Close the File Descriptor.
return state->set<StreamMap>(Sym, StreamState::getClosed(CE)); return state->set<StreamMap>(Sym, StreamState::getClosed(CE));
} }

View File

@ -30,7 +30,7 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
ProgramStateRef St; ProgramStateRef St;
const LocationContext *LCtx; const LocationContext *LCtx;
FindUndefExpr(ProgramStateRef S, const LocationContext *L) FindUndefExpr(ProgramStateRef S, const LocationContext *L)
: St(S), LCtx(L) {} : St(S), LCtx(L) {}
const Expr *FindExpr(const Expr *Ex) { const Expr *FindExpr(const Expr *Ex) {
@ -45,7 +45,7 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
return Ex; return Ex;
} }
bool MatchesCriteria(const Expr *Ex) { bool MatchesCriteria(const Expr *Ex) {
return St->getSVal(Ex, LCtx).isUndef(); return St->getSVal(Ex, LCtx).isUndef();
} }
}; };

View File

@ -83,7 +83,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
SmallString<128> buf; SmallString<128> buf;
llvm::raw_svector_ostream os(buf); llvm::raw_svector_ostream os(buf);
os << "Variable '" << VD->getName() os << "Variable '" << VD->getName()
<< "' is uninitialized when captured by block"; << "' is uninitialized when captured by block";
auto R = llvm::make_unique<BugReport>(*BT, os.str(), N); auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);

View File

@ -7,7 +7,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This defines UndefResultChecker, a builtin check in ExprEngine that // This defines UndefResultChecker, a builtin check in ExprEngine that
// performs checks for undefined results of non-assignment binary operators. // performs checks for undefined results of non-assignment binary operators.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -25,7 +25,7 @@ using namespace clang;
using namespace ento; using namespace ento;
namespace { namespace {
class UndefResultChecker class UndefResultChecker
: public Checker< check::PostStmt<BinaryOperator> > { : public Checker< check::PostStmt<BinaryOperator> > {
mutable std::unique_ptr<BugType> BT; mutable std::unique_ptr<BugType> BT;
@ -53,7 +53,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
ExplodedNode *N = C.generateSink(); ExplodedNode *N = C.generateSink();
if (!N) if (!N)
return; return;
if (!BT) if (!BT)
BT.reset( BT.reset(
new BuiltinBug(this, "Result of operation is garbage or undefined")); new BuiltinBug(this, "Result of operation is garbage or undefined"));
@ -62,7 +62,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
llvm::raw_svector_ostream OS(sbuf); llvm::raw_svector_ostream OS(sbuf);
const Expr *Ex = nullptr; const Expr *Ex = nullptr;
bool isLeft = true; bool isLeft = true;
if (state->getSVal(B->getLHS(), LCtx).isUndef()) { if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
Ex = B->getLHS()->IgnoreParenCasts(); Ex = B->getLHS()->IgnoreParenCasts();
isLeft = true; isLeft = true;
@ -71,13 +71,13 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
Ex = B->getRHS()->IgnoreParenCasts(); Ex = B->getRHS()->IgnoreParenCasts();
isLeft = false; isLeft = false;
} }
if (Ex) { if (Ex) {
OS << "The " << (isLeft ? "left" : "right") OS << "The " << (isLeft ? "left" : "right")
<< " operand of '" << " operand of '"
<< BinaryOperator::getOpcodeStr(B->getOpcode()) << BinaryOperator::getOpcodeStr(B->getOpcode())
<< "' is a garbage value"; << "' is a garbage value";
} }
else { else {
// Neither operand was undefined, but the result is undefined. // Neither operand was undefined, but the result is undefined.
OS << "The result of the '" OS << "The result of the '"
@ -91,7 +91,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
} }
else else
bugreporter::trackNullOrUndefValue(N, B, *report); bugreporter::trackNullOrUndefValue(N, B, *report);
C.emitReport(std::move(report)); C.emitReport(std::move(report));
} }
} }

View File

@ -32,7 +32,7 @@ public:
}; };
} // end anonymous namespace } // end anonymous namespace
void void
UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
CheckerContext &C) const { CheckerContext &C) const {
const Expr *Index = A->getIdx(); const Expr *Index = A->getIdx();

View File

@ -114,7 +114,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const {
// The definition of O_CREAT is platform specific. We need a better way // The definition of O_CREAT is platform specific. We need a better way
// of querying this information from the checking environment. // of querying this information from the checking environment.
if (!Val_O_CREAT.hasValue()) { if (!Val_O_CREAT.hasValue()) {
if (C.getASTContext().getTargetInfo().getTriple().getVendor() if (C.getASTContext().getTargetInfo().getTriple().getVendor()
== llvm::Triple::Apple) == llvm::Triple::Apple)
Val_O_CREAT = 0x0200; Val_O_CREAT = 0x0200;
else { else {
@ -220,7 +220,7 @@ static bool IsZeroByteAllocation(ProgramStateRef state,
ProgramStateRef *falseState) { ProgramStateRef *falseState) {
std::tie(*trueState, *falseState) = std::tie(*trueState, *falseState) =
state->assume(argVal.castAs<DefinedSVal>()); state->assume(argVal.castAs<DefinedSVal>());
return (*falseState && !*trueState); return (*falseState && !*trueState);
} }
@ -239,7 +239,7 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
"Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)"); "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
SmallString<256> S; SmallString<256> S;
llvm::raw_svector_ostream os(S); llvm::raw_svector_ostream os(S);
os << "Call to '" << fn_name << "' has an allocation size of 0 bytes"; os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
auto report = llvm::make_unique<BugReport>(*BT_mallocZero, os.str(), N); auto report = llvm::make_unique<BugReport>(*BT_mallocZero, os.str(), N);
@ -272,13 +272,13 @@ void UnixAPIChecker::BasicAllocationCheck(CheckerContext &C,
// Is the value perfectly constrained to zero? // Is the value perfectly constrained to zero?
if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) { if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
(void) ReportZeroByteAllocation(C, falseState, arg, fn); (void) ReportZeroByteAllocation(C, falseState, arg, fn);
return; return;
} }
// Assume the value is non-zero going forward. // Assume the value is non-zero going forward.
assert(trueState); assert(trueState);
if (trueState != state) if (trueState != state)
C.addTransition(trueState); C.addTransition(trueState);
} }
void UnixAPIChecker::CheckCallocZero(CheckerContext &C, void UnixAPIChecker::CheckCallocZero(CheckerContext &C,

View File

@ -54,7 +54,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
BugReporter &B, BugReporter &B,
ExprEngine &Eng) const { ExprEngine &Eng) const {
CFGBlocksSet reachable, visited; CFGBlocksSet reachable, visited;
if (Eng.hasWorkRemaining()) if (Eng.hasWorkRemaining())
return; return;
@ -88,7 +88,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
// Bail out if we didn't get the CFG or the ParentMap. // Bail out if we didn't get the CFG or the ParentMap.
if (!D || !C || !PM) if (!D || !C || !PM)
return; return;
// Don't do anything for template instantiations. Proving that code // Don't do anything for template instantiations. Proving that code
// in a template instantiation is unreachable means proving that it is // in a template instantiation is unreachable means proving that it is
// unreachable in all instantiations. // unreachable in all instantiations.

View File

@ -7,7 +7,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This defines VLASizeChecker, a builtin check in ExprEngine that // This defines VLASizeChecker, a builtin check in ExprEngine that
// performs checks for declaration of VLA of undefined or zero size. // performs checks for declaration of VLA of undefined or zero size.
// In addition, VLASizeChecker is responsible for defining the extent // In addition, VLASizeChecker is responsible for defining the extent
// of the MemRegion that represents a VLA. // of the MemRegion that represents a VLA.
@ -82,7 +82,7 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind,
void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
if (!DS->isSingleDecl()) if (!DS->isSingleDecl())
return; return;
const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl()); const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
if (!VD) if (!VD)
return; return;
@ -106,7 +106,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
// warned about that already. // warned about that already.
if (sizeV.isUnknown()) if (sizeV.isUnknown())
return; return;
// Check if the size is tainted. // Check if the size is tainted.
if (state->isTainted(sizeV)) { if (state->isTainted(sizeV)) {
reportBug(VLA_Tainted, SE, nullptr, C); reportBug(VLA_Tainted, SE, nullptr, C);
@ -123,7 +123,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
reportBug(VLA_Zero, SE, stateZero, C); reportBug(VLA_Zero, SE, stateZero, C);
return; return;
} }
// From this point on, assume that the size is not zero. // From this point on, assume that the size is not zero.
state = stateNotZero; state = stateNotZero;

View File

@ -7,7 +7,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// //
// This file defines a checker that checks virtual function calls during // This file defines a checker that checks virtual function calls during
// construction or destruction of C++ objects. // construction or destruction of C++ objects.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -37,13 +37,13 @@ class WalkAST : public StmtVisitor<WalkAST> {
/// A vector representing the worklist which has a chain of CallExprs. /// A vector representing the worklist which has a chain of CallExprs.
DFSWorkList WList; DFSWorkList WList;
// PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
// body has not been visited yet. // body has not been visited yet.
// PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
// body has been visited. // body has been visited.
enum Kind { NotVisited, enum Kind { NotVisited,
PreVisited, /**< A CallExpr to this FunctionDecl is in the PreVisited, /**< A CallExpr to this FunctionDecl is in the
worklist, but the body has not yet been worklist, but the body has not yet been
visited. */ visited. */
PostVisited /**< A CallExpr to this FunctionDecl is in the PostVisited /**< A CallExpr to this FunctionDecl is in the
@ -57,7 +57,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
/// generating bug reports. This is null while visiting the body of a /// generating bug reports. This is null while visiting the body of a
/// constructor or destructor. /// constructor or destructor.
const CallExpr *visitingCallExpr; const CallExpr *visitingCallExpr;
public: public:
WalkAST(const CheckerBase *checker, BugReporter &br, WalkAST(const CheckerBase *checker, BugReporter &br,
AnalysisDeclContext *ac) AnalysisDeclContext *ac)
@ -70,7 +70,7 @@ public:
void Enqueue(WorkListUnit WLUnit) { void Enqueue(WorkListUnit WLUnit) {
const FunctionDecl *FD = WLUnit->getDirectCallee(); const FunctionDecl *FD = WLUnit->getDirectCallee();
if (!FD || !FD->getBody()) if (!FD || !FD->getBody())
return; return;
Kind &K = VisitedFunctions[FD]; Kind &K = VisitedFunctions[FD];
if (K != NotVisited) if (K != NotVisited)
return; return;
@ -81,9 +81,9 @@ public:
/// This method returns an item from the worklist without removing it. /// This method returns an item from the worklist without removing it.
WorkListUnit Dequeue() { WorkListUnit Dequeue() {
assert(!WList.empty()); assert(!WList.empty());
return WList.back(); return WList.back();
} }
void Execute() { void Execute() {
while (hasWork()) { while (hasWork()) {
WorkListUnit WLUnit = Dequeue(); WorkListUnit WLUnit = Dequeue();
@ -95,7 +95,7 @@ public:
// Visit the body. // Visit the body.
SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit); SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
Visit(FD->getBody()); Visit(FD->getBody());
// Mark the function as being PostVisited to indicate we have // Mark the function as being PostVisited to indicate we have
// scanned the body. // scanned the body.
VisitedFunctions[FD] = PostVisited; VisitedFunctions[FD] = PostVisited;
@ -114,7 +114,7 @@ public:
void VisitCXXMemberCallExpr(CallExpr *CE); void VisitCXXMemberCallExpr(CallExpr *CE);
void VisitStmt(Stmt *S) { VisitChildren(S); } void VisitStmt(Stmt *S) { VisitChildren(S); }
void VisitChildren(Stmt *S); void VisitChildren(Stmt *S);
void ReportVirtualCall(const CallExpr *CE, bool isPure); void ReportVirtualCall(const CallExpr *CE, bool isPure);
}; };
@ -138,7 +138,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) { void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
VisitChildren(CE); VisitChildren(CE);
bool callIsNonVirtual = false; bool callIsNonVirtual = false;
// Several situations to elide for checking. // Several situations to elide for checking.
if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) { if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
// If the member access is fully qualified (i.e., X::F), then treat // If the member access is fully qualified (i.e., X::F), then treat
@ -170,7 +170,7 @@ void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) { void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
SmallString<100> buf; SmallString<100> buf;
llvm::raw_svector_ostream os(buf); llvm::raw_svector_ostream os(buf);
os << "Call Path : "; os << "Call Path : ";
// Name of current visiting CallExpr. // Name of current visiting CallExpr.
os << *CE->getDirectCallee(); os << *CE->getDirectCallee();
@ -190,7 +190,7 @@ void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
PathDiagnosticLocation CELoc = PathDiagnosticLocation CELoc =
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
SourceRange R = CE->getCallee()->getSourceRange(); SourceRange R = CE->getCallee()->getSourceRange();
if (isPure) { if (isPure) {
os << "\n" << "Call pure virtual functions during construction or " os << "\n" << "Call pure virtual functions during construction or "
<< "destruction may leads undefined behaviour"; << "destruction may leads undefined behaviour";

View File

@ -18,7 +18,7 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
const LangOptions &lang, const LangOptions &lang,
const PathDiagnosticConsumers &PDC, const PathDiagnosticConsumers &PDC,
StoreManagerCreator storemgr, StoreManagerCreator storemgr,
ConstraintManagerCreator constraintmgr, ConstraintManagerCreator constraintmgr,
CheckerManager *checkerMgr, CheckerManager *checkerMgr,
AnalyzerOptions &Options, AnalyzerOptions &Options,
CodeInjector *injector) CodeInjector *injector)

View File

@ -65,7 +65,7 @@ IPAKind AnalyzerOptions::getIPAMode() {
// Set the member variable. // Set the member variable.
IPAMode = IPAConfig; IPAMode = IPAConfig;
} }
return IPAMode; return IPAMode;
} }

View File

@ -26,7 +26,7 @@ class CountKey {
unsigned BlockID; unsigned BlockID;
public: public:
CountKey(const StackFrameContext *CS, unsigned ID) CountKey(const StackFrameContext *CS, unsigned ID)
: CallSite(CS), BlockID(ID) {} : CallSite(CS), BlockID(ID) {}
bool operator==(const CountKey &RHS) const { bool operator==(const CountKey &RHS) const {
@ -55,7 +55,7 @@ static inline CountMap::Factory& GetFactory(void *F) {
return *static_cast<CountMap::Factory*>(F); return *static_cast<CountMap::Factory*>(F);
} }
unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite, unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite,
unsigned BlockID) const { unsigned BlockID) const {
CountMap M = GetMap(Data); CountMap M = GetMap(Data);
CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID)); CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
@ -71,10 +71,10 @@ BlockCounter::Factory::~Factory() {
} }
BlockCounter BlockCounter
BlockCounter::Factory::IncrementCount(BlockCounter BC, BlockCounter::Factory::IncrementCount(BlockCounter BC,
const StackFrameContext *CallSite, const StackFrameContext *CallSite,
unsigned BlockID) { unsigned BlockID) {
return BlockCounter(GetFactory(F).add(GetMap(BC.Data), return BlockCounter(GetFactory(F).add(GetMap(BC.Data),
CountKey(CallSite, BlockID), CountKey(CallSite, BlockID),
BC.getNumVisited(CallSite, BlockID)+1).getRoot()); BC.getNumVisited(CallSite, BlockID)+1).getRoot());
} }

View File

@ -81,13 +81,13 @@ eventsDescribeSameCondition(PathDiagnosticEventPiece *X,
// those that came from TrackConstraintBRVisitor. // those that came from TrackConstraintBRVisitor.
const void *tagPreferred = ConditionBRVisitor::getTag(); const void *tagPreferred = ConditionBRVisitor::getTag();
const void *tagLesser = TrackConstraintBRVisitor::getTag(); const void *tagLesser = TrackConstraintBRVisitor::getTag();
if (X->getLocation() != Y->getLocation()) if (X->getLocation() != Y->getLocation())
return nullptr; return nullptr;
if (X->getTag() == tagPreferred && Y->getTag() == tagLesser) if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
return X; return X;
if (Y->getTag() == tagPreferred && X->getTag() == tagLesser) if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
return Y; return Y;
@ -110,7 +110,7 @@ static void removeRedundantMsgs(PathPieces &path) {
for (unsigned i = 0; i < N; ++i) { for (unsigned i = 0; i < N; ++i) {
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(path.front()); IntrusiveRefCntPtr<PathDiagnosticPiece> piece(path.front());
path.pop_front(); path.pop_front();
switch (piece->getKind()) { switch (piece->getKind()) {
case clang::ento::PathDiagnosticPiece::Call: case clang::ento::PathDiagnosticPiece::Call:
removeRedundantMsgs(cast<PathDiagnosticCallPiece>(piece)->path); removeRedundantMsgs(cast<PathDiagnosticCallPiece>(piece)->path);
@ -123,7 +123,7 @@ static void removeRedundantMsgs(PathPieces &path) {
case clang::ento::PathDiagnosticPiece::Event: { case clang::ento::PathDiagnosticPiece::Event: {
if (i == N-1) if (i == N-1)
break; break;
if (PathDiagnosticEventPiece *nextEvent = if (PathDiagnosticEventPiece *nextEvent =
dyn_cast<PathDiagnosticEventPiece>(path.front().get())) { dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
PathDiagnosticEventPiece *event = PathDiagnosticEventPiece *event =
@ -157,13 +157,13 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
LocationContextMap &LCM) { LocationContextMap &LCM) {
bool containsSomethingInteresting = false; bool containsSomethingInteresting = false;
const unsigned N = pieces.size(); const unsigned N = pieces.size();
for (unsigned i = 0 ; i < N ; ++i) { for (unsigned i = 0 ; i < N ; ++i) {
// Remove the front piece from the path. If it is still something we // Remove the front piece from the path. If it is still something we
// want to keep once we are done, we will push it back on the end. // want to keep once we are done, we will push it back on the end.
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front()); IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front());
pieces.pop_front(); pieces.pop_front();
switch (piece->getKind()) { switch (piece->getKind()) {
case PathDiagnosticPiece::Call: { case PathDiagnosticPiece::Call: {
PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece); PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece);
@ -176,7 +176,7 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
if (!removeUnneededCalls(call->path, R, LCM)) if (!removeUnneededCalls(call->path, R, LCM))
continue; continue;
containsSomethingInteresting = true; containsSomethingInteresting = true;
break; break;
} }
@ -189,7 +189,7 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
} }
case PathDiagnosticPiece::Event: { case PathDiagnosticPiece::Event: {
PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece); PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece);
// We never throw away an event, but we do throw it away wholesale // We never throw away an event, but we do throw it away wholesale
// as part of a path if we throw the entire path away. // as part of a path if we throw the entire path away.
containsSomethingInteresting |= !event->isPrunable(); containsSomethingInteresting |= !event->isPrunable();
@ -198,10 +198,10 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
case PathDiagnosticPiece::ControlFlow: case PathDiagnosticPiece::ControlFlow:
break; break;
} }
pieces.push_back(piece); pieces.push_back(piece);
} }
return containsSomethingInteresting; return containsSomethingInteresting;
} }
@ -213,7 +213,7 @@ static bool hasImplicitBody(const Decl *D) {
} }
/// Recursively scan through a path and make sure that all call pieces have /// Recursively scan through a path and make sure that all call pieces have
/// valid locations. /// valid locations.
static void static void
adjustCallLocations(PathPieces &Pieces, adjustCallLocations(PathPieces &Pieces,
PathDiagnosticLocation *LastCallLocation = nullptr) { PathDiagnosticLocation *LastCallLocation = nullptr) {
@ -323,7 +323,7 @@ class PathDiagnosticBuilder : public BugReporterContext {
NodeMapClosure NMC; NodeMapClosure NMC;
public: public:
const LocationContext *LC; const LocationContext *LC;
PathDiagnosticBuilder(GRBugReporter &br, PathDiagnosticBuilder(GRBugReporter &br,
BugReport *r, InterExplodedGraphMap &Backmap, BugReport *r, InterExplodedGraphMap &Backmap,
PathDiagnosticConsumer *pdc) PathDiagnosticConsumer *pdc)
@ -339,7 +339,7 @@ public:
BugReport *getBugReport() { return R; } BugReport *getBugReport() { return R; }
Decl const &getCodeDecl() { return R->getErrorNode()->getCodeDecl(); } Decl const &getCodeDecl() { return R->getErrorNode()->getCodeDecl(); }
ParentMap& getParentMap() { return LC->getParentMap(); } ParentMap& getParentMap() { return LC->getParentMap(); }
const Stmt *getParent(const Stmt *S) { const Stmt *getParent(const Stmt *S) {
@ -957,7 +957,7 @@ static PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L,
if (firstCharOnly) if (firstCharOnly)
L = PathDiagnosticLocation::createSingleLocation(L); L = PathDiagnosticLocation::createSingleLocation(L);
return L; return L;
} }
@ -1001,7 +1001,7 @@ public:
~EdgeBuilder() { ~EdgeBuilder() {
while (!CLocs.empty()) popLocation(); while (!CLocs.empty()) popLocation();
// Finally, add an initial edge from the start location of the first // Finally, add an initial edge from the start location of the first
// statement (if it doesn't already exist). // statement (if it doesn't already exist).
PathDiagnosticLocation L = PathDiagnosticLocation::createDeclBegin( PathDiagnosticLocation L = PathDiagnosticLocation::createDeclBegin(
@ -1016,7 +1016,7 @@ public:
popLocation(); popLocation();
PrevLoc = PathDiagnosticLocation(); PrevLoc = PathDiagnosticLocation();
} }
void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false, void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false,
bool IsPostJump = false); bool IsPostJump = false);
@ -1101,7 +1101,7 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
PrevLoc = NewLoc; PrevLoc = NewLoc;
return; return;
} }
if (NewLocClean.asLocation() == PrevLocClean.asLocation()) if (NewLocClean.asLocation() == PrevLocClean.asLocation())
return; return;
@ -1242,7 +1242,7 @@ static void reversePropagateIntererstingSymbols(BugReport &R,
SVal V = State->getSVal(Ex, LCtx); SVal V = State->getSVal(Ex, LCtx);
if (!(R.isInteresting(V) || IE.count(Ex))) if (!(R.isInteresting(V) || IE.count(Ex)))
return; return;
switch (Ex->getStmtClass()) { switch (Ex->getStmtClass()) {
default: default:
if (!isa<CastExpr>(Ex)) if (!isa<CastExpr>(Ex))
@ -1260,7 +1260,7 @@ static void reversePropagateIntererstingSymbols(BugReport &R,
break; break;
} }
} }
R.markInteresting(V); R.markInteresting(V);
} }
@ -1275,7 +1275,7 @@ static void reversePropagateInterestingSymbols(BugReport &R,
const Stmt *CallSite = Callee->getCallSite(); const Stmt *CallSite = Callee->getCallSite();
if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite)) { if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeCtx->getDecl())) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeCtx->getDecl())) {
FunctionDecl::param_const_iterator PI = FD->param_begin(), FunctionDecl::param_const_iterator PI = FD->param_begin(),
PE = FD->param_end(); PE = FD->param_end();
CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end(); CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
for (; AI != AE && PI != PE; ++AI, ++PI) { for (; AI != AE && PI != PE; ++AI, ++PI) {
@ -1406,7 +1406,7 @@ static bool GenerateExtensivePathDiagnostic(
N->getState().get(), Ex, N->getState().get(), Ex,
N->getLocationContext()); N->getLocationContext());
} }
if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) { if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
const Stmt *S = CE->getCalleeContext()->getCallSite(); const Stmt *S = CE->getCalleeContext()->getCallSite();
if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) { if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
@ -1414,7 +1414,7 @@ static bool GenerateExtensivePathDiagnostic(
N->getState().get(), Ex, N->getState().get(), Ex,
N->getLocationContext()); N->getLocationContext());
} }
PathDiagnosticCallPiece *C = PathDiagnosticCallPiece *C =
PathDiagnosticCallPiece::construct(N, *CE, SM); PathDiagnosticCallPiece::construct(N, *CE, SM);
LCM[&C->path] = CE->getCalleeContext(); LCM[&C->path] = CE->getCalleeContext();
@ -1427,7 +1427,7 @@ static bool GenerateExtensivePathDiagnostic(
CallStack.push_back(StackDiagPair(C, N)); CallStack.push_back(StackDiagPair(C, N));
break; break;
} }
// Pop the call hierarchy if we are done walking the contents // Pop the call hierarchy if we are done walking the contents
// of a function call. // of a function call.
if (Optional<CallEnter> CE = P.getAs<CallEnter>()) { if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
@ -1436,7 +1436,7 @@ static bool GenerateExtensivePathDiagnostic(
PathDiagnosticLocation pos = PathDiagnosticLocation pos =
PathDiagnosticLocation::createBegin(D, SM); PathDiagnosticLocation::createBegin(D, SM);
EB.addEdge(pos); EB.addEdge(pos);
// Flush all locations, and pop the active path. // Flush all locations, and pop the active path.
bool VisitedEntireCall = PD.isWithinCall(); bool VisitedEntireCall = PD.isWithinCall();
EB.flushLocations(); EB.flushLocations();
@ -1466,7 +1466,7 @@ static bool GenerateExtensivePathDiagnostic(
} }
break; break;
} }
// Note that is important that we update the LocationContext // Note that is important that we update the LocationContext
// after looking at CallExits. CallExit basically adds an // after looking at CallExits. CallExit basically adds an
// edge in the *caller*, so we don't want to update the LocationContext // edge in the *caller*, so we don't want to update the LocationContext
@ -1486,7 +1486,7 @@ static bool GenerateExtensivePathDiagnostic(
CalleeCtx, CallerCtx); CalleeCtx, CallerCtx);
} }
} }
// Are we jumping to the head of a loop? Add a special diagnostic. // Are we jumping to the head of a loop? Add a special diagnostic.
if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
PathDiagnosticLocation L(Loop, SM, PDB.LC); PathDiagnosticLocation L(Loop, SM, PDB.LC);
@ -1552,11 +1552,11 @@ static bool GenerateExtensivePathDiagnostic(
else else
EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt()); EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt());
} }
break; break;
} }
} while (0); } while (0);
if (!NextNode) if (!NextNode)
@ -2410,7 +2410,7 @@ static bool optimizeEdges(PathPieces &path, SourceManager &SM,
// Trim edges on expressions that are consumed by // Trim edges on expressions that are consumed by
// the parent expression. // the parent expression.
if (isa<Expr>(s1End) && PM.isConsumedExpr(cast<Expr>(s1End))) { if (isa<Expr>(s1End) && PM.isConsumedExpr(cast<Expr>(s1End))) {
removeEdge = true; removeEdge = true;
} }
// Trim edges where a lexical containment doesn't exist. // Trim edges where a lexical containment doesn't exist.
// For example: // For example:
@ -2557,7 +2557,7 @@ BugReport::~BugReport() {
const Decl *BugReport::getDeclWithIssue() const { const Decl *BugReport::getDeclWithIssue() const {
if (DeclWithIssue) if (DeclWithIssue)
return DeclWithIssue; return DeclWithIssue;
const ExplodedNode *N = getErrorNode(); const ExplodedNode *N = getErrorNode();
if (!N) if (!N)
return nullptr; return nullptr;
@ -2973,14 +2973,14 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) {
for (PathPieces::const_iterator I = path.begin(), E = path.end(); for (PathPieces::const_iterator I = path.begin(), E = path.end();
I!=E; ++I) { I!=E; ++I) {
PathDiagnosticPiece *piece = I->get(); PathDiagnosticPiece *piece = I->get();
// Recursively compact calls. // Recursively compact calls.
if (PathDiagnosticCallPiece *call=dyn_cast<PathDiagnosticCallPiece>(piece)){ if (PathDiagnosticCallPiece *call=dyn_cast<PathDiagnosticCallPiece>(piece)){
CompactPathDiagnostic(call->path, SM); CompactPathDiagnostic(call->path, SM);
} }
// Get the location of the PathDiagnosticPiece. // Get the location of the PathDiagnosticPiece.
const FullSourceLoc Loc = piece->getLocation().asLocation(); const FullSourceLoc Loc = piece->getLocation().asLocation();
@ -3126,7 +3126,7 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
PD.resetPath(); PD.resetPath();
origReportConfigToken = R->getConfigurationChangeToken(); origReportConfigToken = R->getConfigurationChangeToken();
// Generate the very last diagnostic piece - the piece is visible before // Generate the very last diagnostic piece - the piece is visible before
// the trace is expanded. // the trace is expanded.
std::unique_ptr<PathDiagnosticPiece> LastPiece; std::unique_ptr<PathDiagnosticPiece> LastPiece;
for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end(); for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
@ -3234,7 +3234,7 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
!DeclCtx->isBodyAutosynthesizedFromModelFile()) !DeclCtx->isBodyAutosynthesizedFromModelFile())
return; return;
} }
bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid(); bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid();
assert(ValidSourceLoc); assert(ValidSourceLoc);
// If we mess up in a release build, we'd still prefer to just drop the bug // If we mess up in a release build, we'd still prefer to just drop the bug
@ -3269,10 +3269,10 @@ namespace {
struct FRIEC_WLItem { struct FRIEC_WLItem {
const ExplodedNode *N; const ExplodedNode *N;
ExplodedNode::const_succ_iterator I, E; ExplodedNode::const_succ_iterator I, E;
FRIEC_WLItem(const ExplodedNode *n) FRIEC_WLItem(const ExplodedNode *n)
: N(n), I(N->succ_begin()), E(N->succ_end()) {} : N(n), I(N->succ_begin()), E(N->succ_end()) {}
}; };
} }
static BugReport * static BugReport *
@ -3324,21 +3324,21 @@ FindReportInEquivalenceClass(BugReportEquivClass& EQ,
} }
// At this point we know that 'N' is not a sink and it has at least one // At this point we know that 'N' is not a sink and it has at least one
// successor. Use a DFS worklist to find a non-sink end-of-path node. // successor. Use a DFS worklist to find a non-sink end-of-path node.
typedef FRIEC_WLItem WLItem; typedef FRIEC_WLItem WLItem;
typedef SmallVector<WLItem, 10> DFSWorkList; typedef SmallVector<WLItem, 10> DFSWorkList;
llvm::DenseMap<const ExplodedNode *, unsigned> Visited; llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
DFSWorkList WL; DFSWorkList WL;
WL.push_back(errorNode); WL.push_back(errorNode);
Visited[errorNode] = 1; Visited[errorNode] = 1;
while (!WL.empty()) { while (!WL.empty()) {
WLItem &WI = WL.back(); WLItem &WI = WL.back();
assert(!WI.N->succ_empty()); assert(!WI.N->succ_empty());
for (; WI.I != WI.E; ++WI.I) { for (; WI.I != WI.E; ++WI.I) {
const ExplodedNode *Succ = *WI.I; const ExplodedNode *Succ = *WI.I;
// End-of-path node? // End-of-path node?
if (Succ->succ_empty()) { if (Succ->succ_empty()) {
// If we found an end-of-path node that is not a sink. // If we found an end-of-path node that is not a sink.

View File

@ -169,7 +169,7 @@ public:
bool InEnableNullFPSuppression) { bool InEnableNullFPSuppression) {
if (!CallEvent::isCallStmt(S)) if (!CallEvent::isCallStmt(S))
return; return;
// First, find when we processed the statement. // First, find when we processed the statement.
do { do {
if (Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>()) if (Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>())
@ -192,11 +192,11 @@ public:
Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>(); Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>();
if (!CEE) if (!CEE)
return; return;
const StackFrameContext *CalleeContext = CEE->getCalleeContext(); const StackFrameContext *CalleeContext = CEE->getCalleeContext();
if (CalleeContext->getCallSite() != S) if (CalleeContext->getCallSite() != S)
return; return;
// Check the return value. // Check the return value.
ProgramStateRef State = Node->getState(); ProgramStateRef State = Node->getState();
SVal RetVal = State->getSVal(S, Node->getLocationContext()); SVal RetVal = State->getSVal(S, Node->getLocationContext());
@ -281,7 +281,7 @@ public:
EnableNullFPSuppression); EnableNullFPSuppression);
return nullptr; return nullptr;
} }
// If we're returning 0, we should track where that 0 came from. // If we're returning 0, we should track where that 0 came from.
bugreporter::trackNullOrUndefValue(N, RetE, BR, /*IsArg*/ false, bugreporter::trackNullOrUndefValue(N, RetE, BR, /*IsArg*/ false,
EnableNullFPSuppression); EnableNullFPSuppression);
@ -472,7 +472,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
InitE = PIP->getInitializer()->getInit(); InitE = PIP->getInitializer()->getInit();
} }
} }
// Otherwise, see if this is the store site: // Otherwise, see if this is the store site:
// (1) Succ has this binding and Pred does not, i.e. this is // (1) Succ has this binding and Pred does not, i.e. this is
// where the binding first occurred. // where the binding first occurred.
@ -504,7 +504,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) { if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
ProgramStateManager &StateMgr = BRC.getStateManager(); ProgramStateManager &StateMgr = BRC.getStateManager();
CallEventManager &CallMgr = StateMgr.getCallEventManager(); CallEventManager &CallMgr = StateMgr.getCallEventManager();
@ -681,7 +681,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
else else
os << "Assigning value"; os << "Assigning value";
} }
if (R->canPrintPretty()) { if (R->canPrintPretty()) {
os << " to "; os << " to ";
R->printPretty(os); R->printPretty(os);
@ -931,7 +931,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
if (!N) if (!N)
return false; return false;
} }
ProgramStateRef state = N->getState(); ProgramStateRef state = N->getState();
// The message send could be nil due to the receiver being nil. // The message send could be nil due to the receiver being nil.
@ -959,7 +959,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
assert(LVNode && "Unable to find the lvalue node."); assert(LVNode && "Unable to find the lvalue node.");
ProgramStateRef LVState = LVNode->getState(); ProgramStateRef LVState = LVNode->getState();
SVal LVal = LVState->getSVal(Inner, LVNode->getLocationContext()); SVal LVal = LVState->getSVal(Inner, LVNode->getLocationContext());
if (LVState->isNull(LVal).isConstrainedTrue()) { if (LVState->isNull(LVal).isConstrainedTrue()) {
// In case of C++ references, we want to differentiate between a null // In case of C++ references, we want to differentiate between a null
// reference and reference to null pointer. // reference and reference to null pointer.
@ -1162,11 +1162,11 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
const ExplodedNode *Prev, const ExplodedNode *Prev,
BugReporterContext &BRC, BugReporterContext &BRC,
BugReport &BR) { BugReport &BR) {
ProgramPoint progPoint = N->getLocation(); ProgramPoint progPoint = N->getLocation();
ProgramStateRef CurrentState = N->getState(); ProgramStateRef CurrentState = N->getState();
ProgramStateRef PrevState = Prev->getState(); ProgramStateRef PrevState = Prev->getState();
// Compare the GDMs of the state, because that is where constraints // Compare the GDMs of the state, because that is where constraints
// are managed. Note that ensure that we only look at nodes that // are managed. Note that ensure that we only look at nodes that
// were generated by the analyzer engine proper, not checkers. // were generated by the analyzer engine proper, not checkers.
@ -1177,16 +1177,16 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
// If an assumption was made on a branch, it should be caught // If an assumption was made on a branch, it should be caught
// here by looking at the state transition. // here by looking at the state transition.
if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) { if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) {
const CFGBlock *srcBlk = BE->getSrc(); const CFGBlock *srcBlk = BE->getSrc();
if (const Stmt *term = srcBlk->getTerminator()) if (const Stmt *term = srcBlk->getTerminator())
return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC); return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC);
return nullptr; return nullptr;
} }
if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) { if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) {
// FIXME: Assuming that BugReporter is a GRBugReporter is a layering // FIXME: Assuming that BugReporter is a GRBugReporter is a layering
// violation. // violation.
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags = const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
cast<GRBugReporter>(BRC.getBugReporter()). cast<GRBugReporter>(BRC.getBugReporter()).
getEngine().geteagerlyAssumeBinOpBifurcationTags(); getEngine().geteagerlyAssumeBinOpBifurcationTags();
@ -1222,7 +1222,7 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
case Stmt::ConditionalOperatorClass: case Stmt::ConditionalOperatorClass:
Cond = cast<ConditionalOperator>(Term)->getCond(); Cond = cast<ConditionalOperator>(Term)->getCond();
break; break;
} }
assert(Cond); assert(Cond);
assert(srcBlk->succ_size() == 2); assert(srcBlk->succ_size() == 2);
@ -1236,9 +1236,9 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
BugReporterContext &BRC, BugReporterContext &BRC,
BugReport &R, BugReport &R,
const ExplodedNode *N) { const ExplodedNode *N) {
const Expr *Ex = Cond; const Expr *Ex = Cond;
while (true) { while (true) {
Ex = Ex->IgnoreParenCasts(); Ex = Ex->IgnoreParenCasts();
switch (Ex->getStmtClass()) { switch (Ex->getStmtClass()) {
@ -1294,7 +1294,7 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out,
Out << '\''; Out << '\'';
return quotes; return quotes;
} }
if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) { if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) {
QualType OriginalTy = OriginalExpr->getType(); QualType OriginalTy = OriginalExpr->getType();
if (OriginalTy->isPointerType()) { if (OriginalTy->isPointerType()) {
@ -1309,11 +1309,11 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out,
return false; return false;
} }
} }
Out << IL->getValue(); Out << IL->getValue();
return false; return false;
} }
return false; return false;
} }
@ -1324,10 +1324,10 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
BugReporterContext &BRC, BugReporterContext &BRC,
BugReport &R, BugReport &R,
const ExplodedNode *N) { const ExplodedNode *N) {
bool shouldInvert = false; bool shouldInvert = false;
Optional<bool> shouldPrune; Optional<bool> shouldPrune;
SmallString<128> LhsString, RhsString; SmallString<128> LhsString, RhsString;
{ {
llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString); llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
@ -1335,10 +1335,10 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
shouldPrune); shouldPrune);
const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N, const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N,
shouldPrune); shouldPrune);
shouldInvert = !isVarLHS && isVarRHS; shouldInvert = !isVarLHS && isVarRHS;
} }
BinaryOperator::Opcode Op = BExpr->getOpcode(); BinaryOperator::Opcode Op = BExpr->getOpcode();
if (BinaryOperator::isAssignmentOp(Op)) { if (BinaryOperator::isAssignmentOp(Op)) {
@ -1380,7 +1380,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
default: default:
return nullptr; return nullptr;
} }
switch (Op) { switch (Op) {
case BO_EQ: case BO_EQ:
Out << "equal to "; Out << "equal to ";
@ -1392,7 +1392,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
Out << BinaryOperator::getOpcodeStr(Op) << ' '; Out << BinaryOperator::getOpcodeStr(Op) << ' ';
break; break;
} }
Out << (shouldInvert ? LhsString : RhsString); Out << (shouldInvert ? LhsString : RhsString);
const LocationContext *LCtx = N->getLocationContext(); const LocationContext *LCtx = N->getLocationContext();
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
@ -1416,7 +1416,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
SmallString<256> buf; SmallString<256> buf;
llvm::raw_svector_ostream Out(buf); llvm::raw_svector_ostream Out(buf);
Out << "Assuming " << LhsString << " is "; Out << "Assuming " << LhsString << " is ";
QualType Ty = CondVarExpr->getType(); QualType Ty = CondVarExpr->getType();
if (Ty->isPointerType()) if (Ty->isPointerType())
@ -1444,10 +1444,10 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
} }
} }
} }
return event; return event;
} }
PathDiagnosticPiece * PathDiagnosticPiece *
ConditionBRVisitor::VisitTrueTest(const Expr *Cond, ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
const DeclRefExpr *DR, const DeclRefExpr *DR,
@ -1462,11 +1462,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
SmallString<256> Buf; SmallString<256> Buf;
llvm::raw_svector_ostream Out(Buf); llvm::raw_svector_ostream Out(Buf);
Out << "Assuming '" << VD->getDeclName() << "' is "; Out << "Assuming '" << VD->getDeclName() << "' is ";
QualType VDTy = VD->getType(); QualType VDTy = VD->getType();
if (VDTy->isPointerType()) if (VDTy->isPointerType())
Out << (tookTrue ? "non-null" : "null"); Out << (tookTrue ? "non-null" : "null");
else if (VDTy->isObjCObjectPointerType()) else if (VDTy->isObjCObjectPointerType())
@ -1480,7 +1480,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx); PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
PathDiagnosticEventPiece *event = PathDiagnosticEventPiece *event =
new PathDiagnosticEventPiece(Loc, Out.str()); new PathDiagnosticEventPiece(Loc, Out.str());
const ProgramState *state = N->getState().get(); const ProgramState *state = N->getState().get();
if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) { if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
if (report.isInteresting(R)) if (report.isInteresting(R))
@ -1615,13 +1615,13 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
// Function can only change the value passed in by address. // Function can only change the value passed in by address.
continue; continue;
} }
// If it is a const pointer value, the function does not intend to // If it is a const pointer value, the function does not intend to
// change the value. // change the value.
if (T->getPointeeType().isConstQualified()) if (T->getPointeeType().isConstQualified())
continue; continue;
// Mark the call site (LocationContext) as interesting if the value of the // Mark the call site (LocationContext) as interesting if the value of the
// argument is undefined or '0'/'NULL'. // argument is undefined or '0'/'NULL'.
SVal BoundVal = State->getSVal(R); SVal BoundVal = State->getSVal(R);
if (BoundVal.isUndef() || BoundVal.isZeroConstant()) { if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {

View File

@ -96,7 +96,7 @@ bool CallEvent::hasNonZeroCallbackArg() const {
if (isCallbackArg(getArgSVal(Idx), *I)) if (isCallbackArg(getArgSVal(Idx), *I))
return true; return true;
} }
return false; return false;
} }
@ -159,7 +159,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
// below for efficiency. // below for efficiency.
if (PreserveArgs.count(Idx)) if (PreserveArgs.count(Idx))
if (const MemRegion *MR = getArgSVal(Idx).getAsRegion()) if (const MemRegion *MR = getArgSVal(Idx).getAsRegion())
ETraits.setTrait(MR->StripCasts(), ETraits.setTrait(MR->StripCasts(),
RegionAndSymbolInvalidationTraits::TK_PreserveContents); RegionAndSymbolInvalidationTraits::TK_PreserveContents);
// TODO: Factor this out + handle the lower level const pointers. // TODO: Factor this out + handle the lower level const pointers.
@ -184,7 +184,7 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
} }
const Decl *D = getDecl(); const Decl *D = getDecl();
assert(D && "Cannot get a program point without a statement or decl"); assert(D && "Cannot get a program point without a statement or decl");
SourceLocation Loc = getSourceRange().getBegin(); SourceLocation Loc = getSourceRange().getBegin();
if (IsPreVisit) if (IsPreVisit)
@ -265,7 +265,7 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) {
return QualType(); return QualType();
} }
llvm_unreachable("unknown callable kind"); llvm_unreachable("unknown callable kind");
} }
@ -336,7 +336,7 @@ bool AnyFunctionCall::argumentsMayEscape() const {
if (!II) if (!II)
return false; return false;
// This set of "escaping" APIs is // This set of "escaping" APIs is
// - 'int pthread_setspecific(ptheread_key k, const void *)' stores a // - 'int pthread_setspecific(ptheread_key k, const void *)' stores a
// value into thread local storage. The value can later be retrieved with // value into thread local storage. The value can later be retrieved with
@ -455,7 +455,7 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
// However, we should at least be able to search up and down our own class // However, we should at least be able to search up and down our own class
// hierarchy, and some real bugs have been caught by checking this. // hierarchy, and some real bugs have been caught by checking this.
assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method"); assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method");
// FIXME: This is checking that our DynamicTypeInfo is at least as good as // FIXME: This is checking that our DynamicTypeInfo is at least as good as
// the static type. However, because we currently don't update // the static type. However, because we currently don't update
// DynamicTypeInfo when an object is cast, we can't actually be sure the // DynamicTypeInfo when an object is cast, we can't actually be sure the
@ -525,7 +525,7 @@ RuntimeDefinition CXXMemberCall::getRuntimeDefinition() const {
if (const MemberExpr *ME = dyn_cast<MemberExpr>(getOriginExpr()->getCallee())) if (const MemberExpr *ME = dyn_cast<MemberExpr>(getOriginExpr()->getCallee()))
if (ME->hasQualifier()) if (ME->hasQualifier())
return AnyFunctionCall::getRuntimeDefinition(); return AnyFunctionCall::getRuntimeDefinition();
return CXXInstanceCall::getRuntimeDefinition(); return CXXInstanceCall::getRuntimeDefinition();
} }
@ -628,7 +628,7 @@ SVal ObjCMethodCall::getReceiverSVal() const {
// FIXME: Is this the best way to handle class receivers? // FIXME: Is this the best way to handle class receivers?
if (!isInstanceMessage()) if (!isInstanceMessage())
return UnknownVal(); return UnknownVal();
if (const Expr *RecE = getOriginExpr()->getInstanceReceiver()) if (const Expr *RecE = getOriginExpr()->getInstanceReceiver())
return getSVal(RecE); return getSVal(RecE);
@ -709,7 +709,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const {
return K; return K;
} }
} }
const_cast<ObjCMethodCall *>(this)->Data const_cast<ObjCMethodCall *>(this)->Data
= ObjCMessageDataTy(nullptr, 1).getOpaqueValue(); = ObjCMessageDataTy(nullptr, 1).getOpaqueValue();
assert(getMessageKind() == OCM_Message); assert(getMessageKind() == OCM_Message);
@ -730,7 +730,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
getState()->getStateManager().getContext().getSourceManager(); getState()->getStateManager().getContext().getSourceManager();
// If the class interface is declared inside the main file, assume it is not // If the class interface is declared inside the main file, assume it is not
// subcassed. // subcassed.
// TODO: It could actually be subclassed if the subclass is private as well. // TODO: It could actually be subclassed if the subclass is private as well.
// This is probably very rare. // This is probably very rare.
SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc(); SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc();

View File

@ -23,7 +23,7 @@ StringRef CheckerBase::getTagDescription() const {
CheckName CheckerBase::getCheckName() const { return Name; } CheckName CheckerBase::getCheckName() const { return Name; }
CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName, CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName,
StringRef Msg) StringRef Msg)
: SimpleProgramPointTag(CheckerName, Msg) {} : SimpleProgramPointTag(CheckerName, Msg) {}

View File

@ -357,9 +357,9 @@ void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
ExplodedNodeSet &Dst, ExplodedNodeSet &Dst,
ExplodedNode *Pred, ExplodedNode *Pred,
ExprEngine &Eng) { ExprEngine &Eng) {
// We define the builder outside of the loop bacause if at least one checkers // We define the builder outside of the loop bacause if at least one checkers
// creates a sucsessor for Pred, we do not need to generate an // creates a sucsessor for Pred, we do not need to generate an
// autotransition for it. // autotransition for it.
NodeBuilder Bldr(Pred, Dst, BC); NodeBuilder Bldr(Pred, Dst, BC);
for (unsigned i = 0, e = EndFunctionCheckers.size(); i != e; ++i) { for (unsigned i = 0, e = EndFunctionCheckers.size(); i != e; ++i) {
@ -467,7 +467,7 @@ bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) {
} }
/// \brief Run checkers for region changes. /// \brief Run checkers for region changes.
ProgramStateRef ProgramStateRef
CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
const InvalidatedSymbols *invalidated, const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> ExplicitRegions,
@ -478,7 +478,7 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
// bail out. // bail out.
if (!state) if (!state)
return nullptr; return nullptr;
state = RegionChangesCheckers[i].CheckFn(state, invalidated, state = RegionChangesCheckers[i].CheckFn(state, invalidated,
ExplicitRegions, Regions, Call); ExplicitRegions, Regions, Call);
} }
return state; return state;
@ -506,7 +506,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
} }
/// \brief Run checkers for handling assumptions on symbolic values. /// \brief Run checkers for handling assumptions on symbolic values.
ProgramStateRef ProgramStateRef
CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
SVal Cond, bool Assumption) { SVal Cond, bool Assumption) {
for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) { for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
@ -558,7 +558,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
#endif #endif
} }
} }
// If none of the checkers evaluated the call, ask ExprEngine to handle it. // If none of the checkers evaluated the call, ask ExprEngine to handle it.
if (!anyEvaluated) { if (!anyEvaluated) {
NodeBuilder B(Pred, Dst, Eng.getBuilderContext()); NodeBuilder B(Pred, Dst, Eng.getBuilderContext());

View File

@ -94,7 +94,7 @@ void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
} }
} }
void CheckerRegistry::initializeManager(CheckerManager &checkerMgr, void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
SmallVectorImpl<CheckerOptInfo> &opts) const { SmallVectorImpl<CheckerOptInfo> &opts) const {
// Sort checkers for efficient collection. // Sort checkers for efficient collection.
std::sort(Checkers.begin(), Checkers.end(), checkerNameLT); std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);

View File

@ -26,7 +26,7 @@ static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
} }
ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State, ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State,
SymbolRef Sym) { SymbolRef Sym) {
QualType Ty = Sym->getType(); QualType Ty = Sym->getType();
DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym) DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym)
: nonloc::SymbolVal(Sym); : nonloc::SymbolVal(Sym);

View File

@ -271,7 +271,7 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
unsigned Steps, unsigned Steps,
ProgramStateRef InitState, ProgramStateRef InitState,
ExplodedNodeSet &Dst) { ExplodedNodeSet &Dst) {
bool DidNotFinish = ExecuteWorkList(L, Steps, InitState); bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
for (ExplodedGraph::eop_iterator I = G.eop_begin(), E = G.eop_end(); I != E; for (ExplodedGraph::eop_iterator I = G.eop_begin(), E = G.eop_end(); I != E;
@ -386,7 +386,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
} }
return; return;
} }
case Stmt::DoStmtClass: case Stmt::DoStmtClass:
HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred); HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
return; return;
@ -456,7 +456,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
Pred->State, Pred); Pred->State, Pred);
} }
void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term, void CoreEngine::HandleBranch(const Stmt *Cond, const Stmt *Term,
const CFGBlock * B, ExplodedNode *Pred) { const CFGBlock * B, ExplodedNode *Pred) {
assert(B->succ_size() == 2); assert(B->succ_size() == 2);
NodeBuilderContext Ctx(*this, B, Pred); NodeBuilderContext Ctx(*this, B, Pred);
@ -491,7 +491,7 @@ void CoreEngine::HandleStaticInit(const DeclStmt *DS, const CFGBlock *B,
} }
void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx, void CoreEngine::HandlePostStmt(const CFGBlock *B, unsigned StmtIdx,
ExplodedNode *Pred) { ExplodedNode *Pred) {
assert(B); assert(B);
assert(!B->empty()); assert(!B->empty());

View File

@ -97,9 +97,9 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
const ReturnStmt *RS = cast<ReturnStmt>(S); const ReturnStmt *RS = cast<ReturnStmt>(S);
if (const Expr *RE = RS->getRetValue()) if (const Expr *RE = RS->getRetValue())
return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder); return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
return UndefinedVal(); return UndefinedVal();
} }
// Handle all other Stmt* using a lookup. // Handle all other Stmt* using a lookup.
default: default:
return lookupExpr(EnvironmentEntry(S, LCtx)); return lookupExpr(EnvironmentEntry(S, LCtx));
@ -194,16 +194,16 @@ void Environment::print(raw_ostream &Out, const char *NL,
for (Environment::iterator I = begin(), E = end(); I != E; ++I) { for (Environment::iterator I = begin(), E = end(); I != E; ++I) {
const EnvironmentEntry &En = I.getKey(); const EnvironmentEntry &En = I.getKey();
if (isFirst) { if (isFirst) {
Out << NL << NL Out << NL << NL
<< "Expressions:" << "Expressions:"
<< NL; << NL;
isFirst = false; isFirst = false;
} else { } else {
Out << NL; Out << NL;
} }
const Stmt *S = En.getStmt(); const Stmt *S = En.getStmt();
assert(S != nullptr && "Expected non-null Stmt"); assert(S != nullptr && "Expected non-null Stmt");

View File

@ -90,8 +90,8 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// (7) The LocationContext is the same as the predecessor. // (7) The LocationContext is the same as the predecessor.
// (8) Expressions that are *not* lvalue expressions. // (8) Expressions that are *not* lvalue expressions.
// (9) The PostStmt isn't for a non-consumed Stmt or Expr. // (9) The PostStmt isn't for a non-consumed Stmt or Expr.
// (10) The successor is neither a CallExpr StmtPoint nor a CallEnter or // (10) The successor is neither a CallExpr StmtPoint nor a CallEnter or
// PreImplicitCall (so that we would be able to find it when retrying a // PreImplicitCall (so that we would be able to find it when retrying a
// call with no inlining). // call with no inlining).
// FIXME: It may be safe to reclaim PreCall and PostCall nodes as well. // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well.
@ -102,7 +102,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
const ExplodedNode *pred = *(node->pred_begin()); const ExplodedNode *pred = *(node->pred_begin());
if (pred->succ_size() != 1) if (pred->succ_size() != 1)
return false; return false;
const ExplodedNode *succ = *(node->succ_begin()); const ExplodedNode *succ = *(node->succ_begin());
if (succ->pred_size() != 1) if (succ->pred_size() != 1)
return false; return false;
@ -123,7 +123,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// Conditions 5, 6, and 7. // Conditions 5, 6, and 7.
ProgramStateRef state = node->getState(); ProgramStateRef state = node->getState();
ProgramStateRef pred_state = pred->getState(); ProgramStateRef pred_state = pred->getState();
if (state->store != pred_state->store || state->GDM != pred_state->GDM || if (state->store != pred_state->store || state->GDM != pred_state->GDM ||
progPoint.getLocationContext() != pred->getLocationContext()) progPoint.getLocationContext() != pred->getLocationContext())
return false; return false;
@ -174,7 +174,7 @@ void ExplodedGraph::collectNode(ExplodedNode *node) {
FreeNodes.push_back(node); FreeNodes.push_back(node);
Nodes.RemoveNode(node); Nodes.RemoveNode(node);
--NumNodes; --NumNodes;
node->~ExplodedNode(); node->~ExplodedNode();
} }
void ExplodedGraph::reclaimRecentlyAllocatedNodes() { void ExplodedGraph::reclaimRecentlyAllocatedNodes() {

View File

@ -174,7 +174,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
} }
} }
} }
return state; return state;
} }
@ -265,7 +265,7 @@ bool ExprEngine::wantsRegionChangeUpdate(ProgramStateRef state) {
return getCheckerManager().wantsRegionChangeUpdate(state); return getCheckerManager().wantsRegionChangeUpdate(state);
} }
ProgramStateRef ProgramStateRef
ExprEngine::processRegionChanges(ProgramStateRef state, ExprEngine::processRegionChanges(ProgramStateRef state,
const InvalidatedSymbols *invalidated, const InvalidatedSymbols *invalidated,
ArrayRef<const MemRegion *> Explicits, ArrayRef<const MemRegion *> Explicits,
@ -315,7 +315,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
const CFGStmt S, const CFGStmt S,
const ExplodedNode *Pred, const ExplodedNode *Pred,
const LocationContext *LC) { const LocationContext *LC) {
// Are we never purging state values? // Are we never purging state values?
if (AMgr.options.AnalysisPurgeOpt == PurgeNone) if (AMgr.options.AnalysisPurgeOpt == PurgeNone)
return false; return false;
@ -327,7 +327,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
// Is this on a non-expression? // Is this on a non-expression?
if (!isa<Expr>(S.getStmt())) if (!isa<Expr>(S.getStmt()))
return true; return true;
// Run before processing a call. // Run before processing a call.
if (CallEvent::isCallStmt(S.getStmt())) if (CallEvent::isCallStmt(S.getStmt()))
return true; return true;
@ -512,7 +512,7 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init,
assert(Tmp.size() == 1 && "have not generated any new nodes yet"); assert(Tmp.size() == 1 && "have not generated any new nodes yet");
assert(*Tmp.begin() == Pred && "have not generated any new nodes yet"); assert(*Tmp.begin() == Pred && "have not generated any new nodes yet");
Tmp.clear(); Tmp.clear();
PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame); PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP); evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
} }
@ -775,7 +775,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Engine.addAbortedBlock(node, currBldrCtx->getBlock()); Engine.addAbortedBlock(node, currBldrCtx->getBlock());
break; break;
} }
case Stmt::ParenExprClass: case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled."); llvm_unreachable("ParenExprs already handled.");
case Stmt::GenericSelectionExprClass: case Stmt::GenericSelectionExprClass:
@ -966,7 +966,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ExplodedNodeSet preVisit; ExplodedNodeSet preVisit;
getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this); getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
ExplodedNodeSet Tmp; ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx); StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx);
@ -974,7 +974,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
QualType resultType = Ex->getType(); QualType resultType = Ex->getType();
for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end(); for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end();
it != et; ++it) { it != et; ++it) {
ExplodedNode *N = *it; ExplodedNode *N = *it;
const LocationContext *LCtx = N->getLocationContext(); const LocationContext *LCtx = N->getLocationContext();
SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, SVal result = svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
@ -983,10 +983,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result); ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result);
Bldr2.generateNode(S, N, state); Bldr2.generateNode(S, N, state);
} }
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
Bldr.addNodes(Dst); Bldr.addNodes(Dst);
break; break;
} }
case Stmt::ArraySubscriptExprClass: case Stmt::ArraySubscriptExprClass:
@ -1031,7 +1031,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
} }
Bldr.takeNodes(Pred); Bldr.takeNodes(Pred);
if (AMgr.options.eagerlyAssumeBinOpBifurcation && if (AMgr.options.eagerlyAssumeBinOpBifurcation &&
(B->isRelationalOp() || B->isEqualityOp())) { (B->isRelationalOp() || B->isEqualityOp())) {
ExplodedNodeSet Tmp; ExplodedNodeSet Tmp;
@ -1076,7 +1076,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst); Bldr.addNodes(Dst);
break; break;
} }
case Stmt::CXXCatchStmtClass: { case Stmt::CXXCatchStmtClass: {
Bldr.takeNodes(Pred); Bldr.takeNodes(Pred);
VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst); VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst);
@ -1085,7 +1085,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
} }
case Stmt::CXXTemporaryObjectExprClass: case Stmt::CXXTemporaryObjectExprClass:
case Stmt::CXXConstructExprClass: { case Stmt::CXXConstructExprClass: {
Bldr.takeNodes(Pred); Bldr.takeNodes(Pred);
VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst); VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst);
Bldr.addNodes(Dst); Bldr.addNodes(Dst);
@ -1107,7 +1107,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S); const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this); getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
for (ExplodedNodeSet::iterator i = PreVisit.begin(), for (ExplodedNodeSet::iterator i = PreVisit.begin(),
e = PreVisit.end(); i != e ; ++i) e = PreVisit.end(); i != e ; ++i)
VisitCXXDeleteExpr(CDE, *i, Dst); VisitCXXDeleteExpr(CDE, *i, Dst);
@ -1173,18 +1173,18 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::CXXDynamicCastExprClass: case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXReinterpretCastExprClass: case Stmt::CXXReinterpretCastExprClass:
case Stmt::CXXConstCastExprClass: case Stmt::CXXConstCastExprClass:
case Stmt::CXXFunctionalCastExprClass: case Stmt::CXXFunctionalCastExprClass:
case Stmt::ObjCBridgedCastExprClass: { case Stmt::ObjCBridgedCastExprClass: {
Bldr.takeNodes(Pred); Bldr.takeNodes(Pred);
const CastExpr *C = cast<CastExpr>(S); const CastExpr *C = cast<CastExpr>(S);
// Handle the previsit checks. // Handle the previsit checks.
ExplodedNodeSet dstPrevisit; ExplodedNodeSet dstPrevisit;
getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this); getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this);
// Handle the expression itself. // Handle the expression itself.
ExplodedNodeSet dstExpr; ExplodedNodeSet dstExpr;
for (ExplodedNodeSet::iterator i = dstPrevisit.begin(), for (ExplodedNodeSet::iterator i = dstPrevisit.begin(),
e = dstPrevisit.end(); i != e ; ++i) { e = dstPrevisit.end(); i != e ; ++i) {
VisitCast(C, C->getSubExpr(), *i, dstExpr); VisitCast(C, C->getSubExpr(), *i, dstExpr);
} }
@ -1201,7 +1201,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.addNodes(Dst); Bldr.addNodes(Dst);
break; break;
} }
case Stmt::InitListExprClass: case Stmt::InitListExprClass:
Bldr.takeNodes(Pred); Bldr.takeNodes(Pred);
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst); VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
@ -1296,7 +1296,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
Bldr.takeNodes(Pred); Bldr.takeNodes(Pred);
ProgramStateRef state = Pred->getState(); ProgramStateRef state = Pred->getState();
const PseudoObjectExpr *PE = cast<PseudoObjectExpr>(S); const PseudoObjectExpr *PE = cast<PseudoObjectExpr>(S);
if (const Expr *Result = PE->getResultExpr()) { if (const Expr *Result = PE->getResultExpr()) {
SVal V = state->getSVal(Result, Pred->getLocationContext()); SVal V = state->getSVal(Result, Pred->getLocationContext());
Bldr.generateNode(S, Pred, Bldr.generateNode(S, Pred,
state->BindExpr(S, Pred->getLocationContext(), V)); state->BindExpr(S, Pred->getLocationContext(), V));
@ -1377,7 +1377,7 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
/// Block entrance. (Update counters). /// Block entrance. (Update counters).
void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
NodeBuilderWithSinks &nodeBuilder, NodeBuilderWithSinks &nodeBuilder,
ExplodedNode *Pred) { ExplodedNode *Pred) {
PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext()); PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
@ -1585,7 +1585,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term,
} }
} }
} }
// If the condition is still unknown, give up. // If the condition is still unknown, give up.
if (X.isUnknownOrUndef()) { if (X.isUnknownOrUndef()) {
builder.generateNode(PrevState, true, PredI); builder.generateNode(PrevState, true, PredI);
@ -1752,7 +1752,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
DefinedOrUnknownSVal CondV = CondV_untested.castAs<DefinedOrUnknownSVal>(); DefinedOrUnknownSVal CondV = CondV_untested.castAs<DefinedOrUnknownSVal>();
ProgramStateRef DefaultSt = state; ProgramStateRef DefaultSt = state;
iterator I = builder.begin(), EI = builder.end(); iterator I = builder.begin(), EI = builder.end();
bool defaultIsFeasible = I == EI; bool defaultIsFeasible = I == EI;
@ -1760,7 +1760,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
// Successor may be pruned out during CFG construction. // Successor may be pruned out during CFG construction.
if (!I.getBlock()) if (!I.getBlock())
continue; continue;
const CaseStmt *Case = I.getCase(); const CaseStmt *Case = I.getCase();
// Evaluate the LHS of the case value. // Evaluate the LHS of the case value.
@ -1851,7 +1851,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// C permits "extern void v", and if you cast the address to a valid type, // C permits "extern void v", and if you cast the address to a valid type,
// you can even do things with it. We simply pretend // you can even do things with it. We simply pretend
assert(Ex->isGLValue() || VD->getType()->isVoidType()); assert(Ex->isGLValue() || VD->getType()->isVoidType());
SVal V = state->getLValue(VD, Pred->getLocationContext()); SVal V = state->getLValue(VD, Pred->getLocationContext());
@ -1902,7 +1902,7 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A,
const Expr *Base = A->getBase()->IgnoreParens(); const Expr *Base = A->getBase()->IgnoreParens();
const Expr *Idx = A->getIdx()->IgnoreParens(); const Expr *Idx = A->getIdx()->IgnoreParens();
ExplodedNodeSet checkerPreStmt; ExplodedNodeSet checkerPreStmt;
getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this); getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
@ -2066,14 +2066,14 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
return State; return State;
} }
ProgramStateRef ProgramStateRef
ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State, ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
const InvalidatedSymbols *Invalidated, const InvalidatedSymbols *Invalidated,
ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions, ArrayRef<const MemRegion *> Regions,
const CallEvent *Call, const CallEvent *Call,
RegionAndSymbolInvalidationTraits &ITraits) { RegionAndSymbolInvalidationTraits &ITraits) {
if (!Invalidated || Invalidated->empty()) if (!Invalidated || Invalidated->empty())
return State; return State;
@ -2084,7 +2084,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
PSK_EscapeOther, PSK_EscapeOther,
&ITraits); &ITraits);
// If the symbols were invalidated by a call, we want to find out which ones // If the symbols were invalidated by a call, we want to find out which ones
// were invalidated directly due to being arguments to the call. // were invalidated directly due to being arguments to the call.
InvalidatedSymbols SymbolsDirectlyInvalidated; InvalidatedSymbols SymbolsDirectlyInvalidated;
for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(), for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(),
@ -2144,13 +2144,13 @@ void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE,
Bldr.generateNode(L, state, Pred); Bldr.generateNode(L, state, Pred);
return; return;
} }
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
I!=E; ++I) { I!=E; ++I) {
ExplodedNode *PredI = *I; ExplodedNode *PredI = *I;
ProgramStateRef state = PredI->getState(); ProgramStateRef state = PredI->getState();
state = processPointerEscapedOnBind(state, location, Val); state = processPointerEscapedOnBind(state, location, Val);
// When binding the value, pass on the hint that this is a initialization. // When binding the value, pass on the hint that this is a initialization.
@ -2303,7 +2303,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst,
// "p = 0" is not noted as "Null pointer value stored to 'p'" but // "p = 0" is not noted as "Null pointer value stored to 'p'" but
// instead "int *p" is noted as // instead "int *p" is noted as
// "Variable 'p' initialized to a null pointer value" // "Variable 'p' initialized to a null pointer value"
static SimpleProgramPointTag tag(TagProviderName, "Location"); static SimpleProgramPointTag tag(TagProviderName, "Location");
Bldr.generateNode(NodeEx, Pred, state, &tag); Bldr.generateNode(NodeEx, Pred, state, &tag);
} }
@ -2328,7 +2328,7 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
ExplodedNodeSet &Src, ExplodedNodeSet &Src,
const Expr *Ex) { const Expr *Ex) {
StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx); StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
ExplodedNode *Pred = *I; ExplodedNode *Pred = *I;
// Test if the previous node was as the same expression. This can happen // Test if the previous node was as the same expression. This can happen
@ -2351,7 +2351,7 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
// First assume that the condition is true. // First assume that the condition is true.
if (StateTrue) { if (StateTrue) {
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val); StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
Bldr.generateNode(Ex, Pred, StateTrue, tags.first); Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
} }
@ -2643,10 +2643,10 @@ struct DOTGraphTraits<ExplodedNode*> :
<< " NodeID: " << (const void*) N << "\\|"; << " NodeID: " << (const void*) N << "\\|";
state->printDOT(Out); state->printDOT(Out);
Out << "\\l"; Out << "\\l";
if (const ProgramPointTag *tag = Loc.getTag()) { if (const ProgramPointTag *tag = Loc.getTag()) {
Out << "\\|Tag: " << tag->getTagDescription(); Out << "\\|Tag: " << tag->getTagDescription();
Out << "\\l"; Out << "\\l";
} }
return Out.str(); return Out.str();

View File

@ -25,23 +25,23 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
Expr *LHS = B->getLHS()->IgnoreParens(); Expr *LHS = B->getLHS()->IgnoreParens();
Expr *RHS = B->getRHS()->IgnoreParens(); Expr *RHS = B->getRHS()->IgnoreParens();
// FIXME: Prechecks eventually go in ::Visit(). // FIXME: Prechecks eventually go in ::Visit().
ExplodedNodeSet CheckedSet; ExplodedNodeSet CheckedSet;
ExplodedNodeSet Tmp2; ExplodedNodeSet Tmp2;
getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, B, *this); getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, B, *this);
// With both the LHS and RHS evaluated, process the operation itself. // With both the LHS and RHS evaluated, process the operation itself.
for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end(); for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end();
it != ei; ++it) { it != ei; ++it) {
ProgramStateRef state = (*it)->getState(); ProgramStateRef state = (*it)->getState();
const LocationContext *LCtx = (*it)->getLocationContext(); const LocationContext *LCtx = (*it)->getLocationContext();
SVal LeftV = state->getSVal(LHS, LCtx); SVal LeftV = state->getSVal(LHS, LCtx);
SVal RightV = state->getSVal(RHS, LCtx); SVal RightV = state->getSVal(RHS, LCtx);
BinaryOperator::Opcode Op = B->getOpcode(); BinaryOperator::Opcode Op = B->getOpcode();
if (Op == BO_Assign) { if (Op == BO_Assign) {
// EXPERIMENTAL: "Conjured" symbols. // EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs. // FIXME: Handle structs.
@ -57,7 +57,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
LeftV, RightV); LeftV, RightV);
continue; continue;
} }
if (!B->isAssignmentOp()) { if (!B->isAssignmentOp()) {
StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx); StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx);
@ -90,19 +90,19 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// Process non-assignments except commas or short-circuited // Process non-assignments except commas or short-circuited
// logical expressions (LAnd and LOr). // logical expressions (LAnd and LOr).
SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType()); SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
if (Result.isUnknown()) { if (Result.isUnknown()) {
Bldr.generateNode(B, *it, state); Bldr.generateNode(B, *it, state);
continue; continue;
} }
state = state->BindExpr(B, LCtx, Result); state = state->BindExpr(B, LCtx, Result);
Bldr.generateNode(B, *it, state); Bldr.generateNode(B, *it, state);
continue; continue;
} }
assert (B->isCompoundAssignmentOp()); assert (B->isCompoundAssignmentOp());
switch (Op) { switch (Op) {
default: default:
llvm_unreachable("Invalid opcode for compound assignment."); llvm_unreachable("Invalid opcode for compound assignment.");
@ -117,43 +117,43 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
case BO_XorAssign: Op = BO_Xor; break; case BO_XorAssign: Op = BO_Xor; break;
case BO_OrAssign: Op = BO_Or; break; case BO_OrAssign: Op = BO_Or; break;
} }
// Perform a load (the LHS). This performs the checks for // Perform a load (the LHS). This performs the checks for
// null dereferences, and so on. // null dereferences, and so on.
ExplodedNodeSet Tmp; ExplodedNodeSet Tmp;
SVal location = LeftV; SVal location = LeftV;
evalLoad(Tmp, B, LHS, *it, state, location); evalLoad(Tmp, B, LHS, *it, state, location);
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E;
++I) { ++I) {
state = (*I)->getState(); state = (*I)->getState();
const LocationContext *LCtx = (*I)->getLocationContext(); const LocationContext *LCtx = (*I)->getLocationContext();
SVal V = state->getSVal(LHS, LCtx); SVal V = state->getSVal(LHS, LCtx);
// Get the computation type. // Get the computation type.
QualType CTy = QualType CTy =
cast<CompoundAssignOperator>(B)->getComputationResultType(); cast<CompoundAssignOperator>(B)->getComputationResultType();
CTy = getContext().getCanonicalType(CTy); CTy = getContext().getCanonicalType(CTy);
QualType CLHSTy = QualType CLHSTy =
cast<CompoundAssignOperator>(B)->getComputationLHSType(); cast<CompoundAssignOperator>(B)->getComputationLHSType();
CLHSTy = getContext().getCanonicalType(CLHSTy); CLHSTy = getContext().getCanonicalType(CLHSTy);
QualType LTy = getContext().getCanonicalType(LHS->getType()); QualType LTy = getContext().getCanonicalType(LHS->getType());
// Promote LHS. // Promote LHS.
V = svalBuilder.evalCast(V, CLHSTy, LTy); V = svalBuilder.evalCast(V, CLHSTy, LTy);
// Compute the result of the operation. // Compute the result of the operation.
SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy), SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
B->getType(), CTy); B->getType(), CTy);
// EXPERIMENTAL: "Conjured" symbols. // EXPERIMENTAL: "Conjured" symbols.
// FIXME: Handle structs. // FIXME: Handle structs.
SVal LHSVal; SVal LHSVal;
if (Result.isUnknown()) { if (Result.isUnknown()) {
// The symbolic value is actually for the type of the left-hand side // The symbolic value is actually for the type of the left-hand side
// expression, not the computation type, as this is the value the // expression, not the computation type, as this is the value the
@ -168,42 +168,42 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
// computation type. // computation type.
LHSVal = svalBuilder.evalCast(Result, LTy, CTy); LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
} }
// In C++, assignment and compound assignment operators return an // In C++, assignment and compound assignment operators return an
// lvalue. // lvalue.
if (B->isGLValue()) if (B->isGLValue())
state = state->BindExpr(B, LCtx, location); state = state->BindExpr(B, LCtx, location);
else else
state = state->BindExpr(B, LCtx, Result); state = state->BindExpr(B, LCtx, Result);
evalStore(Tmp2, B, LHS, *I, state, location, LHSVal); evalStore(Tmp2, B, LHS, *I, state, location, LHSVal);
} }
} }
// FIXME: postvisits eventually go in ::Visit() // FIXME: postvisits eventually go in ::Visit()
getCheckerManager().runCheckersForPostStmt(Dst, Tmp2, B, *this); getCheckerManager().runCheckersForPostStmt(Dst, Tmp2, B, *this);
} }
void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
ExplodedNodeSet &Dst) { ExplodedNodeSet &Dst) {
CanQualType T = getContext().getCanonicalType(BE->getType()); CanQualType T = getContext().getCanonicalType(BE->getType());
// Get the value of the block itself. // Get the value of the block itself.
SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T, SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
Pred->getLocationContext(), Pred->getLocationContext(),
currBldrCtx->blockCount()); currBldrCtx->blockCount());
ProgramStateRef State = Pred->getState(); ProgramStateRef State = Pred->getState();
// If we created a new MemRegion for the block, we should explicitly bind // If we created a new MemRegion for the block, we should explicitly bind
// the captured variables. // the captured variables.
if (const BlockDataRegion *BDR = if (const BlockDataRegion *BDR =
dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) { dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(), BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(),
E = BDR->referenced_vars_end(); E = BDR->referenced_vars_end();
for (; I != E; ++I) { for (; I != E; ++I) {
const MemRegion *capturedR = I.getCapturedRegion(); const MemRegion *capturedR = I.getCapturedRegion();
const MemRegion *originalR = I.getOriginalRegion(); const MemRegion *originalR = I.getOriginalRegion();
@ -213,7 +213,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
} }
} }
} }
ExplodedNodeSet Tmp; ExplodedNodeSet Tmp;
StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
Bldr.generateNode(BE, Pred, Bldr.generateNode(BE, Pred,
@ -224,12 +224,12 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this);
} }
void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNode *Pred, ExplodedNodeSet &Dst) {
ExplodedNodeSet dstPreStmt; ExplodedNodeSet dstPreStmt;
getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this); getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this);
if (CastE->getCastKind() == CK_LValueToRValue) { if (CastE->getCastKind() == CK_LValueToRValue) {
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I!=E; ++I) { I!=E; ++I) {
@ -240,18 +240,18 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
} }
return; return;
} }
// All other casts. // All other casts.
QualType T = CastE->getType(); QualType T = CastE->getType();
QualType ExTy = Ex->getType(); QualType ExTy = Ex->getType();
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
T = ExCast->getTypeAsWritten(); T = ExCast->getTypeAsWritten();
StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx); StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx);
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
I != E; ++I) { I != E; ++I) {
Pred = *I; Pred = *I;
ProgramStateRef state = Pred->getState(); ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext(); const LocationContext *LCtx = Pred->getLocationContext();
@ -316,8 +316,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
case CK_IntegralComplexToFloatingComplex: case CK_IntegralComplexToFloatingComplex:
case CK_CPointerToObjCPointerCast: case CK_CPointerToObjCPointerCast:
case CK_BlockPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast:
case CK_AnyPointerToBlockPointerCast: case CK_AnyPointerToBlockPointerCast:
case CK_ObjCObjectLValueCast: case CK_ObjCObjectLValueCast:
case CK_ZeroToOCLEvent: case CK_ZeroToOCLEvent:
case CK_LValueBitCast: { case CK_LValueBitCast: {
// Delegate to SValBuilder to process. // Delegate to SValBuilder to process.
@ -371,7 +371,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType, svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType,
currBldrCtx->blockCount()); currBldrCtx->blockCount());
state = state->BindExpr(CastE, LCtx, NewSym); state = state->BindExpr(CastE, LCtx, NewSym);
} else } else
// Else, bind to the derived region value. // Else, bind to the derived region value.
state = state->BindExpr(CastE, LCtx, val); state = state->BindExpr(CastE, LCtx, val);
} }
@ -417,7 +417,7 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
const Expr *Init = CL->getInitializer(); const Expr *Init = CL->getInitializer();
SVal V = State->getSVal(CL->getInitializer(), LCtx); SVal V = State->getSVal(CL->getInitializer(), LCtx);
if (isa<CXXConstructExpr>(Init)) { if (isa<CXXConstructExpr>(Init)) {
// No work needed. Just pass the value up to this expression. // No work needed. Just pass the value up to this expression.
} else { } else {
@ -450,11 +450,11 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
Dst.insert(Pred); Dst.insert(Pred);
return; return;
} }
// FIXME: all pre/post visits should eventually be handled by ::Visit(). // FIXME: all pre/post visits should eventually be handled by ::Visit().
ExplodedNodeSet dstPreVisit; ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
ExplodedNodeSet dstEvaluated; ExplodedNodeSet dstEvaluated;
StmtNodeBuilder B(dstPreVisit, dstEvaluated, *currBldrCtx); StmtNodeBuilder B(dstPreVisit, dstEvaluated, *currBldrCtx);
for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end();
@ -485,7 +485,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
assert(InitVal.getAs<nonloc::LazyCompoundVal>()); assert(InitVal.getAs<nonloc::LazyCompoundVal>());
} }
} }
// Recover some path-sensitivity if a scalar value evaluated to // Recover some path-sensitivity if a scalar value evaluated to
// UnknownVal. // UnknownVal.
if (InitVal.isUnknown()) { if (InitVal.isUnknown()) {
@ -596,7 +596,7 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
(T->isArrayType() || T->isRecordType() || T->isVectorType() || (T->isArrayType() || T->isRecordType() || T->isVectorType() ||
T->isAnyComplexType())) { T->isAnyComplexType())) {
llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList(); llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList();
// Handle base case where the initializer has no elements. // Handle base case where the initializer has no elements.
// e.g: static int* myArray[] = {}; // e.g: static int* myArray[] = {};
if (NumInitElements == 0) { if (NumInitElements == 0) {
@ -604,13 +604,13 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V)); B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
return; return;
} }
for (InitListExpr::const_reverse_iterator it = IE->rbegin(), for (InitListExpr::const_reverse_iterator it = IE->rbegin(),
ei = IE->rend(); it != ei; ++it) { ei = IE->rend(); it != ei; ++it) {
SVal V = state->getSVal(cast<Expr>(*it), LCtx); SVal V = state->getSVal(cast<Expr>(*it), LCtx);
vals = getBasicVals().consVals(V, vals); vals = getBasicVals().consVals(V, vals);
} }
B.generateNode(IE, Pred, B.generateNode(IE, Pred,
state->BindExpr(IE, LCtx, state->BindExpr(IE, LCtx,
svalBuilder.makeCompoundVal(T, vals))); svalBuilder.makeCompoundVal(T, vals)));
@ -632,7 +632,7 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
} }
void ExprEngine::VisitGuardedExpr(const Expr *Ex, void ExprEngine::VisitGuardedExpr(const Expr *Ex,
const Expr *L, const Expr *L,
const Expr *R, const Expr *R,
ExplodedNode *Pred, ExplodedNode *Pred,
ExplodedNodeSet &Dst) { ExplodedNodeSet &Dst) {
@ -692,7 +692,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
} }
void ExprEngine:: void ExprEngine::
VisitOffsetOfExpr(const OffsetOfExpr *OOE, VisitOffsetOfExpr(const OffsetOfExpr *OOE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNode *Pred, ExplodedNodeSet &Dst) {
StmtNodeBuilder B(Pred, Dst, *currBldrCtx); StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
APSInt IV; APSInt IV;
@ -728,7 +728,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
if (Ex->getKind() == UETT_SizeOf) { if (Ex->getKind() == UETT_SizeOf) {
if (!T->isIncompleteType() && !T->isConstantSizeType()) { if (!T->isIncompleteType() && !T->isConstantSizeType()) {
assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
// FIXME: Add support for VLA type arguments and VLA expressions. // FIXME: Add support for VLA type arguments and VLA expressions.
// When that happens, we should probably refactor VLASizeChecker's code. // When that happens, we should probably refactor VLASizeChecker's code.
continue; continue;
@ -739,10 +739,10 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
continue; continue;
} }
} }
APSInt Value = Ex->EvaluateKnownConstInt(getContext()); APSInt Value = Ex->EvaluateKnownConstInt(getContext());
CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
ProgramStateRef state = (*I)->getState(); ProgramStateRef state = (*I)->getState();
state = state->BindExpr(Ex, (*I)->getLocationContext(), state = state->BindExpr(Ex, (*I)->getLocationContext(),
svalBuilder.makeIntVal(amt.getQuantity(), svalBuilder.makeIntVal(amt.getQuantity(),
@ -753,7 +753,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this);
} }
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
ExplodedNode *Pred, ExplodedNode *Pred,
ExplodedNodeSet &Dst) { ExplodedNodeSet &Dst) {
// FIXME: Prechecks eventually go in ::Visit(). // FIXME: Prechecks eventually go in ::Visit().
@ -775,13 +775,13 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
} }
case UO_Real: { case UO_Real: {
const Expr *Ex = U->getSubExpr()->IgnoreParens(); const Expr *Ex = U->getSubExpr()->IgnoreParens();
// FIXME: We don't have complex SValues yet. // FIXME: We don't have complex SValues yet.
if (Ex->getType()->isAnyComplexType()) { if (Ex->getType()->isAnyComplexType()) {
// Just report "Unknown." // Just report "Unknown."
break; break;
} }
// For all other types, UO_Real is an identity operation. // For all other types, UO_Real is an identity operation.
assert (U->getType() == Ex->getType()); assert (U->getType() == Ex->getType());
ProgramStateRef state = (*I)->getState(); ProgramStateRef state = (*I)->getState();
@ -790,8 +790,8 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
state->getSVal(Ex, LCtx))); state->getSVal(Ex, LCtx)));
break; break;
} }
case UO_Imag: { case UO_Imag: {
const Expr *Ex = U->getSubExpr()->IgnoreParens(); const Expr *Ex = U->getSubExpr()->IgnoreParens();
// FIXME: We don't have complex SValues yet. // FIXME: We don't have complex SValues yet.
if (Ex->getType()->isAnyComplexType()) { if (Ex->getType()->isAnyComplexType()) {
@ -805,7 +805,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, X)); Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, X));
break; break;
} }
case UO_Plus: case UO_Plus:
assert(!U->isGLValue()); assert(!U->isGLValue());
// FALL-THROUGH. // FALL-THROUGH.
@ -818,7 +818,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
// Unary "+" is a no-op, similar to a parentheses. We still have places // Unary "+" is a no-op, similar to a parentheses. We still have places
// where it may be a block-level expression, so we need to // where it may be a block-level expression, so we need to
// generate an extra node that just propagates the value of the // generate an extra node that just propagates the value of the
// subexpression. // subexpression.
const Expr *Ex = U->getSubExpr()->IgnoreParens(); const Expr *Ex = U->getSubExpr()->IgnoreParens();
ProgramStateRef state = (*I)->getState(); ProgramStateRef state = (*I)->getState();
const LocationContext *LCtx = (*I)->getLocationContext(); const LocationContext *LCtx = (*I)->getLocationContext();
@ -826,7 +826,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
state->getSVal(Ex, LCtx))); state->getSVal(Ex, LCtx)));
break; break;
} }
case UO_LNot: case UO_LNot:
case UO_Minus: case UO_Minus:
case UO_Not: { case UO_Not: {
@ -834,15 +834,15 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
const Expr *Ex = U->getSubExpr()->IgnoreParens(); const Expr *Ex = U->getSubExpr()->IgnoreParens();
ProgramStateRef state = (*I)->getState(); ProgramStateRef state = (*I)->getState();
const LocationContext *LCtx = (*I)->getLocationContext(); const LocationContext *LCtx = (*I)->getLocationContext();
// Get the value of the subexpression. // Get the value of the subexpression.
SVal V = state->getSVal(Ex, LCtx); SVal V = state->getSVal(Ex, LCtx);
if (V.isUnknownOrUndef()) { if (V.isUnknownOrUndef()) {
Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V)); Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V));
break; break;
} }
switch (U->getOpcode()) { switch (U->getOpcode()) {
default: default:
llvm_unreachable("Invalid Opcode."); llvm_unreachable("Invalid Opcode.");
@ -859,7 +859,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
// //
// Note: technically we do "E == 0", but this is the same in the // Note: technically we do "E == 0", but this is the same in the
// transfer functions as "0 == E". // transfer functions as "0 == E".
SVal Result; SVal Result;
if (Optional<Loc> LV = V.getAs<Loc>()) { if (Optional<Loc> LV = V.getAs<Loc>()) {
Loc X = svalBuilder.makeNull(); Loc X = svalBuilder.makeNull();
Result = evalBinOp(state, BO_EQ, *LV, X, U->getType()); Result = evalBinOp(state, BO_EQ, *LV, X, U->getType());
@ -872,8 +872,8 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
Result = evalBinOp(state, BO_EQ, V.castAs<NonLoc>(), X, Result = evalBinOp(state, BO_EQ, V.castAs<NonLoc>(), X,
U->getType()); U->getType());
} }
state = state->BindExpr(U, LCtx, Result); state = state->BindExpr(U, LCtx, Result);
break; break;
} }
Bldr.generateNode(U, *I, state); Bldr.generateNode(U, *I, state);
@ -891,81 +891,81 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
// Handle ++ and -- (both pre- and post-increment). // Handle ++ and -- (both pre- and post-increment).
assert (U->isIncrementDecrementOp()); assert (U->isIncrementDecrementOp());
const Expr *Ex = U->getSubExpr()->IgnoreParens(); const Expr *Ex = U->getSubExpr()->IgnoreParens();
const LocationContext *LCtx = Pred->getLocationContext(); const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef state = Pred->getState(); ProgramStateRef state = Pred->getState();
SVal loc = state->getSVal(Ex, LCtx); SVal loc = state->getSVal(Ex, LCtx);
// Perform a load. // Perform a load.
ExplodedNodeSet Tmp; ExplodedNodeSet Tmp;
evalLoad(Tmp, U, Ex, Pred, state, loc); evalLoad(Tmp, U, Ex, Pred, state, loc);
ExplodedNodeSet Dst2; ExplodedNodeSet Dst2;
StmtNodeBuilder Bldr(Tmp, Dst2, *currBldrCtx); StmtNodeBuilder Bldr(Tmp, Dst2, *currBldrCtx);
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) { for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) {
state = (*I)->getState(); state = (*I)->getState();
assert(LCtx == (*I)->getLocationContext()); assert(LCtx == (*I)->getLocationContext());
SVal V2_untested = state->getSVal(Ex, LCtx); SVal V2_untested = state->getSVal(Ex, LCtx);
// Propagate unknown and undefined values. // Propagate unknown and undefined values.
if (V2_untested.isUnknownOrUndef()) { if (V2_untested.isUnknownOrUndef()) {
Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V2_untested)); Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V2_untested));
continue; continue;
} }
DefinedSVal V2 = V2_untested.castAs<DefinedSVal>(); DefinedSVal V2 = V2_untested.castAs<DefinedSVal>();
// Handle all other values. // Handle all other values.
BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add : BO_Sub; BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add : BO_Sub;
// If the UnaryOperator has non-location type, use its type to create the // If the UnaryOperator has non-location type, use its type to create the
// constant value. If the UnaryOperator has location type, create the // constant value. If the UnaryOperator has location type, create the
// constant with int type and pointer width. // constant with int type and pointer width.
SVal RHS; SVal RHS;
if (U->getType()->isAnyPointerType()) if (U->getType()->isAnyPointerType())
RHS = svalBuilder.makeArrayIndex(1); RHS = svalBuilder.makeArrayIndex(1);
else if (U->getType()->isIntegralOrEnumerationType()) else if (U->getType()->isIntegralOrEnumerationType())
RHS = svalBuilder.makeIntVal(1, U->getType()); RHS = svalBuilder.makeIntVal(1, U->getType());
else else
RHS = UnknownVal(); RHS = UnknownVal();
SVal Result = evalBinOp(state, Op, V2, RHS, U->getType()); SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
// Conjure a new symbol if necessary to recover precision. // Conjure a new symbol if necessary to recover precision.
if (Result.isUnknown()){ if (Result.isUnknown()){
DefinedOrUnknownSVal SymVal = DefinedOrUnknownSVal SymVal =
svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx, svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
currBldrCtx->blockCount()); currBldrCtx->blockCount());
Result = SymVal; Result = SymVal;
// If the value is a location, ++/-- should always preserve // If the value is a location, ++/-- should always preserve
// non-nullness. Check if the original value was non-null, and if so // non-nullness. Check if the original value was non-null, and if so
// propagate that constraint. // propagate that constraint.
if (Loc::isLocType(U->getType())) { if (Loc::isLocType(U->getType())) {
DefinedOrUnknownSVal Constraint = DefinedOrUnknownSVal Constraint =
svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType())); svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType()));
if (!state->assume(Constraint, true)) { if (!state->assume(Constraint, true)) {
// It isn't feasible for the original value to be null. // It isn't feasible for the original value to be null.
// Propagate this constraint. // Propagate this constraint.
Constraint = svalBuilder.evalEQ(state, SymVal, Constraint = svalBuilder.evalEQ(state, SymVal,
svalBuilder.makeZeroVal(U->getType())); svalBuilder.makeZeroVal(U->getType()));
state = state->assume(Constraint, false); state = state->assume(Constraint, false);
assert(state); assert(state);
} }
} }
} }
// Since the lvalue-to-rvalue conversion is explicit in the AST, // Since the lvalue-to-rvalue conversion is explicit in the AST,
// we bind an l-value if the operator is prefix and an lvalue (in C++). // we bind an l-value if the operator is prefix and an lvalue (in C++).
if (U->isGLValue()) if (U->isGLValue())
state = state->BindExpr(U, LCtx, loc); state = state->BindExpr(U, LCtx, loc);
else else
state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result); state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result);
// Perform the store. // Perform the store.
Bldr.takeNodes(*I); Bldr.takeNodes(*I);
ExplodedNodeSet Dst3; ExplodedNodeSet Dst3;

View File

@ -300,7 +300,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
const MemRegion *Dest, const MemRegion *Dest,
const Stmt *S, const Stmt *S,
bool IsBaseDtor, bool IsBaseDtor,
ExplodedNode *Pred, ExplodedNode *Pred,
ExplodedNodeSet &Dst) { ExplodedNodeSet &Dst) {
const LocationContext *LCtx = Pred->getLocationContext(); const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState(); ProgramStateRef State = Pred->getState();
@ -373,7 +373,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// Also, we need to decide how allocators actually work -- they're not // Also, we need to decide how allocators actually work -- they're not
// really part of the CXXNewExpr because they happen BEFORE the // really part of the CXXNewExpr because they happen BEFORE the
// CXXConstructExpr subexpression. See PR12014 for some discussion. // CXXConstructExpr subexpression. See PR12014 for some discussion.
unsigned blockCount = currBldrCtx->blockCount(); unsigned blockCount = currBldrCtx->blockCount();
const LocationContext *LCtx = Pred->getLocationContext(); const LocationContext *LCtx = Pred->getLocationContext();
DefinedOrUnknownSVal symVal = UnknownVal(); DefinedOrUnknownSVal symVal = UnknownVal();
@ -392,8 +392,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1); IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1);
} }
// We assume all standard global 'operator new' functions allocate memory in // We assume all standard global 'operator new' functions allocate memory in
// heap. We realize this is an approximation that might not correctly model // heap. We realize this is an approximation that might not correctly model
// a custom global allocator. // a custom global allocator.
if (IsStandardGlobalOpNewFunction) if (IsStandardGlobalOpNewFunction)
symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount); symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
@ -472,7 +472,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
} }
} }
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,
ExplodedNode *Pred, ExplodedNodeSet &Dst) { ExplodedNode *Pred, ExplodedNodeSet &Dst) {
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef state = Pred->getState(); ProgramStateRef state = Pred->getState();

View File

@ -44,19 +44,19 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
const CFG *CalleeCFG = calleeCtx->getCFG(); const CFG *CalleeCFG = calleeCtx->getCFG();
const CFGBlock *Entry = &(CalleeCFG->getEntry()); const CFGBlock *Entry = &(CalleeCFG->getEntry());
// Validate the CFG. // Validate the CFG.
assert(Entry->empty()); assert(Entry->empty());
assert(Entry->succ_size() == 1); assert(Entry->succ_size() == 1);
// Get the solitary successor. // Get the solitary successor.
const CFGBlock *Succ = *(Entry->succ_begin()); const CFGBlock *Succ = *(Entry->succ_begin());
// Construct an edge representing the starting location in the callee. // Construct an edge representing the starting location in the callee.
BlockEdge Loc(Entry, Succ, calleeCtx); BlockEdge Loc(Entry, Succ, calleeCtx);
ProgramStateRef state = Pred->getState(); ProgramStateRef state = Pred->getState();
// Construct a new node and add it to the worklist. // Construct a new node and add it to the worklist.
bool isNew; bool isNew;
ExplodedNode *Node = G.getNode(Loc, state, false, &isNew); ExplodedNode *Node = G.getNode(Loc, state, false, &isNew);
@ -207,8 +207,8 @@ static bool isTemporaryPRValue(const CXXConstructExpr *E, SVal V) {
return isa<CXXTempObjectRegion>(MR); return isa<CXXTempObjectRegion>(MR);
} }
/// The call exit is simulated with a sequence of nodes, which occur between /// The call exit is simulated with a sequence of nodes, which occur between
/// CallExitBegin and CallExitEnd. The following operations occur between the /// CallExitBegin and CallExitEnd. The following operations occur between the
/// two program points: /// two program points:
/// 1. CallExitBegin (triggers the start of call exit sequence) /// 1. CallExitBegin (triggers the start of call exit sequence)
/// 2. Bind the return value /// 2. Bind the return value
@ -220,12 +220,12 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext()); PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext());
const StackFrameContext *calleeCtx = const StackFrameContext *calleeCtx =
CEBNode->getLocationContext()->getCurrentStackFrame(); CEBNode->getLocationContext()->getCurrentStackFrame();
// The parent context might not be a stack frame, so make sure we // The parent context might not be a stack frame, so make sure we
// look up the first enclosing stack frame. // look up the first enclosing stack frame.
const StackFrameContext *callerCtx = const StackFrameContext *callerCtx =
calleeCtx->getParent()->getCurrentStackFrame(); calleeCtx->getParent()->getCurrentStackFrame();
const Stmt *CE = calleeCtx->getCallSite(); const Stmt *CE = calleeCtx->getCallSite();
ProgramStateRef state = CEBNode->getState(); ProgramStateRef state = CEBNode->getState();
// Find the last statement in the function and the corresponding basic block. // Find the last statement in the function and the corresponding basic block.
@ -429,7 +429,7 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
cast<BlockDecl>(D), cast<BlockDecl>(D),
BR); BR);
} }
// This may be NULL, but that's fine. // This may be NULL, but that's fine.
const Expr *CallE = Call.getOriginExpr(); const Expr *CallE = Call.getOriginExpr();
@ -439,8 +439,8 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
CalleeADC->getStackFrame(ParentOfCallee, CallE, CalleeADC->getStackFrame(ParentOfCallee, CallE,
currBldrCtx->getBlock(), currBldrCtx->getBlock(),
currStmtIdx); currStmtIdx);
CallEnter Loc(CallE, CalleeSFC, CurLC); CallEnter Loc(CallE, CalleeSFC, CurLC);
// Construct a new state which contains the mapping from actual to // Construct a new state which contains the mapping from actual to
@ -769,7 +769,7 @@ static bool mayInlineDecl(AnalysisDeclContext *CalleeADC,
if (!Ctx.getSourceManager().isInMainFile(FD->getLocation())) if (!Ctx.getSourceManager().isInMainFile(FD->getLocation()))
if (isContainerMethod(Ctx, FD)) if (isContainerMethod(Ctx, FD))
return false; return false;
// Conditionally control the inlining of the destructor of C++ shared_ptr. // Conditionally control the inlining of the destructor of C++ shared_ptr.
// We don't currently do a good job modeling shared_ptr because we can't // We don't currently do a good job modeling shared_ptr because we can't
// see the reference count, so treating as opaque is probably the best // see the reference count, so treating as opaque is probably the best
@ -992,12 +992,12 @@ void ExprEngine::BifurcateCall(const MemRegion *BifurReg,
void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
ExplodedNodeSet &Dst) { ExplodedNodeSet &Dst) {
ExplodedNodeSet dstPreVisit; ExplodedNodeSet dstPreVisit;
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this); getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this);
StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx); StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
if (RS->getRetValue()) { if (RS->getRetValue()) {
for (ExplodedNodeSet::iterator it = dstPreVisit.begin(), for (ExplodedNodeSet::iterator it = dstPreVisit.begin(),
ei = dstPreVisit.end(); it != ei; ++it) { ei = dstPreVisit.end(); it != ei; ++it) {

View File

@ -19,18 +19,18 @@
using namespace clang; using namespace clang;
using namespace ento; using namespace ento;
void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex, void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
ExplodedNode *Pred, ExplodedNode *Pred,
ExplodedNodeSet &Dst) { ExplodedNodeSet &Dst) {
ProgramStateRef state = Pred->getState(); ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext(); const LocationContext *LCtx = Pred->getLocationContext();
SVal baseVal = state->getSVal(Ex->getBase(), LCtx); SVal baseVal = state->getSVal(Ex->getBase(), LCtx);
SVal location = state->getLValue(Ex->getDecl(), baseVal); SVal location = state->getLValue(Ex->getDecl(), baseVal);
ExplodedNodeSet dstIvar; ExplodedNodeSet dstIvar;
StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx); StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx);
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location)); Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
// Perform the post-condition check of the ObjCIvarRefExpr and store // Perform the post-condition check of the ObjCIvarRefExpr and store
// the created nodes in 'Dst'. // the created nodes in 'Dst'.
getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this); getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
@ -45,7 +45,7 @@ void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
ExplodedNode *Pred, ExplodedNode *Pred,
ExplodedNodeSet &Dst) { ExplodedNodeSet &Dst) {
// ObjCForCollectionStmts are processed in two places. This method // ObjCForCollectionStmts are processed in two places. This method
// handles the case where an ObjCForCollectionStmt* occurs as one of the // handles the case where an ObjCForCollectionStmt* occurs as one of the
// statements within a basic block. This transfer function does two things: // statements within a basic block. This transfer function does two things:
@ -74,7 +74,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
const Stmt *elem = S->getElement(); const Stmt *elem = S->getElement();
ProgramStateRef state = Pred->getState(); ProgramStateRef state = Pred->getState();
SVal elementV; SVal elementV;
if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) { if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl()); const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
assert(elemD->getInit() == nullptr); assert(elemD->getInit() == nullptr);
@ -83,7 +83,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
else { else {
elementV = state->getSVal(elem, Pred->getLocationContext()); elementV = state->getSVal(elem, Pred->getLocationContext());
} }
ExplodedNodeSet dstLocation; ExplodedNodeSet dstLocation;
evalLocation(dstLocation, S, elem, Pred, state, elementV, nullptr, false); evalLocation(dstLocation, S, elem, Pred, state, elementV, nullptr, false);
@ -95,17 +95,17 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
Pred = *NI; Pred = *NI;
ProgramStateRef state = Pred->getState(); ProgramStateRef state = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext(); const LocationContext *LCtx = Pred->getLocationContext();
// Handle the case where the container still has elements. // Handle the case where the container still has elements.
SVal TrueV = svalBuilder.makeTruthVal(1); SVal TrueV = svalBuilder.makeTruthVal(1);
ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV); ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV);
// Handle the case where the container has no elements. // Handle the case where the container has no elements.
SVal FalseV = svalBuilder.makeTruthVal(0); SVal FalseV = svalBuilder.makeTruthVal(0);
ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV); ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
if (Optional<loc::MemRegionVal> MV = elementV.getAs<loc::MemRegionVal>()) if (Optional<loc::MemRegionVal> MV = elementV.getAs<loc::MemRegionVal>())
if (const TypedValueRegion *R = if (const TypedValueRegion *R =
dyn_cast<TypedValueRegion>(MV->getRegion())) { dyn_cast<TypedValueRegion>(MV->getRegion())) {
// FIXME: The proper thing to do is to really iterate over the // FIXME: The proper thing to do is to really iterate over the
// container. We will do this with dispatch logic to the store. // container. We will do this with dispatch logic to the store.
@ -116,12 +116,12 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
currBldrCtx->blockCount()); currBldrCtx->blockCount());
SVal V = svalBuilder.makeLoc(Sym); SVal V = svalBuilder.makeLoc(Sym);
hasElems = hasElems->bindLoc(elementV, V); hasElems = hasElems->bindLoc(elementV, V);
// Bind the location to 'nil' on the false branch. // Bind the location to 'nil' on the false branch.
SVal nilV = svalBuilder.makeIntVal(0, T); SVal nilV = svalBuilder.makeIntVal(0, T);
noElems = noElems->bindLoc(elementV, nilV); noElems = noElems->bindLoc(elementV, nilV);
} }
// Create the new nodes. // Create the new nodes.
Bldr.generateNode(S, Pred, hasElems); Bldr.generateNode(S, Pred, hasElems);
Bldr.generateNode(S, Pred, noElems); Bldr.generateNode(S, Pred, noElems);
@ -156,7 +156,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ExplodedNode *Pred = *DI; ExplodedNode *Pred = *DI;
ProgramStateRef State = Pred->getState(); ProgramStateRef State = Pred->getState();
CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State); CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
if (UpdatedMsg->isInstanceMessage()) { if (UpdatedMsg->isInstanceMessage()) {
SVal recVal = UpdatedMsg->getReceiverSVal(); SVal recVal = UpdatedMsg->getReceiverSVal();
if (!recVal.isUndef()) { if (!recVal.isUndef()) {
@ -166,7 +166,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
ProgramStateRef notNilState, nilState; ProgramStateRef notNilState, nilState;
std::tie(notNilState, nilState) = State->assume(receiverVal); std::tie(notNilState, nilState) = State->assume(receiverVal);
// There are three cases: can be nil or non-nil, must be nil, must be // There are three cases: can be nil or non-nil, must be nil, must be
// non-nil. We ignore must be nil, and merge the rest two into non-nil. // non-nil. We ignore must be nil, and merge the rest two into non-nil.
// FIXME: This ignores many potential bugs (<rdar://problem/11733396>). // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
@ -174,7 +174,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
if (nilState && !notNilState) { if (nilState && !notNilState) {
continue; continue;
} }
// Check if the "raise" message was sent. // Check if the "raise" message was sent.
assert(notNilState); assert(notNilState);
if (ObjCNoRet.isImplicitNoReturn(ME)) { if (ObjCNoRet.isImplicitNoReturn(ME)) {
@ -183,7 +183,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
Bldr.generateSink(ME, Pred, State); Bldr.generateSink(ME, Pred, State);
continue; continue;
} }
// Generate a transition to non-Nil state. // Generate a transition to non-Nil state.
if (notNilState != State) { if (notNilState != State) {
Pred = Bldr.generateNode(ME, Pred, notNilState); Pred = Bldr.generateNode(ME, Pred, notNilState);
@ -203,7 +203,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
defaultEvalCall(Bldr, Pred, *UpdatedMsg); defaultEvalCall(Bldr, Pred, *UpdatedMsg);
} }
ExplodedNodeSet dstPostvisit; ExplodedNodeSet dstPostvisit;
getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
*Msg, *this); *Msg, *this);

View File

@ -1,13 +1,13 @@
##===- clang/lib/StaticAnalyzer/Core/Makefile --------------*- Makefile -*-===## ##===- clang/lib/StaticAnalyzer/Core/Makefile --------------*- Makefile -*-===##
# #
# The LLVM Compiler Infrastructure # The LLVM Compiler Infrastructure
# #
# This file is distributed under the University of Illinois Open Source # This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details. # License. See LICENSE.TXT for details.
# #
##===----------------------------------------------------------------------===## ##===----------------------------------------------------------------------===##
# #
# This implements analyses built on top of source-level CFGs. # This implements analyses built on top of source-level CFGs.
# #
##===----------------------------------------------------------------------===## ##===----------------------------------------------------------------------===##

View File

@ -756,7 +756,7 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
return cast<VarRegion>(I.getCapturedRegion()); return cast<VarRegion>(I.getCapturedRegion());
} }
} }
LC = LC->getParent(); LC = LC->getParent();
} }
return (const StackFrameContext *)nullptr; return (const StackFrameContext *)nullptr;
@ -788,18 +788,18 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
else else
sReg = getGlobalsRegion(); sReg = getGlobalsRegion();
} }
// Finally handle static locals. // Finally handle static locals.
} else { } else {
// FIXME: Once we implement scope handling, we will need to properly lookup // FIXME: Once we implement scope handling, we will need to properly lookup
// 'D' to the proper LocationContext. // 'D' to the proper LocationContext.
const DeclContext *DC = D->getDeclContext(); const DeclContext *DC = D->getDeclContext();
llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V = llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V =
getStackOrCaptureRegionForDeclContext(LC, DC, D); getStackOrCaptureRegionForDeclContext(LC, DC, D);
if (V.is<const VarRegion*>()) if (V.is<const VarRegion*>())
return V.get<const VarRegion*>(); return V.get<const VarRegion*>();
const StackFrameContext *STC = V.get<const StackFrameContext*>(); const StackFrameContext *STC = V.get<const StackFrameContext*>();
if (!STC) if (!STC)
@ -1239,7 +1239,7 @@ RegionOffset MemRegion::getAsOffset() const {
Ty = SR->getSymbol()->getType()->getPointeeType(); Ty = SR->getSymbol()->getType()->getPointeeType();
RootIsSymbolic = true; RootIsSymbolic = true;
} }
const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl(); const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
if (!Child) { if (!Child) {
// We cannot compute the offset of the base class. // We cannot compute the offset of the base class.
@ -1290,7 +1290,7 @@ RegionOffset MemRegion::getAsOffset() const {
if (Optional<nonloc::ConcreteInt> CI = if (Optional<nonloc::ConcreteInt> CI =
Index.getAs<nonloc::ConcreteInt>()) { Index.getAs<nonloc::ConcreteInt>()) {
// Don't bother calculating precise offsets if we already have a // Don't bother calculating precise offsets if we already have a
// symbolic offset somewhere in the chain. // symbolic offset somewhere in the chain.
if (SymbolicOffsetBase) if (SymbolicOffsetBase)
continue; continue;
@ -1324,7 +1324,7 @@ RegionOffset MemRegion::getAsOffset() const {
// Get the field number. // Get the field number.
unsigned idx = 0; unsigned idx = 0;
for (RecordDecl::field_iterator FI = RD->field_begin(), for (RecordDecl::field_iterator FI = RD->field_begin(),
FE = RD->field_end(); FI != FE; ++FI, ++idx) FE = RD->field_end(); FI != FE; ++FI, ++idx)
if (FR->getDecl() == *FI) if (FR->getDecl() == *FI)
break; break;
@ -1420,7 +1420,7 @@ BlockDataRegion::referenced_vars_begin() const {
BumpVector<const MemRegion*> *VecOriginal = BumpVector<const MemRegion*> *VecOriginal =
static_cast<BumpVector<const MemRegion*>*>(OriginalVars); static_cast<BumpVector<const MemRegion*>*>(OriginalVars);
return BlockDataRegion::referenced_vars_iterator(Vec->begin(), return BlockDataRegion::referenced_vars_iterator(Vec->begin(),
VecOriginal->begin()); VecOriginal->begin());
} }
@ -1456,12 +1456,12 @@ const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
// RegionAndSymbolInvalidationTraits // RegionAndSymbolInvalidationTraits
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym, void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym,
InvalidationKinds IK) { InvalidationKinds IK) {
SymTraitsMap[Sym] |= IK; SymTraitsMap[Sym] |= IK;
} }
void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR, void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
InvalidationKinds IK) { InvalidationKinds IK) {
assert(MR); assert(MR);
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
@ -1470,13 +1470,13 @@ void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
MRTraitsMap[MR] |= IK; MRTraitsMap[MR] |= IK;
} }
bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym, bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym,
InvalidationKinds IK) { InvalidationKinds IK) {
const_symbol_iterator I = SymTraitsMap.find(Sym); const_symbol_iterator I = SymTraitsMap.find(Sym);
if (I != SymTraitsMap.end()) if (I != SymTraitsMap.end())
return I->second & IK; return I->second & IK;
return false; return false;
} }
bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR, bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,

View File

@ -179,7 +179,7 @@ void PathDiagnostic::resetDiagnosticLocationToMainFile() {
// Reset the report containing declaration and location. // Reset the report containing declaration and location.
DeclWithIssue = CP->getCaller(); DeclWithIssue = CP->getCaller();
Loc = CP->getLocation(); Loc = CP->getLocation();
return; return;
} }
} }
@ -199,7 +199,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
std::unique_ptr<PathDiagnostic> D) { std::unique_ptr<PathDiagnostic> D) {
if (!D || D->path.empty()) if (!D || D->path.empty())
return; return;
// We need to flatten the locations (convert Stmt* to locations) because // We need to flatten the locations (convert Stmt* to locations) because
// the referenced statements may be freed by the time the diagnostics // the referenced statements may be freed by the time the diagnostics
// are emitted. // are emitted.
@ -221,12 +221,12 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
++I) { ++I) {
const PathDiagnosticPiece *piece = I->get(); const PathDiagnosticPiece *piece = I->get();
FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc(); FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
if (FID.isInvalid()) { if (FID.isInvalid()) {
FID = SMgr.getFileID(L); FID = SMgr.getFileID(L);
} else if (SMgr.getFileID(L) != FID) } else if (SMgr.getFileID(L) != FID)
return; // FIXME: Emit a warning? return; // FIXME: Emit a warning?
// Check the source ranges. // Check the source ranges.
ArrayRef<SourceRange> Ranges = piece->getRanges(); ArrayRef<SourceRange> Ranges = piece->getRanges();
for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
@ -238,7 +238,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
if (!L.isFileID() || SMgr.getFileID(L) != FID) if (!L.isFileID() || SMgr.getFileID(L) != FID)
return; // FIXME: Emit a warning? return; // FIXME: Emit a warning?
} }
if (const PathDiagnosticCallPiece *call = if (const PathDiagnosticCallPiece *call =
dyn_cast<PathDiagnosticCallPiece>(piece)) { dyn_cast<PathDiagnosticCallPiece>(piece)) {
WorkList.push_back(&call->path); WorkList.push_back(&call->path);
@ -249,10 +249,10 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
} }
} }
} }
if (FID.isInvalid()) if (FID.isInvalid())
return; // FIXME: Emit a warning? return; // FIXME: Emit a warning?
} }
// Profile the node to see if we already have something matching it // Profile the node to see if we already have something matching it
llvm::FoldingSetNodeID profile; llvm::FoldingSetNodeID profile;
@ -318,7 +318,7 @@ static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
const PathDiagnosticPiece &Y) { const PathDiagnosticPiece &Y) {
if (X.getKind() != Y.getKind()) if (X.getKind() != Y.getKind())
return X.getKind() < Y.getKind(); return X.getKind() < Y.getKind();
FullSourceLoc XL = X.getLocation().asLocation(); FullSourceLoc XL = X.getLocation().asLocation();
FullSourceLoc YL = Y.getLocation().asLocation(); FullSourceLoc YL = Y.getLocation().asLocation();
if (XL != YL) if (XL != YL)
@ -331,7 +331,7 @@ static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
return X.getRanges().size() < Y.getRanges().size(); return X.getRanges().size() < Y.getRanges().size();
const SourceManager &SM = XL.getManager(); const SourceManager &SM = XL.getManager();
for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
SourceRange XR = X.getRanges()[i]; SourceRange XR = X.getRanges()[i];
SourceRange YR = Y.getRanges()[i]; SourceRange YR = Y.getRanges()[i];
@ -341,7 +341,7 @@ static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd());
} }
} }
switch (X.getKind()) { switch (X.getKind()) {
case clang::ento::PathDiagnosticPiece::ControlFlow: case clang::ento::PathDiagnosticPiece::ControlFlow:
return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
@ -418,9 +418,9 @@ void PathDiagnosticConsumer::FlushDiagnostics(
PathDiagnosticConsumer::FilesMade *Files) { PathDiagnosticConsumer::FilesMade *Files) {
if (flushed) if (flushed)
return; return;
flushed = true; flushed = true;
std::vector<const PathDiagnostic *> BatchDiags; std::vector<const PathDiagnostic *> BatchDiags;
for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
et = Diags.end(); it != et; ++it) { et = Diags.end(); it != et; ++it) {
@ -448,7 +448,7 @@ void PathDiagnosticConsumer::FlushDiagnostics(
const PathDiagnostic *D = *it; const PathDiagnostic *D = *it;
delete D; delete D;
} }
// Clear out the FoldingSet. // Clear out the FoldingSet.
Diags.clear(); Diags.clear();
} }
@ -470,7 +470,7 @@ void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
Entry = new (Entry) PDFileEntry(NodeID); Entry = new (Entry) PDFileEntry(NodeID);
Set.InsertNode(Entry, InsertPos); Set.InsertNode(Entry, InsertPos);
} }
// Allocate persistent storage for the file name. // Allocate persistent storage for the file name.
char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
memcpy(FileName_cstr, FileName.data(), FileName.size()); memcpy(FileName_cstr, FileName.data(), FileName.size());
@ -845,7 +845,7 @@ PathDiagnosticRange
SourceRange R = S->getSourceRange(); SourceRange R = S->getSourceRange();
if (R.isValid()) if (R.isValid())
return R; return R;
break; break;
} }
case DeclK: case DeclK:
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@ -947,7 +947,7 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
Out << "constructor"; Out << "constructor";
describeClass(Out, MD->getParent(), " for "); describeClass(Out, MD->getParent(), " for ");
} else if (isa<CXXDestructorDecl>(MD)) { } else if (isa<CXXDestructorDecl>(MD)) {
if (!MD->isUserProvided()) { if (!MD->isUserProvided()) {
Out << "destructor"; Out << "destructor";
@ -1039,7 +1039,7 @@ static void compute_path_size(const PathPieces &pieces, unsigned &size) {
for (PathPieces::const_iterator it = pieces.begin(), for (PathPieces::const_iterator it = pieces.begin(),
et = pieces.end(); it != et; ++it) { et = pieces.end(); it != et; ++it) {
const PathDiagnosticPiece *piece = it->get(); const PathDiagnosticPiece *piece = it->get();
if (const PathDiagnosticCallPiece *cp = if (const PathDiagnosticCallPiece *cp =
dyn_cast<PathDiagnosticCallPiece>(piece)) { dyn_cast<PathDiagnosticCallPiece>(piece)) {
compute_path_size(cp->path, size); compute_path_size(cp->path, size);
} }
@ -1075,12 +1075,12 @@ void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
I != E; ++I) { I != E; ++I) {
ID.AddInteger(I->getBegin().getRawEncoding()); ID.AddInteger(I->getBegin().getRawEncoding());
ID.AddInteger(I->getEnd().getRawEncoding()); ID.AddInteger(I->getEnd().getRawEncoding());
} }
} }
void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const { void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
PathDiagnosticPiece::Profile(ID); PathDiagnosticPiece::Profile(ID);
for (PathPieces::const_iterator it = path.begin(), for (PathPieces::const_iterator it = path.begin(),
et = path.end(); it != et; ++it) { et = path.end(); it != et; ++it) {
ID.Add(**it); ID.Add(**it);
} }

View File

@ -171,7 +171,7 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
--indent; --indent;
Indent(o, indent) << "</array>\n"; Indent(o, indent) << "</array>\n";
} }
// Output the call depth. // Output the call depth.
Indent(o, indent) << "<key>depth</key>"; Indent(o, indent) << "<key>depth</key>";
EmitInteger(o, depth) << '\n'; EmitInteger(o, depth) << '\n';
@ -187,7 +187,7 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
Indent(o, indent) << "<key>message</key>\n"; Indent(o, indent) << "<key>message</key>\n";
Indent(o, indent); Indent(o, indent);
EmitString(o, P.getString()) << '\n'; EmitString(o, P.getString()) << '\n';
// Finish up. // Finish up.
--indent; --indent;
Indent(o, indent); o << "</dict>\n"; Indent(o, indent); o << "</dict>\n";
@ -208,9 +208,9 @@ static void ReportCall(raw_ostream &o,
const LangOptions &LangOpts, const LangOptions &LangOpts,
unsigned indent, unsigned indent,
unsigned depth) { unsigned depth) {
IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter = IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
P.getCallEnterEvent(); P.getCallEnterEvent();
if (callEnter) if (callEnter)
ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true, ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true,
@ -218,18 +218,18 @@ static void ReportCall(raw_ostream &o,
IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithinCaller = IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithinCaller =
P.getCallEnterWithinCallerEvent(); P.getCallEnterWithinCallerEvent();
++depth; ++depth;
if (callEnterWithinCaller) if (callEnterWithinCaller)
ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts, ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
indent, depth, true); indent, depth, true);
for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I) for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true); ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true);
--depth; --depth;
IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit = IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
P.getCallExitEvent(); P.getCallExitEvent();
@ -297,7 +297,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
if (!Diags.empty()) if (!Diags.empty())
SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager(); SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();
for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(), for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
DE = Diags.end(); DI != DE; ++DI) { DE = Diags.end(); DI != DE; ++DI) {
@ -374,7 +374,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " <array>\n"; o << " <array>\n";
for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end(); for (PathPieces::const_iterator I = D->path.begin(), E = D->path.end();
I != E; ++I) I != E; ++I)
ReportDiag(o, **I, FM, *SM, LangOpts); ReportDiag(o, **I, FM, *SM, LangOpts);
@ -389,7 +389,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
EmitString(o, D->getBugType()) << '\n'; EmitString(o, D->getBugType()) << '\n';
o << " <key>check_name</key>"; o << " <key>check_name</key>";
EmitString(o, D->getCheckName()) << '\n'; EmitString(o, D->getCheckName()) << '\n';
// Output information about the semantic context where // Output information about the semantic context where
// the issue occurred. // the issue occurred.
if (const Decl *DeclWithIssue = D->getDeclWithIssue()) { if (const Decl *DeclWithIssue = D->getDeclWithIssue()) {
@ -423,7 +423,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
// Output the bug hash for issue unique-ing. Currently, it's just an // Output the bug hash for issue unique-ing. Currently, it's just an
// offset from the beginning of the function. // offset from the beginning of the function.
if (const Stmt *Body = DeclWithIssue->getBody()) { if (const Stmt *Body = DeclWithIssue->getBody()) {
// If the bug uniqueing location exists, use it for the hash. // If the bug uniqueing location exists, use it for the hash.
// For example, this ensures that two leaks reported on the same line // For example, this ensures that two leaks reported on the same line
// will have different issue_hashes and that the hash will identify // will have different issue_hashes and that the hash will identify
@ -486,5 +486,5 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " </array>\n"; o << " </array>\n";
// Finish. // Finish.
o << "</dict>\n</plist>"; o << "</dict>\n</plist>";
} }

View File

@ -36,7 +36,7 @@ void ProgramStateRelease(const ProgramState *state) {
if (--s->refCount == 0) { if (--s->refCount == 0) {
ProgramStateManager &Mgr = s->getStateManager(); ProgramStateManager &Mgr = s->getStateManager();
Mgr.StateSet.RemoveNode(s); Mgr.StateSet.RemoveNode(s);
s->~ProgramState(); s->~ProgramState();
Mgr.freeStates.push_back(s); Mgr.freeStates.push_back(s);
} }
} }
@ -86,7 +86,7 @@ ProgramStateManager::~ProgramStateManager() {
I->second.second(I->second.first); I->second.second(I->second.first);
} }
ProgramStateRef ProgramStateRef
ProgramStateManager::removeDeadBindings(ProgramStateRef state, ProgramStateManager::removeDeadBindings(ProgramStateRef state,
const StackFrameContext *LCtx, const StackFrameContext *LCtx,
SymbolReaper& SymReaper) { SymbolReaper& SymReaper) {
@ -113,7 +113,7 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state,
ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const { ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const {
ProgramStateManager &Mgr = getStateManager(); ProgramStateManager &Mgr = getStateManager();
ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(), ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
LV, V)); LV, V));
const MemRegion *MR = LV.getAsRegion(); const MemRegion *MR = LV.getAsRegion();
if (MR && Mgr.getOwningEngine() && notifyChanges) if (MR && Mgr.getOwningEngine() && notifyChanges)
@ -127,15 +127,15 @@ ProgramStateRef ProgramState::bindDefault(SVal loc, SVal V) const {
const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion(); const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();
const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V); const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V);
ProgramStateRef new_state = makeWithStore(newStore); ProgramStateRef new_state = makeWithStore(newStore);
return Mgr.getOwningEngine() ? return Mgr.getOwningEngine() ?
Mgr.getOwningEngine()->processRegionChange(new_state, R) : Mgr.getOwningEngine()->processRegionChange(new_state, R) :
new_state; new_state;
} }
typedef ArrayRef<const MemRegion *> RegionList; typedef ArrayRef<const MemRegion *> RegionList;
typedef ArrayRef<SVal> ValueList; typedef ArrayRef<SVal> ValueList;
ProgramStateRef ProgramStateRef
ProgramState::invalidateRegions(RegionList Regions, ProgramState::invalidateRegions(RegionList Regions,
const Expr *E, unsigned Count, const Expr *E, unsigned Count,
const LocationContext *LCtx, const LocationContext *LCtx,
@ -197,11 +197,11 @@ ProgramState::invalidateRegionsImpl(ValueList Values,
if (CausedByPointerEscape) { if (CausedByPointerEscape) {
newState = Eng->notifyCheckersOfPointerEscape(newState, IS, newState = Eng->notifyCheckersOfPointerEscape(newState, IS,
TopLevelInvalidated, TopLevelInvalidated,
Invalidated, Call, Invalidated, Call,
*ITraits); *ITraits);
} }
return Eng->processRegionChanges(newState, IS, TopLevelInvalidated, return Eng->processRegionChanges(newState, IS, TopLevelInvalidated,
Invalidated, Call); Invalidated, Call);
} }
@ -224,7 +224,7 @@ ProgramStateRef ProgramState::killBinding(Loc LV) const {
return makeWithStore(newStore); return makeWithStore(newStore);
} }
ProgramStateRef ProgramStateRef
ProgramState::enterStackFrame(const CallEvent &Call, ProgramState::enterStackFrame(const CallEvent &Call,
const StackFrameContext *CalleeCtx) const { const StackFrameContext *CalleeCtx) const {
const StoreRef &NewStore = const StoreRef &NewStore =
@ -275,7 +275,7 @@ SVal ProgramState::getSVal(Loc location, QualType T) const {
// symbol for the call to foo(); the type of that symbol is 'char', // symbol for the call to foo(); the type of that symbol is 'char',
// not unsigned. // not unsigned.
const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int); const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int);
if (V.getAs<Loc>()) if (V.getAs<Loc>())
return loc::ConcreteInt(NewV); return loc::ConcreteInt(NewV);
else else
@ -283,7 +283,7 @@ SVal ProgramState::getSVal(Loc location, QualType T) const {
} }
} }
} }
return V; return V;
} }
@ -353,11 +353,11 @@ ConditionTruthVal ProgramState::isNull(SVal V) const {
if (V.isConstant()) if (V.isConstant())
return false; return false;
SymbolRef Sym = V.getAsSymbol(/* IncludeBaseRegion */ true); SymbolRef Sym = V.getAsSymbol(/* IncludeBaseRegion */ true);
if (!Sym) if (!Sym)
return ConditionTruthVal(); return ConditionTruthVal();
return getStateManager().ConstraintMgr->isNull(this, Sym); return getStateManager().ConstraintMgr->isNull(this, Sym);
} }
@ -390,7 +390,7 @@ ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {
ProgramState *newState = nullptr; ProgramState *newState = nullptr;
if (!freeStates.empty()) { if (!freeStates.empty()) {
newState = freeStates.back(); newState = freeStates.back();
freeStates.pop_back(); freeStates.pop_back();
} }
else { else {
newState = (ProgramState*) Alloc.Allocate<ProgramState>(); newState = (ProgramState*) Alloc.Allocate<ProgramState>();
@ -530,10 +530,10 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
bool wasVisited = !visited.insert(sym).second; bool wasVisited = !visited.insert(sym).second;
if (wasVisited) if (wasVisited)
return true; return true;
if (!visitor.VisitSymbol(sym)) if (!visitor.VisitSymbol(sym))
return false; return false;
// TODO: should be rewritten using SymExpr::symbol_iterator. // TODO: should be rewritten using SymExpr::symbol_iterator.
switch (sym->getKind()) { switch (sym->getKind()) {
case SymExpr::RegionValueKind: case SymExpr::RegionValueKind:
@ -582,11 +582,11 @@ bool ScanReachableSymbols::scan(SVal val) {
bool ScanReachableSymbols::scan(const MemRegion *R) { bool ScanReachableSymbols::scan(const MemRegion *R) {
if (isa<MemSpaceRegion>(R)) if (isa<MemSpaceRegion>(R))
return true; return true;
bool wasVisited = !visited.insert(R).second; bool wasVisited = !visited.insert(R).second;
if (wasVisited) if (wasVisited)
return true; return true;
if (!visitor.VisitMemRegion(R)) if (!visitor.VisitMemRegion(R))
return false; return false;
@ -722,14 +722,14 @@ bool ProgramState::isTainted(const MemRegion *Reg, TaintTagType K) const {
bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const { bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
if (!Sym) if (!Sym)
return false; return false;
// Traverse all the symbols this symbol depends on to see if any are tainted. // Traverse all the symbols this symbol depends on to see if any are tainted.
bool Tainted = false; bool Tainted = false;
for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end(); for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
SI != SE; ++SI) { SI != SE; ++SI) {
if (!isa<SymbolData>(*SI)) if (!isa<SymbolData>(*SI))
continue; continue;
const TaintTagType *Tag = get<TaintMap>(*SI); const TaintTagType *Tag = get<TaintMap>(*SI);
Tainted = (Tag && *Tag == Kind); Tainted = (Tag && *Tag == Kind);
@ -748,7 +748,7 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
if (Tainted) if (Tainted)
return true; return true;
} }
return Tainted; return Tainted;
} }

View File

@ -365,7 +365,7 @@ ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
/// Scan all symbols referenced by the constraints. If the symbol is not alive /// Scan all symbols referenced by the constraints. If the symbol is not alive
/// as marked in LSymbols, mark it as dead in DSymbols. /// as marked in LSymbols, mark it as dead in DSymbols.
ProgramStateRef ProgramStateRef
RangeConstraintManager::removeDeadBindings(ProgramStateRef state, RangeConstraintManager::removeDeadBindings(ProgramStateRef state,
SymbolReaper& SymReaper) { SymbolReaper& SymReaper) {
@ -415,7 +415,7 @@ RangeConstraintManager::GetRange(ProgramStateRef state, SymbolRef sym) {
// As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1, // As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1,
// UINT_MAX, 0, 1, and 2. // UINT_MAX, 0, 1, and 2.
ProgramStateRef ProgramStateRef
RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym, RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int, const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) { const llvm::APSInt &Adjustment) {
@ -435,7 +435,7 @@ RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
} }
ProgramStateRef ProgramStateRef
RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym, RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int, const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) { const llvm::APSInt &Adjustment) {
@ -450,7 +450,7 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
} }
ProgramStateRef ProgramStateRef
RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym, RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int, const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) { const llvm::APSInt &Adjustment) {
@ -479,7 +479,7 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
} }
ProgramStateRef ProgramStateRef
RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym, RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int, const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) { const llvm::APSInt &Adjustment) {
@ -508,7 +508,7 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
} }
ProgramStateRef ProgramStateRef
RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym, RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int, const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) { const llvm::APSInt &Adjustment) {
@ -537,7 +537,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New); return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
} }
ProgramStateRef ProgramStateRef
RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym, RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
const llvm::APSInt &Int, const llvm::APSInt &Int,
const llvm::APSInt &Adjustment) { const llvm::APSInt &Adjustment) {

View File

@ -464,9 +464,9 @@ public: // Part of public interface to class.
StoreRef killBinding(Store ST, Loc L) override; StoreRef killBinding(Store ST, Loc L) override;
void incrementReferenceCount(Store store) override { void incrementReferenceCount(Store store) override {
getRegionBindings(store).manualRetain(); getRegionBindings(store).manualRetain();
} }
/// If the StoreManager supports it, decrement the reference count of /// If the StoreManager supports it, decrement the reference count of
/// the specified Store object. If the reference count hits 0, the memory /// the specified Store object. If the reference count hits 0, the memory
/// associated with the object is recycled. /// associated with the object is recycled.
@ -508,7 +508,7 @@ public: // Part of public interface to class.
SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B, SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
const TypedValueRegion *R, const TypedValueRegion *R,
QualType Ty); QualType Ty);
SVal getLazyBinding(const SubRegion *LazyBindingRegion, SVal getLazyBinding(const SubRegion *LazyBindingRegion,
RegionBindingsRef LazyBinding); RegionBindingsRef LazyBinding);
@ -987,8 +987,8 @@ void invalidateRegionsWorker::VisitBinding(SVal V) {
void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
const ClusterBindings *C) { const ClusterBindings *C) {
bool PreserveRegionsContents = bool PreserveRegionsContents =
ITraits.hasTrait(baseR, ITraits.hasTrait(baseR,
RegionAndSymbolInvalidationTraits::TK_PreserveContents); RegionAndSymbolInvalidationTraits::TK_PreserveContents);
if (C) { if (C) {
@ -1456,7 +1456,7 @@ RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
// through to look for lazy compound value. It is like a field region. // through to look for lazy compound value. It is like a field region.
Result = findLazyBinding(B, cast<SubRegion>(BaseReg->getSuperRegion()), Result = findLazyBinding(B, cast<SubRegion>(BaseReg->getSuperRegion()),
originalRegion); originalRegion);
if (Result.second) if (Result.second)
Result.second = MRMgr.getCXXBaseObjectRegionWithSuper(BaseReg, Result.second = MRMgr.getCXXBaseObjectRegionWithSuper(BaseReg,
Result.second); Result.second);
@ -1502,7 +1502,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
return svalBuilder.makeIntVal(c, T); return svalBuilder.makeIntVal(c, T);
} }
} }
// Check for loads from a code text region. For such loads, just give up. // Check for loads from a code text region. For such loads, just give up.
if (isa<CodeTextRegion>(superR)) if (isa<CodeTextRegion>(superR))
return UnknownVal(); return UnknownVal();
@ -1514,12 +1514,12 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
// return *y; // return *y;
// FIXME: This is a hack, and doesn't do anything really intelligent yet. // FIXME: This is a hack, and doesn't do anything really intelligent yet.
const RegionRawOffset &O = R->getAsArrayOffset(); const RegionRawOffset &O = R->getAsArrayOffset();
// If we cannot reason about the offset, return an unknown value. // If we cannot reason about the offset, return an unknown value.
if (!O.getRegion()) if (!O.getRegion())
return UnknownVal(); return UnknownVal();
if (const TypedValueRegion *baseR = if (const TypedValueRegion *baseR =
dyn_cast_or_null<TypedValueRegion>(O.getRegion())) { dyn_cast_or_null<TypedValueRegion>(O.getRegion())) {
QualType baseT = baseR->getValueType(); QualType baseT = baseR->getValueType();
if (baseT->isScalarType()) { if (baseT->isScalarType()) {
@ -1610,7 +1610,7 @@ SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion,
return Result; return Result;
} }
SVal SVal
RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
const TypedValueRegion *R, const TypedValueRegion *R,
@ -1664,7 +1664,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
if (!index.isConstant()) if (!index.isConstant())
hasSymbolicIndex = true; hasSymbolicIndex = true;
} }
// If our super region is a field or element itself, walk up the region // If our super region is a field or element itself, walk up the region
// hierarchy to see if there is a default value installed in an ancestor. // hierarchy to see if there is a default value installed in an ancestor.
SR = dyn_cast<SubRegion>(Base); SR = dyn_cast<SubRegion>(Base);
@ -1674,7 +1674,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
if (isa<ElementRegion>(R)) { if (isa<ElementRegion>(R)) {
// Currently we don't reason specially about Clang-style vectors. Check // Currently we don't reason specially about Clang-style vectors. Check
// if superR is a vector and if so return Unknown. // if superR is a vector and if so return Unknown.
if (const TypedValueRegion *typedSuperR = if (const TypedValueRegion *typedSuperR =
dyn_cast<TypedValueRegion>(R->getSuperRegion())) { dyn_cast<TypedValueRegion>(R->getSuperRegion())) {
if (typedSuperR->getValueType()->isVectorType()) if (typedSuperR->getValueType()->isVectorType())
return UnknownVal(); return UnknownVal();
@ -1801,7 +1801,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
List.insert(List.end(), InnerList.begin(), InnerList.end()); List.insert(List.end(), InnerList.begin(), InnerList.end());
continue; continue;
} }
List.push_back(V); List.push_back(V);
} }
@ -1838,7 +1838,7 @@ SVal RegionStoreManager::getBindingForArray(RegionBindingsConstRef B,
const TypedValueRegion *R) { const TypedValueRegion *R) {
assert(Ctx.getAsConstantArrayType(R->getValueType()) && assert(Ctx.getAsConstantArrayType(R->getValueType()) &&
"Only constant array types can have compound bindings."); "Only constant array types can have compound bindings.");
return createLazyBinding(B, R); return createLazyBinding(B, R);
} }
@ -2012,11 +2012,11 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
QualType T = R->getValueType(); QualType T = R->getValueType();
assert(T->isVectorType()); assert(T->isVectorType());
const VectorType *VT = T->getAs<VectorType>(); // Use getAs for typedefs. const VectorType *VT = T->getAs<VectorType>(); // Use getAs for typedefs.
// Handle lazy compound values and symbolic values. // Handle lazy compound values and symbolic values.
if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>()) if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
return bindAggregate(B, R, V); return bindAggregate(B, R, V);
// We may get non-CompoundVal accidentally due to imprecise cast logic or // We may get non-CompoundVal accidentally due to imprecise cast logic or
// that we are binding symbolic struct value. Kill the field values, and if // that we are binding symbolic struct value. Kill the field values, and if
// the value is symbolic go and bind it as a "default" binding. // the value is symbolic go and bind it as a "default" binding.
@ -2033,7 +2033,7 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
for ( ; index != numElements ; ++index) { for ( ; index != numElements ; ++index) {
if (VI == VE) if (VI == VE)
break; break;
NonLoc Idx = svalBuilder.makeArrayIndex(index); NonLoc Idx = svalBuilder.makeArrayIndex(index);
const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx); const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx);
@ -2075,7 +2075,7 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B,
} }
RegionBindingsRef NewB = B; RegionBindingsRef NewB = B;
for (FieldVector::iterator I = Fields.begin(), E = Fields.end(); I != E; ++I){ for (FieldVector::iterator I = Fields.begin(), E = Fields.end(); I != E; ++I){
const FieldRegion *SourceFR = MRMgr.getFieldRegion(*I, LCV.getRegion()); const FieldRegion *SourceFR = MRMgr.getFieldRegion(*I, LCV.getRegion());
SVal V = getBindingForField(getRegionBindings(LCV.getStore()), SourceFR); SVal V = getBindingForField(getRegionBindings(LCV.getStore()), SourceFR);
@ -2259,7 +2259,7 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
// If V is a region, then add it to the worklist. // If V is a region, then add it to the worklist.
if (const MemRegion *R = V.getAsRegion()) { if (const MemRegion *R = V.getAsRegion()) {
AddToWorkList(R); AddToWorkList(R);
// All regions captured by a block are also live. // All regions captured by a block are also live.
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(), BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(),
@ -2268,7 +2268,7 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
AddToWorkList(I.getCapturedRegion()); AddToWorkList(I.getCapturedRegion());
} }
} }
// Update the set of live symbols. // Update the set of live symbols.
for (SymExpr::symbol_iterator SI = V.symbol_begin(), SE = V.symbol_end(); for (SymExpr::symbol_iterator SI = V.symbol_begin(), SE = V.symbol_end();

View File

@ -91,7 +91,7 @@ nonloc::ConcreteInt SValBuilder::makeBoolVal(const CXXBoolLiteralExpr *boolean){
return makeTruthVal(boolean->getValue()); return makeTruthVal(boolean->getValue());
} }
DefinedOrUnknownSVal DefinedOrUnknownSVal
SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) { SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
QualType T = region->getValueType(); QualType T = region->getValueType();
@ -146,10 +146,10 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
return UnknownVal(); return UnknownVal();
SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount); SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount);
if (Loc::isLocType(type)) if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
return nonloc::SymbolVal(sym); return nonloc::SymbolVal(sym);
} }
@ -307,7 +307,7 @@ SVal SValBuilder::makeSymExprValNN(ProgramStateRef State,
QualType ResultTy) { QualType ResultTy) {
if (!State->isTainted(RHS) && !State->isTainted(LHS)) if (!State->isTainted(RHS) && !State->isTainted(LHS))
return UnknownVal(); return UnknownVal();
const SymExpr *symLHS = LHS.getAsSymExpr(); const SymExpr *symLHS = LHS.getAsSymExpr();
const SymExpr *symRHS = RHS.getAsSymExpr(); const SymExpr *symRHS = RHS.getAsSymExpr();
// TODO: When the Max Complexity is reached, we should conjure a symbol // TODO: When the Max Complexity is reached, we should conjure a symbol
@ -430,7 +430,7 @@ SVal SValBuilder::evalCast(SVal val, QualType castTy, QualType originalTy) {
if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy), if (shouldBeModeledWithNoOp(Context, Context.getPointerType(castTy),
Context.getPointerType(originalTy))) Context.getPointerType(originalTy)))
return val; return val;
// Check for casts from pointers to integers. // Check for casts from pointers to integers.
if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy)) if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy))
return evalCastFromLoc(val.castAs<Loc>(), castTy); return evalCastFromLoc(val.castAs<Loc>(), castTy);

View File

@ -638,7 +638,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
// on the ABI). // on the ABI).
// FIXME: we can probably do a comparison against other MemRegions, though. // FIXME: we can probably do a comparison against other MemRegions, though.
// FIXME: is there a way to tell if two labels refer to the same location? // FIXME: is there a way to tell if two labels refer to the same location?
return UnknownVal(); return UnknownVal();
case loc::ConcreteIntKind: { case loc::ConcreteIntKind: {
// If one of the operands is a symbol and the other is a constant, // If one of the operands is a symbol and the other is a constant,
@ -863,7 +863,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// Special case: rhs is a zero constant. // Special case: rhs is a zero constant.
if (rhs.isZeroConstant()) if (rhs.isZeroConstant())
return lhs; return lhs;
// We are dealing with pointer arithmetic. // We are dealing with pointer arithmetic.
// Handle pointer arithmetic on constant values. // Handle pointer arithmetic on constant values.
@ -880,7 +880,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
// Offset the increment by the pointer size. // Offset the increment by the pointer size.
llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true); llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true);
rightI *= Multiplicand; rightI *= Multiplicand;
// Compute the adjusted pointer. // Compute the adjusted pointer.
switch (op) { switch (op) {
case BO_Add: case BO_Add:
@ -922,7 +922,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
superR, getContext())); superR, getContext()));
} }
} }
return UnknownVal(); return UnknownVal();
} }
const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,

View File

@ -52,7 +52,7 @@ StoreRef StoreManager::BindDefault(Store store, const MemRegion *R, SVal V) {
return StoreRef(store, *this); return StoreRef(store, *this);
} }
const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R, const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R,
QualType T) { QualType T) {
NonLoc idx = svalBuilder.makeZeroArrayIndex(); NonLoc idx = svalBuilder.makeZeroArrayIndex();
assert(!T.isNull()); assert(!T.isNull());
@ -366,22 +366,22 @@ SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType,
/// as another region. /// as another region.
SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R, SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
QualType castTy, bool performTestOnly) { QualType castTy, bool performTestOnly) {
if (castTy.isNull() || V.isUnknownOrUndef()) if (castTy.isNull() || V.isUnknownOrUndef())
return V; return V;
ASTContext &Ctx = svalBuilder.getContext(); ASTContext &Ctx = svalBuilder.getContext();
if (performTestOnly) { if (performTestOnly) {
// Automatically translate references to pointers. // Automatically translate references to pointers.
QualType T = R->getValueType(); QualType T = R->getValueType();
if (const ReferenceType *RT = T->getAs<ReferenceType>()) if (const ReferenceType *RT = T->getAs<ReferenceType>())
T = Ctx.getPointerType(RT->getPointeeType()); T = Ctx.getPointerType(RT->getPointeeType());
assert(svalBuilder.getContext().hasSameUnqualifiedType(castTy, T)); assert(svalBuilder.getContext().hasSameUnqualifiedType(castTy, T));
return V; return V;
} }
return svalBuilder.dispatchCast(V, castTy); return svalBuilder.dispatchCast(V, castTy);
} }
@ -424,7 +424,7 @@ SVal StoreManager::getLValueIvar(const ObjCIvarDecl *decl, SVal base) {
return getLValueFieldOrIvar(decl, base); return getLValueFieldOrIvar(decl, base);
} }
SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset, SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
SVal Base) { SVal Base) {
// If the base is an unknown or undefined value, just return it back. // If the base is an unknown or undefined value, just return it back.

View File

@ -409,7 +409,7 @@ bool SymbolReaper::maybeDead(SymbolRef sym) {
bool SymbolReaper::isLiveRegion(const MemRegion *MR) { bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
if (RegionRoots.count(MR)) if (RegionRoots.count(MR))
return true; return true;
MR = MR->getBaseRegion(); MR = MR->getBaseRegion();
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
@ -442,9 +442,9 @@ bool SymbolReaper::isLive(SymbolRef sym) {
markDependentsLive(sym); markDependentsLive(sym);
return true; return true;
} }
bool KnownLive; bool KnownLive;
switch (sym->getKind()) { switch (sym->getKind()) {
case SymExpr::RegionValueKind: case SymExpr::RegionValueKind:
KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion()); KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
@ -525,7 +525,7 @@ bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
if (!includeStoreBindings) if (!includeStoreBindings)
return false; return false;
unsigned &cachedQuery = unsigned &cachedQuery =
const_cast<SymbolReaper*>(this)->includedRegionCache[VR]; const_cast<SymbolReaper*>(this)->includedRegionCache[VR];
@ -535,12 +535,12 @@ bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
// Query the store to see if the region occurs in any live bindings. // Query the store to see if the region occurs in any live bindings.
if (Store store = reapedStore.getStore()) { if (Store store = reapedStore.getStore()) {
bool hasRegion = bool hasRegion =
reapedStore.getStoreManager().includedInBindings(store, VR); reapedStore.getStoreManager().includedInBindings(store, VR);
cachedQuery = hasRegion ? 1 : 2; cachedQuery = hasRegion ? 1 : 2;
return hasRegion; return hasRegion;
} }
return false; return false;
} }

View File

@ -168,7 +168,7 @@ public:
/// The local declaration to all declarations ratio might be very small when /// The local declaration to all declarations ratio might be very small when
/// working with a PCH file. /// working with a PCH file.
SetOfDecls LocalTUDecls; SetOfDecls LocalTUDecls;
// Set of PathDiagnosticConsumers. Owned by AnalysisManager. // Set of PathDiagnosticConsumers. Owned by AnalysisManager.
PathDiagnosticConsumers PathConsumers; PathDiagnosticConsumers PathConsumers;
@ -364,7 +364,7 @@ public:
} }
return true; return true;
} }
bool VisitBlockDecl(BlockDecl *BD) { bool VisitBlockDecl(BlockDecl *BD) {
if (BD->hasBody()) { if (BD->hasBody()) {
assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false); assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
@ -475,7 +475,7 @@ void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
CallGraphNode *N = *I; CallGraphNode *N = *I;
Decl *D = N->getDecl(); Decl *D = N->getDecl();
// Skip the abstract root node. // Skip the abstract root node.
if (!D) if (!D)
continue; continue;
@ -679,11 +679,11 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
case LangOptions::NonGC: case LangOptions::NonGC:
ActionExprEngine(D, false, IMode, Visited); ActionExprEngine(D, false, IMode, Visited);
break; break;
case LangOptions::GCOnly: case LangOptions::GCOnly:
ActionExprEngine(D, true, IMode, Visited); ActionExprEngine(D, true, IMode, Visited);
break; break;
case LangOptions::HybridGC: case LangOptions::HybridGC:
ActionExprEngine(D, false, IMode, Visited); ActionExprEngine(D, false, IMode, Visited);
ActionExprEngine(D, true, IMode, Visited); ActionExprEngine(D, true, IMode, Visited);

View File

@ -42,7 +42,7 @@ public:
ClangCheckerRegistry(ArrayRef<std::string> plugins, ClangCheckerRegistry(ArrayRef<std::string> plugins,
DiagnosticsEngine *diags = nullptr); DiagnosticsEngine *diags = nullptr);
}; };
} // end anonymous namespace } // end anonymous namespace
ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins, ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins,

View File

@ -1,10 +1,10 @@
##===- clang/lib/StaticAnalyzer/Frontend/Makefile ----------*- Makefile -*-===## ##===- clang/lib/StaticAnalyzer/Frontend/Makefile ----------*- Makefile -*-===##
# #
# The LLVM Compiler Infrastructure # The LLVM Compiler Infrastructure
# #
# This file is distributed under the University of Illinois Open Source # This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details. # License. See LICENSE.TXT for details.
# #
##===----------------------------------------------------------------------===## ##===----------------------------------------------------------------------===##
# #
# Starting point into the static analyzer land for the driver. # Starting point into the static analyzer land for the driver.

View File

@ -282,7 +282,7 @@ sub Analyze {
# We save the output file in the 'crashes' directory if clang encounters # We save the output file in the 'crashes' directory if clang encounters
# any problems with the file. # any problems with the file.
my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir); my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir);
my $OutputStream = silent_system($HtmlDir, $Cmd, @CmdArgs); my $OutputStream = silent_system($HtmlDir, $Cmd, @CmdArgs);
while ( <$OutputStream> ) { while ( <$OutputStream> ) {
print $ofh $_; print $ofh $_;

View File

@ -1400,7 +1400,7 @@ my $ForceDisplayHelp = 0;
sub ProcessArgs { sub ProcessArgs {
my $Args = shift; my $Args = shift;
while (@$Args) { while (@$Args) {
# Scan for options we recognize. # Scan for options we recognize.

View File

@ -5,7 +5,7 @@ CmpRuns - A simple tool for comparing two static analyzer runs to determine
which reports have been added, removed, or changed. which reports have been added, removed, or changed.
This is designed to support automated testing using the static analyzer, from This is designed to support automated testing using the static analyzer, from
two perspectives: two perspectives:
1. To monitor changes in the static analyzer's reports on real code bases, for 1. To monitor changes in the static analyzer's reports on real code bases, for
regression testing. regression testing.
@ -19,11 +19,11 @@ Usage:
# #
resultsA = loadResultsFromSingleRun(singleRunInfoA, deleteEmpty) resultsA = loadResultsFromSingleRun(singleRunInfoA, deleteEmpty)
resultsB = loadResultsFromSingleRun(singleRunInfoB, deleteEmpty) resultsB = loadResultsFromSingleRun(singleRunInfoB, deleteEmpty)
# Generate a relation from diagnostics in run A to diagnostics in run B # Generate a relation from diagnostics in run A to diagnostics in run B
# to obtain a list of triples (a, b, confidence). # to obtain a list of triples (a, b, confidence).
diff = compareResults(resultsA, resultsB) diff = compareResults(resultsA, resultsB)
""" """
import os import os
@ -32,7 +32,7 @@ import CmpRuns
# Information about analysis run: # Information about analysis run:
# path - the analysis output directory # path - the analysis output directory
# root - the name of the root directory, which will be disregarded when # root - the name of the root directory, which will be disregarded when
# determining the source file name # determining the source file name
class SingleRunInfo: class SingleRunInfo:
def __init__(self, path, root="", verboseLog=None): def __init__(self, path, root="", verboseLog=None):
@ -56,7 +56,7 @@ class AnalysisDiagnostic:
def getLine(self): def getLine(self):
return self._loc['line'] return self._loc['line']
def getColumn(self): def getColumn(self):
return self._loc['col'] return self._loc['col']
@ -80,12 +80,12 @@ class AnalysisDiagnostic:
return os.path.join(self._report.run.path, self._htmlReport) return os.path.join(self._report.run.path, self._htmlReport)
def getReadableName(self): def getReadableName(self):
return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(), return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(),
self.getColumn(), self.getCategory(), self.getColumn(), self.getCategory(),
self.getDescription()) self.getDescription())
# Note, the data format is not an API and may change from one analyzer # Note, the data format is not an API and may change from one analyzer
# version to another. # version to another.
def getRawData(self): def getRawData(self):
return self._data return self._data
@ -94,7 +94,7 @@ class multidict:
self.data = {} self.data = {}
for key,value in elts: for key,value in elts:
self[key] = value self[key] = value
def __getitem__(self, item): def __getitem__(self, item):
return self.data[item] return self.data[item]
def __setitem__(self, key, value): def __setitem__(self, key, value):
@ -134,15 +134,15 @@ class AnalysisRun:
# Cumulative list of all diagnostics from all the reports. # Cumulative list of all diagnostics from all the reports.
self.diagnostics = [] self.diagnostics = []
self.clang_version = None self.clang_version = None
def getClangVersion(self): def getClangVersion(self):
return self.clang_version return self.clang_version
def readSingleFile(self, p, deleteEmpty): def readSingleFile(self, p, deleteEmpty):
data = plistlib.readPlist(p) data = plistlib.readPlist(p)
# We want to retrieve the clang version even if there are no # We want to retrieve the clang version even if there are no
# reports. Assume that all reports were created using the same # reports. Assume that all reports were created using the same
# clang version (this is always true and is more efficient). # clang version (this is always true and is more efficient).
if 'clang_version' in data: if 'clang_version' in data:
if self.clang_version == None: if self.clang_version == None:
@ -166,9 +166,9 @@ class AnalysisRun:
htmlFiles.append(d.pop('HTMLDiagnostics_files')[0]) htmlFiles.append(d.pop('HTMLDiagnostics_files')[0])
else: else:
htmlFiles = [None] * len(data['diagnostics']) htmlFiles = [None] * len(data['diagnostics'])
report = AnalysisReport(self, data.pop('files')) report = AnalysisReport(self, data.pop('files'))
diagnostics = [AnalysisDiagnostic(d, report, h) diagnostics = [AnalysisDiagnostic(d, report, h)
for d,h in zip(data.pop('diagnostics'), for d,h in zip(data.pop('diagnostics'),
htmlFiles)] htmlFiles)]
@ -179,7 +179,7 @@ class AnalysisRun:
self.diagnostics.extend(diagnostics) self.diagnostics.extend(diagnostics)
# Backward compatibility API. # Backward compatibility API.
def loadResults(path, opts, root = "", deleteEmpty=True): def loadResults(path, opts, root = "", deleteEmpty=True):
return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog), return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog),
deleteEmpty) deleteEmpty)
@ -257,7 +257,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
# Load the run results. # Load the run results.
resultsA = loadResults(dirA, opts, opts.rootA, deleteEmpty) resultsA = loadResults(dirA, opts, opts.rootA, deleteEmpty)
resultsB = loadResults(dirB, opts, opts.rootB, deleteEmpty) resultsB = loadResults(dirB, opts, opts.rootB, deleteEmpty)
# Open the verbose log, if given. # Open the verbose log, if given.
if opts.verboseLog: if opts.verboseLog:
auxLog = open(opts.verboseLog, "wb") auxLog = open(opts.verboseLog, "wb")
@ -285,7 +285,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
b.getReadableName()) b.getReadableName())
foundDiffs += 1 foundDiffs += 1
if auxLog: if auxLog:
print >>auxLog, ("('CHANGED', %r, %r, %r, %r)" print >>auxLog, ("('CHANGED', %r, %r, %r, %r)"
% (a.getReadableName(), % (a.getReadableName(),
b.getReadableName(), b.getReadableName(),
a.getReport(), a.getReport(),
@ -299,7 +299,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
if auxLog: if auxLog:
print >>auxLog, "('TOTAL NEW REPORTS', %r)" % TotalReports print >>auxLog, "('TOTAL NEW REPORTS', %r)" % TotalReports
print >>auxLog, "('TOTAL DIFFERENCES', %r)" % foundDiffs print >>auxLog, "('TOTAL DIFFERENCES', %r)" % foundDiffs
return foundDiffs, len(resultsA.diagnostics), len(resultsB.diagnostics) return foundDiffs, len(resultsA.diagnostics), len(resultsB.diagnostics)
def main(): def main():
@ -322,7 +322,7 @@ def main():
dirA,dirB = args dirA,dirB = args
dumpScanBuildResultsDiff(dirA, dirB, opts) dumpScanBuildResultsDiff(dirA, dirB, opts)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View File

@ -1,20 +1,20 @@
#!/usr/bin/env python #!/usr/bin/env python
""" """
Static Analyzer qualification infrastructure: adding a new project to Static Analyzer qualification infrastructure: adding a new project to
the Repository Directory. the Repository Directory.
Add a new project for testing: build it and add to the Project Map file. Add a new project for testing: build it and add to the Project Map file.
Assumes it's being run from the Repository Directory. Assumes it's being run from the Repository Directory.
The project directory should be added inside the Repository Directory and The project directory should be added inside the Repository Directory and
have the same name as the project ID have the same name as the project ID
The project should use the following files for set up: The project should use the following files for set up:
- pre_run_static_analyzer.sh - prepare the build environment. - pre_run_static_analyzer.sh - prepare the build environment.
Ex: make clean can be a part of it. Ex: make clean can be a part of it.
- run_static_analyzer.cmd - a list of commands to run through scan-build. - run_static_analyzer.cmd - a list of commands to run through scan-build.
Each command should be on a separate line. Each command should be on a separate line.
Choose from: configure, make, xcodebuild Choose from: configure, make, xcodebuild
""" """
import SATestBuild import SATestBuild
@ -27,7 +27,7 @@ def isExistingProject(PMapFile, projectID) :
for I in PMapReader: for I in PMapReader:
if projectID == I[0]: if projectID == I[0]:
return True return True
return False return False
# Add a new project for testing: build it and add to the Project Map file. # Add a new project for testing: build it and add to the Project Map file.
# Params: # Params:
@ -39,7 +39,7 @@ def addNewProject(ID, BuildMode) :
if not os.path.exists(Dir): if not os.path.exists(Dir):
print "Error: Project directory is missing: %s" % Dir print "Error: Project directory is missing: %s" % Dir
sys.exit(-1) sys.exit(-1)
# Build the project. # Build the project.
SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True, Dir=Dir) SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True, Dir=Dir)
@ -51,19 +51,19 @@ def addNewProject(ID, BuildMode) :
print "Warning: Creating the Project Map file!!" print "Warning: Creating the Project Map file!!"
PMapFile = open(ProjectMapPath, "w+b") PMapFile = open(ProjectMapPath, "w+b")
try: try:
if (isExistingProject(PMapFile, ID)) : if (isExistingProject(PMapFile, ID)) :
print >> sys.stdout, 'Warning: Project with ID \'', ID, \ print >> sys.stdout, 'Warning: Project with ID \'', ID, \
'\' already exists.' '\' already exists.'
print >> sys.stdout, "Reference output has been regenerated." print >> sys.stdout, "Reference output has been regenerated."
else: else:
PMapWriter = csv.writer(PMapFile) PMapWriter = csv.writer(PMapFile)
PMapWriter.writerow( (ID, int(BuildMode)) ); PMapWriter.writerow( (ID, int(BuildMode)) );
print "The project map is updated: ", ProjectMapPath print "The project map is updated: ", ProjectMapPath
finally: finally:
PMapFile.close() PMapFile.close()
# TODO: Add an option not to build.
# TODO: Add an option not to build.
# TODO: Set the path to the Repository directory. # TODO: Set the path to the Repository directory.
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) < 2: if len(sys.argv) < 2:
@ -73,10 +73,10 @@ if __name__ == '__main__':
'1 for scan_build; ' \ '1 for scan_build; ' \
'2 for single file c++11 project' '2 for single file c++11 project'
sys.exit(-1) sys.exit(-1)
BuildMode = 1 BuildMode = 1
if (len(sys.argv) >= 3): if (len(sys.argv) >= 3):
BuildMode = int(sys.argv[2]) BuildMode = int(sys.argv[2])
assert((BuildMode == 0) | (BuildMode == 1) | (BuildMode == 2)) assert((BuildMode == 0) | (BuildMode == 1) | (BuildMode == 2))
addNewProject(sys.argv[1], BuildMode) addNewProject(sys.argv[1], BuildMode)

View File

@ -6,8 +6,8 @@ Static Analyzer qualification infrastructure.
The goal is to test the analyzer against different projects, check for failures, The goal is to test the analyzer against different projects, check for failures,
compare results, and measure performance. compare results, and measure performance.
Repository Directory will contain sources of the projects as well as the Repository Directory will contain sources of the projects as well as the
information on how to build them and the expected output. information on how to build them and the expected output.
Repository Directory structure: Repository Directory structure:
- ProjectMap file - ProjectMap file
- Historical Performance Data - Historical Performance Data
@ -19,16 +19,16 @@ Repository Directory structure:
Note that the build tree must be inside the project dir. Note that the build tree must be inside the project dir.
To test the build of the analyzer one would: To test the build of the analyzer one would:
- Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that - Copy over a copy of the Repository Directory. (TODO: Prefer to ensure that
the build directory does not pollute the repository to min network traffic). the build directory does not pollute the repository to min network traffic).
- Build all projects, until error. Produce logs to report errors. - Build all projects, until error. Produce logs to report errors.
- Compare results. - Compare results.
The files which should be kept around for failure investigations: The files which should be kept around for failure investigations:
RepositoryCopy/Project DirI/ScanBuildResults RepositoryCopy/Project DirI/ScanBuildResults
RepositoryCopy/Project DirI/run_static_analyzer.log RepositoryCopy/Project DirI/run_static_analyzer.log
Assumptions (TODO: shouldn't need to assume these.): Assumptions (TODO: shouldn't need to assume these.):
The script is being run from the Repository Directory. The script is being run from the Repository Directory.
The compiler for scan-build and scan-build are in the PATH. The compiler for scan-build and scan-build are in the PATH.
export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH export PATH=/Users/zaks/workspace/c2llvm/build/Release+Asserts/bin:$PATH
@ -36,7 +36,7 @@ Assumptions (TODO: shouldn't need to assume these.):
For more logging, set the env variables: For more logging, set the env variables:
zaks:TI zaks$ export CCC_ANALYZER_LOG=1 zaks:TI zaks$ export CCC_ANALYZER_LOG=1
zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1 zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1
The list of checkers tested are hardcoded in the Checkers variable. The list of checkers tested are hardcoded in the Checkers variable.
For testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment For testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment
variable. It should contain a comma separated list. variable. It should contain a comma separated list.
@ -120,16 +120,16 @@ class flushfile(object):
sys.stdout = flushfile(sys.stdout) sys.stdout = flushfile(sys.stdout)
def getProjectMapPath(): def getProjectMapPath():
ProjectMapPath = os.path.join(os.path.abspath(os.curdir), ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
ProjectMapFile) ProjectMapFile)
if not os.path.exists(ProjectMapPath): if not os.path.exists(ProjectMapPath):
print "Error: Cannot find the Project Map file " + ProjectMapPath +\ print "Error: Cannot find the Project Map file " + ProjectMapPath +\
"\nRunning script for the wrong directory?" "\nRunning script for the wrong directory?"
sys.exit(-1) sys.exit(-1)
return ProjectMapPath return ProjectMapPath
def getProjectDir(ID): def getProjectDir(ID):
return os.path.join(os.path.abspath(os.curdir), ID) return os.path.join(os.path.abspath(os.curdir), ID)
def getSBOutputDirName(IsReferenceBuild) : def getSBOutputDirName(IsReferenceBuild) :
if IsReferenceBuild == True : if IsReferenceBuild == True :
@ -156,13 +156,13 @@ ProjectMapFile = "projectMap.csv"
# Names of the project specific scripts. # Names of the project specific scripts.
# The script that needs to be executed before the build can start. # The script that needs to be executed before the build can start.
CleanupScript = "cleanup_run_static_analyzer.sh" CleanupScript = "cleanup_run_static_analyzer.sh"
# This is a file containing commands for scan-build. # This is a file containing commands for scan-build.
BuildScript = "run_static_analyzer.cmd" BuildScript = "run_static_analyzer.cmd"
# The log file name. # The log file name.
LogFolderName = "Logs" LogFolderName = "Logs"
BuildLogName = "run_static_analyzer.log" BuildLogName = "run_static_analyzer.log"
# Summary file - contains the summary of the failures. Ex: This info can be be # Summary file - contains the summary of the failures. Ex: This info can be be
# displayed when buildbot detects a build failure. # displayed when buildbot detects a build failure.
NumOfFailuresInSummary = 10 NumOfFailuresInSummary = 10
FailuresSummaryFileName = "failures.txt" FailuresSummaryFileName = "failures.txt"
@ -189,21 +189,21 @@ def runCleanupScript(Dir, PBuildLogFile):
ScriptPath = os.path.join(Dir, CleanupScript) ScriptPath = os.path.join(Dir, CleanupScript)
if os.path.exists(ScriptPath): if os.path.exists(ScriptPath):
try: try:
if Verbose == 1: if Verbose == 1:
print " Executing: %s" % (ScriptPath,) print " Executing: %s" % (ScriptPath,)
check_call("chmod +x %s" % ScriptPath, cwd = Dir, check_call("chmod +x %s" % ScriptPath, cwd = Dir,
stderr=PBuildLogFile, stderr=PBuildLogFile,
stdout=PBuildLogFile, stdout=PBuildLogFile,
shell=True) shell=True)
check_call(ScriptPath, cwd = Dir, stderr=PBuildLogFile, check_call(ScriptPath, cwd = Dir, stderr=PBuildLogFile,
stdout=PBuildLogFile, stdout=PBuildLogFile,
shell=True) shell=True)
except: except:
print "Error: The pre-processing step failed. See ", \ print "Error: The pre-processing step failed. See ", \
PBuildLogFile.name, " for details." PBuildLogFile.name, " for details."
sys.exit(-1) sys.exit(-1)
# Build the project with scan-build by reading in the commands and # Build the project with scan-build by reading in the commands and
# prefixing them with the scan-build options. # prefixing them with the scan-build options.
def runScanBuild(Dir, SBOutputDir, PBuildLogFile): def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
BuildScriptPath = os.path.join(Dir, BuildScript) BuildScriptPath = os.path.join(Dir, BuildScript)
@ -212,9 +212,9 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
sys.exit(-1) sys.exit(-1)
SBOptions = "--use-analyzer " + Clang + " " SBOptions = "--use-analyzer " + Clang + " "
SBOptions += "-plist-html -o " + SBOutputDir + " " SBOptions += "-plist-html -o " + SBOutputDir + " "
SBOptions += "-enable-checker " + Checkers + " " SBOptions += "-enable-checker " + Checkers + " "
SBOptions += "--keep-empty " SBOptions += "--keep-empty "
# Always use ccc-analyze to ensure that we can locate the failures # Always use ccc-analyze to ensure that we can locate the failures
# directory. # directory.
SBOptions += "--override-compiler " SBOptions += "--override-compiler "
try: try:
@ -231,10 +231,10 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
"-j" not in Command: "-j" not in Command:
Command += " -j%d" % Jobs Command += " -j%d" % Jobs
SBCommand = SBPrefix + Command SBCommand = SBPrefix + Command
if Verbose == 1: if Verbose == 1:
print " Executing: %s" % (SBCommand,) print " Executing: %s" % (SBCommand,)
check_call(SBCommand, cwd = Dir, stderr=PBuildLogFile, check_call(SBCommand, cwd = Dir, stderr=PBuildLogFile,
stdout=PBuildLogFile, stdout=PBuildLogFile,
shell=True) shell=True)
except: except:
print "Error: scan-build failed. See ",PBuildLogFile.name,\ print "Error: scan-build failed. See ",PBuildLogFile.name,\
@ -249,97 +249,97 @@ def hasNoExtension(FileName):
def isValidSingleInputFile(FileName): def isValidSingleInputFile(FileName):
(Root, Ext) = os.path.splitext(FileName) (Root, Ext) = os.path.splitext(FileName)
if ((Ext == ".i") | (Ext == ".ii") | if ((Ext == ".i") | (Ext == ".ii") |
(Ext == ".c") | (Ext == ".cpp") | (Ext == ".c") | (Ext == ".cpp") |
(Ext == ".m") | (Ext == "")) : (Ext == ".m") | (Ext == "")) :
return True return True
return False return False
# Run analysis on a set of preprocessed files. # Run analysis on a set of preprocessed files.
def runAnalyzePreprocessed(Dir, SBOutputDir, Mode): def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
if os.path.exists(os.path.join(Dir, BuildScript)): if os.path.exists(os.path.join(Dir, BuildScript)):
print "Error: The preprocessed files project should not contain %s" % \ print "Error: The preprocessed files project should not contain %s" % \
BuildScript BuildScript
raise Exception() raise Exception()
CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w " CmdPrefix = Clang + " -cc1 -analyze -analyzer-output=plist -w "
CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks " CmdPrefix += "-analyzer-checker=" + Checkers +" -fcxx-exceptions -fblocks "
if (Mode == 2) : if (Mode == 2) :
CmdPrefix += "-std=c++11 " CmdPrefix += "-std=c++11 "
PlistPath = os.path.join(Dir, SBOutputDir, "date") PlistPath = os.path.join(Dir, SBOutputDir, "date")
FailPath = os.path.join(PlistPath, "failures"); FailPath = os.path.join(PlistPath, "failures");
os.makedirs(FailPath); os.makedirs(FailPath);
for FullFileName in glob.glob(Dir + "/*"): for FullFileName in glob.glob(Dir + "/*"):
FileName = os.path.basename(FullFileName) FileName = os.path.basename(FullFileName)
Failed = False Failed = False
# Only run the analyzes on supported files. # Only run the analyzes on supported files.
if (hasNoExtension(FileName)): if (hasNoExtension(FileName)):
continue continue
if (isValidSingleInputFile(FileName) == False): if (isValidSingleInputFile(FileName) == False):
print "Error: Invalid single input file %s." % (FullFileName,) print "Error: Invalid single input file %s." % (FullFileName,)
raise Exception() raise Exception()
# Build and call the analyzer command. # Build and call the analyzer command.
OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist " OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist "
Command = CmdPrefix + OutputOption + FileName Command = CmdPrefix + OutputOption + FileName
LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b") LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b")
try: try:
if Verbose == 1: if Verbose == 1:
print " Executing: %s" % (Command,) print " Executing: %s" % (Command,)
check_call(Command, cwd = Dir, stderr=LogFile, check_call(Command, cwd = Dir, stderr=LogFile,
stdout=LogFile, stdout=LogFile,
shell=True) shell=True)
except CalledProcessError, e: except CalledProcessError, e:
print "Error: Analyzes of %s failed. See %s for details." \ print "Error: Analyzes of %s failed. See %s for details." \
"Error code %d." % \ "Error code %d." % \
(FullFileName, LogFile.name, e.returncode) (FullFileName, LogFile.name, e.returncode)
Failed = True Failed = True
finally: finally:
LogFile.close() LogFile.close()
# If command did not fail, erase the log file. # If command did not fail, erase the log file.
if Failed == False: if Failed == False:
os.remove(LogFile.name); os.remove(LogFile.name);
def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild): def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
TBegin = time.time() TBegin = time.time()
BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName) BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
print "Log file: %s" % (BuildLogPath,) print "Log file: %s" % (BuildLogPath,)
print "Output directory: %s" %(SBOutputDir, ) print "Output directory: %s" %(SBOutputDir, )
# Clean up the log file. # Clean up the log file.
if (os.path.exists(BuildLogPath)) : if (os.path.exists(BuildLogPath)) :
RmCommand = "rm " + BuildLogPath RmCommand = "rm " + BuildLogPath
if Verbose == 1: if Verbose == 1:
print " Executing: %s" % (RmCommand,) print " Executing: %s" % (RmCommand,)
check_call(RmCommand, shell=True) check_call(RmCommand, shell=True)
# Clean up scan build results. # Clean up scan build results.
if (os.path.exists(SBOutputDir)) : if (os.path.exists(SBOutputDir)) :
RmCommand = "rm -r " + SBOutputDir RmCommand = "rm -r " + SBOutputDir
if Verbose == 1: if Verbose == 1:
print " Executing: %s" % (RmCommand,) print " Executing: %s" % (RmCommand,)
check_call(RmCommand, shell=True) check_call(RmCommand, shell=True)
assert(not os.path.exists(SBOutputDir)) assert(not os.path.exists(SBOutputDir))
os.makedirs(os.path.join(SBOutputDir, LogFolderName)) os.makedirs(os.path.join(SBOutputDir, LogFolderName))
# Open the log file. # Open the log file.
PBuildLogFile = open(BuildLogPath, "wb+") PBuildLogFile = open(BuildLogPath, "wb+")
# Build and analyze the project. # Build and analyze the project.
try: try:
runCleanupScript(Dir, PBuildLogFile) runCleanupScript(Dir, PBuildLogFile)
if (ProjectBuildMode == 1): if (ProjectBuildMode == 1):
runScanBuild(Dir, SBOutputDir, PBuildLogFile) runScanBuild(Dir, SBOutputDir, PBuildLogFile)
else: else:
runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode) runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
if IsReferenceBuild : if IsReferenceBuild :
runCleanupScript(Dir, PBuildLogFile) runCleanupScript(Dir, PBuildLogFile)
@ -354,28 +354,28 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
else SourceFile for SourceFile in Data['files']] else SourceFile for SourceFile in Data['files']]
Data['files'] = Paths Data['files'] = Paths
plistlib.writePlist(Data, Plist) plistlib.writePlist(Data, Plist)
finally: finally:
PBuildLogFile.close() PBuildLogFile.close()
print "Build complete (time: %.2f). See the log for more details: %s" % \ print "Build complete (time: %.2f). See the log for more details: %s" % \
((time.time()-TBegin), BuildLogPath) ((time.time()-TBegin), BuildLogPath)
# A plist file is created for each call to the analyzer(each source file). # A plist file is created for each call to the analyzer(each source file).
# We are only interested on the once that have bug reports, so delete the rest. # We are only interested on the once that have bug reports, so delete the rest.
def CleanUpEmptyPlists(SBOutputDir): def CleanUpEmptyPlists(SBOutputDir):
for F in glob.glob(SBOutputDir + "/*/*.plist"): for F in glob.glob(SBOutputDir + "/*/*.plist"):
P = os.path.join(SBOutputDir, F) P = os.path.join(SBOutputDir, F)
Data = plistlib.readPlist(P) Data = plistlib.readPlist(P)
# Delete empty reports. # Delete empty reports.
if not Data['files']: if not Data['files']:
os.remove(P) os.remove(P)
continue continue
# Given the scan-build output directory, checks if the build failed # Given the scan-build output directory, checks if the build failed
# (by searching for the failures directories). If there are failures, it # (by searching for the failures directories). If there are failures, it
# creates a summary file in the output directory. # creates a summary file in the output directory.
def checkBuild(SBOutputDir): def checkBuild(SBOutputDir):
# Check if there are failures. # Check if there are failures.
Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt") Failures = glob.glob(SBOutputDir + "/*/failures/*.stderr.txt")
@ -386,37 +386,37 @@ def checkBuild(SBOutputDir):
print "Number of bug reports (non-empty plist files) produced: %d" %\ print "Number of bug reports (non-empty plist files) produced: %d" %\
len(Plists) len(Plists)
return; return;
# Create summary file to display when the build fails. # Create summary file to display when the build fails.
SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName) SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName)
if (Verbose > 0): if (Verbose > 0):
print " Creating the failures summary file %s" % (SummaryPath,) print " Creating the failures summary file %s" % (SummaryPath,)
SummaryLog = open(SummaryPath, "w+") SummaryLog = open(SummaryPath, "w+")
try: try:
SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,)) SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,))
if TotalFailed > NumOfFailuresInSummary: if TotalFailed > NumOfFailuresInSummary:
SummaryLog.write("See the first %d below.\n" SummaryLog.write("See the first %d below.\n"
% (NumOfFailuresInSummary,)) % (NumOfFailuresInSummary,))
# TODO: Add a line "See the results folder for more." # TODO: Add a line "See the results folder for more."
FailuresCopied = NumOfFailuresInSummary FailuresCopied = NumOfFailuresInSummary
Idx = 0 Idx = 0
for FailLogPathI in Failures: for FailLogPathI in Failures:
if Idx >= NumOfFailuresInSummary: if Idx >= NumOfFailuresInSummary:
break; break;
Idx += 1 Idx += 1
SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,)); SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,));
FailLogI = open(FailLogPathI, "r"); FailLogI = open(FailLogPathI, "r");
try: try:
shutil.copyfileobj(FailLogI, SummaryLog); shutil.copyfileobj(FailLogI, SummaryLog);
finally: finally:
FailLogI.close() FailLogI.close()
finally: finally:
SummaryLog.close() SummaryLog.close()
print "Error: analysis failed. See ", SummaryPath print "Error: analysis failed. See ", SummaryPath
sys.exit(-1) sys.exit(-1)
# Auxiliary object to discard stdout. # Auxiliary object to discard stdout.
class Discarder(object): class Discarder(object):
@ -428,44 +428,44 @@ class Discarder(object):
# 0 - success if there are no crashes or analyzer failure. # 0 - success if there are no crashes or analyzer failure.
# 1 - success if there are no difference in the number of reported bugs. # 1 - success if there are no difference in the number of reported bugs.
# 2 - success if all the bug reports are identical. # 2 - success if all the bug reports are identical.
def runCmpResults(Dir, Strictness = 0): def runCmpResults(Dir, Strictness = 0):
TBegin = time.time() TBegin = time.time()
RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName) RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName)
NewDir = os.path.join(Dir, SBOutputDirName) NewDir = os.path.join(Dir, SBOutputDirName)
# We have to go one level down the directory tree. # We have to go one level down the directory tree.
RefList = glob.glob(RefDir + "/*") RefList = glob.glob(RefDir + "/*")
NewList = glob.glob(NewDir + "/*") NewList = glob.glob(NewDir + "/*")
# Log folders are also located in the results dir, so ignore them. # Log folders are also located in the results dir, so ignore them.
RefLogDir = os.path.join(RefDir, LogFolderName) RefLogDir = os.path.join(RefDir, LogFolderName)
if RefLogDir in RefList: if RefLogDir in RefList:
RefList.remove(RefLogDir) RefList.remove(RefLogDir)
NewList.remove(os.path.join(NewDir, LogFolderName)) NewList.remove(os.path.join(NewDir, LogFolderName))
if len(RefList) == 0 or len(NewList) == 0: if len(RefList) == 0 or len(NewList) == 0:
return False return False
assert(len(RefList) == len(NewList)) assert(len(RefList) == len(NewList))
# There might be more then one folder underneath - one per each scan-build # There might be more then one folder underneath - one per each scan-build
# command (Ex: one for configure and one for make). # command (Ex: one for configure and one for make).
if (len(RefList) > 1): if (len(RefList) > 1):
# Assume that the corresponding folders have the same names. # Assume that the corresponding folders have the same names.
RefList.sort() RefList.sort()
NewList.sort() NewList.sort()
# Iterate and find the differences. # Iterate and find the differences.
NumDiffs = 0 NumDiffs = 0
PairList = zip(RefList, NewList) PairList = zip(RefList, NewList)
for P in PairList: for P in PairList:
RefDir = P[0] RefDir = P[0]
NewDir = P[1] NewDir = P[1]
assert(RefDir != NewDir) assert(RefDir != NewDir)
if Verbose == 1: if Verbose == 1:
print " Comparing Results: %s %s" % (RefDir, NewDir) print " Comparing Results: %s %s" % (RefDir, NewDir)
DiffsPath = os.path.join(NewDir, DiffsSummaryFileName) DiffsPath = os.path.join(NewDir, DiffsSummaryFileName)
Opts = CmpRuns.CmpOptions(DiffsPath, "", Dir) Opts = CmpRuns.CmpOptions(DiffsPath, "", Dir)
# Discard everything coming out of stdout (CmpRun produces a lot of them). # Discard everything coming out of stdout (CmpRun produces a lot of them).
@ -480,70 +480,70 @@ def runCmpResults(Dir, Strictness = 0):
(NumDiffs, DiffsPath,) (NumDiffs, DiffsPath,)
if Strictness >= 2 and NumDiffs > 0: if Strictness >= 2 and NumDiffs > 0:
print "Error: Diffs found in strict mode (2)." print "Error: Diffs found in strict mode (2)."
sys.exit(-1) sys.exit(-1)
elif Strictness >= 1 and ReportsInRef != ReportsInNew: elif Strictness >= 1 and ReportsInRef != ReportsInNew:
print "Error: The number of results are different in strict mode (1)." print "Error: The number of results are different in strict mode (1)."
sys.exit(-1) sys.exit(-1)
print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin) print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
return (NumDiffs > 0) return (NumDiffs > 0)
def updateSVN(Mode, ProjectsMap): def updateSVN(Mode, ProjectsMap):
try: try:
ProjectsMap.seek(0) ProjectsMap.seek(0)
for I in csv.reader(ProjectsMap): for I in csv.reader(ProjectsMap):
ProjName = I[0] ProjName = I[0]
Path = os.path.join(ProjName, getSBOutputDirName(True)) Path = os.path.join(ProjName, getSBOutputDirName(True))
if Mode == "delete": if Mode == "delete":
Command = "svn delete %s" % (Path,) Command = "svn delete %s" % (Path,)
else: else:
Command = "svn add %s" % (Path,) Command = "svn add %s" % (Path,)
if Verbose == 1: if Verbose == 1:
print " Executing: %s" % (Command,) print " Executing: %s" % (Command,)
check_call(Command, shell=True) check_call(Command, shell=True)
if Mode == "delete": if Mode == "delete":
CommitCommand = "svn commit -m \"[analyzer tests] Remove " \ CommitCommand = "svn commit -m \"[analyzer tests] Remove " \
"reference results.\"" "reference results.\""
else: else:
CommitCommand = "svn commit -m \"[analyzer tests] Add new " \ CommitCommand = "svn commit -m \"[analyzer tests] Add new " \
"reference results.\"" "reference results.\""
if Verbose == 1: if Verbose == 1:
print " Executing: %s" % (CommitCommand,) print " Executing: %s" % (CommitCommand,)
check_call(CommitCommand, shell=True) check_call(CommitCommand, shell=True)
except: except:
print "Error: SVN update failed." print "Error: SVN update failed."
sys.exit(-1) sys.exit(-1)
def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictness = 0): def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictness = 0):
print " \n\n--- Building project %s" % (ID,) print " \n\n--- Building project %s" % (ID,)
TBegin = time.time() TBegin = time.time()
if Dir is None : if Dir is None :
Dir = getProjectDir(ID) Dir = getProjectDir(ID)
if Verbose == 1: if Verbose == 1:
print " Build directory: %s." % (Dir,) print " Build directory: %s." % (Dir,)
# Set the build results directory. # Set the build results directory.
RelOutputDir = getSBOutputDirName(IsReferenceBuild) RelOutputDir = getSBOutputDirName(IsReferenceBuild)
SBOutputDir = os.path.join(Dir, RelOutputDir) SBOutputDir = os.path.join(Dir, RelOutputDir)
buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild) buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild)
checkBuild(SBOutputDir) checkBuild(SBOutputDir)
if IsReferenceBuild == False: if IsReferenceBuild == False:
runCmpResults(Dir, Strictness) runCmpResults(Dir, Strictness)
print "Completed tests for project %s (time: %.2f)." % \ print "Completed tests for project %s (time: %.2f)." % \
(ID, (time.time()-TBegin)) (ID, (time.time()-TBegin))
def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0): def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
PMapFile = open(getProjectMapPath(), "rb") PMapFile = open(getProjectMapPath(), "rb")
try: try:
# Validate the input. # Validate the input.
for I in csv.reader(PMapFile): for I in csv.reader(PMapFile):
if (len(I) != 2) : if (len(I) != 2) :
@ -552,16 +552,16 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))): if (not ((I[1] == "0") | (I[1] == "1") | (I[1] == "2"))):
print "Error: Second entry in the ProjectMapFile should be 0" \ print "Error: Second entry in the ProjectMapFile should be 0" \
" (single file), 1 (project), or 2(single file c++11)." " (single file), 1 (project), or 2(single file c++11)."
raise Exception() raise Exception()
# When we are regenerating the reference results, we might need to # When we are regenerating the reference results, we might need to
# update svn. Remove reference results from SVN. # update svn. Remove reference results from SVN.
if UpdateSVN == True: if UpdateSVN == True:
assert(IsReferenceBuild == True); assert(IsReferenceBuild == True);
updateSVN("delete", PMapFile); updateSVN("delete", PMapFile);
# Test the projects. # Test the projects.
PMapFile.seek(0) PMapFile.seek(0)
for I in csv.reader(PMapFile): for I in csv.reader(PMapFile):
testProject(I[0], int(I[1]), IsReferenceBuild, None, Strictness) testProject(I[0], int(I[1]), IsReferenceBuild, None, Strictness)
@ -571,10 +571,10 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
except: except:
print "Error occurred. Premature termination." print "Error occurred. Premature termination."
raise raise
finally: finally:
PMapFile.close() PMapFile.close()
if __name__ == '__main__': if __name__ == '__main__':
# Parse command line arguments. # Parse command line arguments.
Parser = argparse.ArgumentParser(description='Test the Clang Static Analyzer.') Parser = argparse.ArgumentParser(description='Test the Clang Static Analyzer.')

View File

@ -3,7 +3,7 @@
""" """
Script to Summarize statistics in the scan-build output. Script to Summarize statistics in the scan-build output.
Statistics are enabled by passing '-internal-stats' option to scan-build Statistics are enabled by passing '-internal-stats' option to scan-build
(or '-analyzer-stats' to the analyzer). (or '-analyzer-stats' to the analyzer).
""" """
@ -69,7 +69,7 @@ if __name__ == '__main__':
if ((") Total" in line) and (Mode == 1)) : if ((") Total" in line) and (Mode == 1)) :
s = line.split() s = line.split()
TotalTime = TotalTime + float(s[6]) TotalTime = TotalTime + float(s[6])
print "TU Count %d" % (Count) print "TU Count %d" % (Count)
print "Time %f" % (Time) print "Time %f" % (Time)
print "Warnings %d" % (Warnings) print "Warnings %d" % (Warnings)
@ -81,4 +81,3 @@ if __name__ == '__main__':
print "MaxTime %f" % (MaxTime) print "MaxTime %f" % (MaxTime)
print "TotalTime %f" % (TotalTime) print "TotalTime %f" % (TotalTime)
print "Max CFG Size %d" % (MaxCFGSize) print "Max CFG Size %d" % (MaxCFGSize)

View File

@ -18,7 +18,7 @@ import sys
def Error(message): def Error(message):
print >> sys.stderr, 'ubiviz: ' + message print >> sys.stderr, 'ubiviz: ' + message
sys.exit(1) sys.exit(1)
def StreamData(filename): def StreamData(filename):
file = open(filename) file = open(filename)
for ln in file: for ln in file:
@ -55,20 +55,19 @@ def Display(G, data):
def main(args): def main(args):
if len(args) == 0: if len(args) == 0:
Error('no input files') Error('no input files')
server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2') server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2')
G = server.ubigraph G = server.ubigraph
for arg in args: for arg in args:
G.clear() G.clear()
for x in StreamData(arg): for x in StreamData(arg):
Display(G,x) Display(G,x)
sys.exit(0) sys.exit(0)
if __name__ == '__main__': if __name__ == '__main__':
main(sys.argv[1:]) main(sys.argv[1:])