forked from OSchip/llvm-project
[analyzer] Apply whitespace cleanups by Honggyu Kim.
llvm-svn: 246978
This commit is contained in:
parent
21dfbfb426
commit
3a0678e33c
|
@ -101,7 +101,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
|
|||
else if (isa<BlockDecl>(D)) {
|
||||
output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
|
||||
}
|
||||
|
||||
|
||||
NumBlocksUnreachable += unreachable;
|
||||
NumBlocks += total;
|
||||
std::string NameOfRootFunction = output.str();
|
||||
|
|
|
@ -23,7 +23,7 @@ using namespace clang;
|
|||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class ArrayBoundChecker :
|
||||
class ArrayBoundChecker :
|
||||
public Checker<check::Location> {
|
||||
mutable std::unique_ptr<BuiltinBug> BT;
|
||||
|
||||
|
@ -55,8 +55,8 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
|
|||
ProgramStateRef state = C.getState();
|
||||
|
||||
// Get the size of the array.
|
||||
DefinedOrUnknownSVal NumElements
|
||||
= C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
|
||||
DefinedOrUnknownSVal NumElements
|
||||
= C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
|
||||
ER->getValueType());
|
||||
|
||||
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);
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
|
||||
if (!BT)
|
||||
BT.reset(new BuiltinBug(
|
||||
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));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Array bound check succeeded. From this point forward the array bound
|
||||
// should always succeed.
|
||||
C.addTransition(StInBound);
|
||||
|
|
|
@ -26,15 +26,15 @@ using namespace clang;
|
|||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class ArrayBoundCheckerV2 :
|
||||
class ArrayBoundCheckerV2 :
|
||||
public Checker<check::Location> {
|
||||
mutable std::unique_ptr<BuiltinBug> BT;
|
||||
|
||||
enum OOB_Kind { OOB_Precedes, OOB_Excedes, OOB_Tainted };
|
||||
|
||||
|
||||
void reportOOB(CheckerContext &C, ProgramStateRef errorState,
|
||||
OOB_Kind kind) const;
|
||||
|
||||
|
||||
public:
|
||||
void checkLocation(SVal l, bool isLoad, const Stmt*S,
|
||||
CheckerContext &C) const;
|
||||
|
@ -55,7 +55,7 @@ public:
|
|||
|
||||
NonLoc getByteOffset() const { return byteOffset.castAs<NonLoc>(); }
|
||||
const SubRegion *getRegion() const { return baseRegion; }
|
||||
|
||||
|
||||
static RegionRawOffsetV2 computeOffset(ProgramStateRef state,
|
||||
SValBuilder &svalBuilder,
|
||||
SVal location);
|
||||
|
@ -65,12 +65,12 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
static SVal computeExtentBegin(SValBuilder &svalBuilder,
|
||||
static SVal computeExtentBegin(SValBuilder &svalBuilder,
|
||||
const MemRegion *region) {
|
||||
while (true)
|
||||
switch (region->getKind()) {
|
||||
default:
|
||||
return svalBuilder.makeZeroArrayIndex();
|
||||
return svalBuilder.makeZeroArrayIndex();
|
||||
case MemRegion::SymbolicRegionKind:
|
||||
// FIXME: improve this later by tracking symbolic lower bounds
|
||||
// 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
|
||||
// have some flexibility in defining the base region, we can achieve
|
||||
// various levels of conservatism in our buffer overflow checking.
|
||||
ProgramStateRef state = checkerContext.getState();
|
||||
ProgramStateRef state = checkerContext.getState();
|
||||
ProgramStateRef originalState = state;
|
||||
|
||||
SValBuilder &svalBuilder = checkerContext.getSValBuilder();
|
||||
const RegionRawOffsetV2 &rawOffset =
|
||||
const RegionRawOffsetV2 &rawOffset =
|
||||
RegionRawOffsetV2::computeOffset(state, svalBuilder, location);
|
||||
|
||||
if (!rawOffset.getRegion())
|
||||
return;
|
||||
|
||||
// CHECK LOWER BOUND: Is byteOffset < extent begin?
|
||||
// CHECK LOWER BOUND: Is byteOffset < extent begin?
|
||||
// If so, we are doing a load/store
|
||||
// before the first valid offset in the memory region.
|
||||
|
||||
SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion());
|
||||
|
||||
|
||||
if (Optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) {
|
||||
SVal lowerBound =
|
||||
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>();
|
||||
if (!lowerBoundToCheck)
|
||||
return;
|
||||
|
||||
|
||||
ProgramStateRef state_precedesLowerBound, state_withinLowerBound;
|
||||
std::tie(state_precedesLowerBound, state_withinLowerBound) =
|
||||
state->assume(*lowerBoundToCheck);
|
||||
|
@ -128,12 +128,12 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
|
|||
reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, assume the constraint of the lower bound.
|
||||
assert(state_withinLowerBound);
|
||||
state = state_withinLowerBound;
|
||||
}
|
||||
|
||||
|
||||
do {
|
||||
// CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)? If so,
|
||||
// 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(),
|
||||
extentVal.castAs<NonLoc>(),
|
||||
svalBuilder.getConditionType());
|
||||
|
||||
|
||||
Optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>();
|
||||
if (!upperboundToCheck)
|
||||
break;
|
||||
|
||||
|
||||
ProgramStateRef state_exceedsUpperBound, state_withinUpperBound;
|
||||
std::tie(state_exceedsUpperBound, state_withinUpperBound) =
|
||||
state->assume(*upperboundToCheck);
|
||||
|
@ -161,19 +161,19 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
|
|||
reportOOB(checkerContext, state_exceedsUpperBound, OOB_Tainted);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If we are constrained enough to definitely exceed the upper bound, report.
|
||||
if (state_exceedsUpperBound) {
|
||||
assert(!state_withinUpperBound);
|
||||
reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
assert(state_withinUpperBound);
|
||||
state = state_withinUpperBound;
|
||||
}
|
||||
while (false);
|
||||
|
||||
|
||||
if (state != originalState)
|
||||
checkerContext.addTransition(state);
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
|
|||
void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
|
||||
ProgramStateRef errorState,
|
||||
OOB_Kind kind) const {
|
||||
|
||||
|
||||
ExplodedNode *errorNode = checkerContext.generateSink(errorState);
|
||||
if (!errorNode)
|
||||
return;
|
||||
|
@ -259,7 +259,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
|
|||
{
|
||||
const MemRegion *region = location.getAsRegion();
|
||||
SVal offset = UndefinedVal();
|
||||
|
||||
|
||||
while (region) {
|
||||
switch (region->getKind()) {
|
||||
default: {
|
||||
|
@ -280,7 +280,7 @@ RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(ProgramStateRef state,
|
|||
ASTContext &astContext = svalBuilder.getContext();
|
||||
if (elemType->isIncompleteType())
|
||||
return RegionRawOffsetV2();
|
||||
|
||||
|
||||
// Update the offset.
|
||||
offset = addValue(state,
|
||||
getValue(offset, svalBuilder),
|
||||
|
|
|
@ -143,7 +143,7 @@ void NilArgChecker::warnIfNilExpr(const Expr *E,
|
|||
if (ExplodedNode *N = C.generateSink()) {
|
||||
generateBugReport(N, Msg, E->getSourceRange(), E, C);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C,
|
|||
ProgramStateRef State = C.getState();
|
||||
if (!State->isNull(msg.getArgSVal(Arg)).isConstrainedTrue())
|
||||
return;
|
||||
|
||||
|
||||
if (ExplodedNode *N = C.generateSink()) {
|
||||
SmallString<128> sbuf;
|
||||
llvm::raw_svector_ostream os(sbuf);
|
||||
|
@ -193,7 +193,7 @@ void NilArgChecker::warnIfNilArg(CheckerContext &C,
|
|||
os << "' cannot be nil";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
generateBugReport(N, os.str(), msg.getArgSourceRange(Arg),
|
||||
msg.getArgExpr(Arg), C);
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ void NilArgChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
|||
static const unsigned InvalidArgIndex = UINT_MAX;
|
||||
unsigned Arg = InvalidArgIndex;
|
||||
bool CanBeSubscript = false;
|
||||
|
||||
|
||||
if (Class == FC_NSString) {
|
||||
Selector S = msg.getSelector();
|
||||
|
||||
|
@ -433,7 +433,7 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE,
|
|||
const FunctionDecl *FD = C.getCalleeDecl(CE);
|
||||
if (!FD)
|
||||
return;
|
||||
|
||||
|
||||
ASTContext &Ctx = C.getASTContext();
|
||||
if (!II)
|
||||
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
|
||||
// the bits initialized to the provided values.
|
||||
//
|
||||
if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
|
||||
if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
|
||||
: C.addTransition()) {
|
||||
SmallString<128> sbuf;
|
||||
llvm::raw_svector_ostream os(sbuf);
|
||||
|
||||
|
||||
os << (SourceSize == 8 ? "An " : "A ")
|
||||
<< SourceSize << " bit integer is used to initialize a CFNumber "
|
||||
"object that represents "
|
||||
<< (TargetSize == 8 ? "an " : "a ")
|
||||
<< TargetSize << " bit integer. ";
|
||||
|
||||
|
||||
if (SourceSize < TargetSize)
|
||||
os << (TargetSize - SourceSize)
|
||||
<< " bits of the CFNumber value will be garbage." ;
|
||||
|
@ -549,7 +549,7 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE,
|
|||
const FunctionDecl *FD = C.getCalleeDecl(CE);
|
||||
if (!FD)
|
||||
return;
|
||||
|
||||
|
||||
if (!BT) {
|
||||
ASTContext &Ctx = C.getASTContext();
|
||||
Retain = &Ctx.Idents.get("CFRetain");
|
||||
|
@ -635,7 +635,7 @@ public:
|
|||
|
||||
void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
||||
CheckerContext &C) const {
|
||||
|
||||
|
||||
if (!BT) {
|
||||
BT.reset(new APIMisuse(
|
||||
this, "message incorrectly sent to class instead of class instance"));
|
||||
|
@ -646,7 +646,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
|||
autoreleaseS = GetNullarySelector("autorelease", Ctx);
|
||||
drainS = GetNullarySelector("drain", Ctx);
|
||||
}
|
||||
|
||||
|
||||
if (msg.isInstanceMessage())
|
||||
return;
|
||||
const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
|
||||
|
@ -655,7 +655,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
|||
Selector S = msg.getSelector();
|
||||
if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
|
||||
return;
|
||||
|
||||
|
||||
if (ExplodedNode *N = C.addTransition()) {
|
||||
SmallString<200> buf;
|
||||
llvm::raw_svector_ostream os(buf);
|
||||
|
@ -665,7 +665,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
|||
os << "' message should be sent to instances "
|
||||
"of class '" << Class->getName()
|
||||
<< "' and not the class directly";
|
||||
|
||||
|
||||
auto report = llvm::make_unique<BugReport>(*BT, os.str(), N);
|
||||
report->addRange(msg.getSourceRange());
|
||||
C.emitReport(std::move(report));
|
||||
|
@ -699,12 +699,12 @@ public:
|
|||
bool
|
||||
VariadicMethodTypeChecker::isVariadicMessage(const ObjCMethodCall &msg) const {
|
||||
const ObjCMethodDecl *MD = msg.getDecl();
|
||||
|
||||
|
||||
if (!MD || !MD->isVariadic() || isa<ObjCProtocolDecl>(MD->getDeclContext()))
|
||||
return false;
|
||||
|
||||
|
||||
Selector S = msg.getSelector();
|
||||
|
||||
|
||||
if (msg.isInstanceMessage()) {
|
||||
// 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
|
||||
|
@ -751,7 +751,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
|||
|
||||
ASTContext &Ctx = C.getASTContext();
|
||||
arrayWithObjectsS = GetUnarySelector("arrayWithObjects", Ctx);
|
||||
dictionaryWithObjectsAndKeysS =
|
||||
dictionaryWithObjectsAndKeysS =
|
||||
GetUnarySelector("dictionaryWithObjectsAndKeys", Ctx);
|
||||
setWithObjectsS = GetUnarySelector("setWithObjects", Ctx);
|
||||
orderedSetWithObjectsS = GetUnarySelector("orderedSetWithObjects", Ctx);
|
||||
|
@ -789,11 +789,11 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
|
|||
// Ignore pointer constants.
|
||||
if (msg.getArgSVal(I).getAs<loc::ConcreteInt>())
|
||||
continue;
|
||||
|
||||
|
||||
// Ignore pointer types annotated with 'NSObject' attribute.
|
||||
if (C.getASTContext().isObjCNSObjectType(ArgTy))
|
||||
continue;
|
||||
|
||||
|
||||
// Ignore CF references, which can be toll-free bridged.
|
||||
if (coreFoundation::isCFObjectRef(ArgTy))
|
||||
continue;
|
||||
|
@ -861,7 +861,7 @@ static bool isKnownNonNilCollectionType(QualType T) {
|
|||
const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>();
|
||||
if (!PT)
|
||||
return false;
|
||||
|
||||
|
||||
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
|
||||
if (!ID)
|
||||
return false;
|
||||
|
@ -1023,7 +1023,7 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS,
|
|||
State = checkElementNonNil(C, State, FCS);
|
||||
State = assumeCollectionNonEmpty(C, State, FCS, /*Assumption*/true);
|
||||
}
|
||||
|
||||
|
||||
if (!State)
|
||||
C.generateSink();
|
||||
else if (State != C.getState())
|
||||
|
@ -1041,7 +1041,7 @@ bool ObjCLoopChecker::isCollectionCountMethod(const ObjCMethodCall &M,
|
|||
if (S.isUnarySelector() &&
|
||||
(S.getIdentifierInfoForSlot(0) == CountSelectorII))
|
||||
return true;
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1069,7 +1069,7 @@ void ObjCLoopChecker::checkPostObjCMessage(const ObjCMethodCall &M,
|
|||
// a call to "count" and add it to the map.
|
||||
if (!isCollectionCountMethod(M, C))
|
||||
return;
|
||||
|
||||
|
||||
const Expr *MsgExpr = M.getOriginExpr();
|
||||
SymbolRef CountS = C.getSVal(MsgExpr).getAsSymbol();
|
||||
if (CountS) {
|
||||
|
|
|
@ -42,45 +42,45 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state,
|
|||
static bool isBooleanType(QualType Ty) {
|
||||
if (Ty->isBooleanType()) // C++ or C99
|
||||
return true;
|
||||
|
||||
|
||||
if (const TypedefType *TT = Ty->getAs<TypedefType>())
|
||||
return TT->getDecl()->getName() == "BOOL" || // Objective-C
|
||||
TT->getDecl()->getName() == "_Bool" || // stdbool.h < C99
|
||||
TT->getDecl()->getName() == "Boolean"; // MacTypes.h
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
|
||||
CheckerContext &C) const {
|
||||
|
||||
|
||||
// We are only interested in stores into Booleans.
|
||||
const TypedValueRegion *TR =
|
||||
dyn_cast_or_null<TypedValueRegion>(loc.getAsRegion());
|
||||
|
||||
|
||||
if (!TR)
|
||||
return;
|
||||
|
||||
|
||||
QualType valTy = TR->getValueType();
|
||||
|
||||
|
||||
if (!isBooleanType(valTy))
|
||||
return;
|
||||
|
||||
|
||||
// Get the value of the right-hand side. We only care about values
|
||||
// that are defined (UnknownVals and UndefinedVals are handled by other
|
||||
// checkers).
|
||||
Optional<DefinedSVal> DV = val.getAs<DefinedSVal>();
|
||||
if (!DV)
|
||||
return;
|
||||
|
||||
|
||||
// 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
|
||||
// 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();
|
||||
ConstraintManager &CM = C.getConstraintManager();
|
||||
|
||||
// First, ensure that the value is >= 0.
|
||||
|
||||
// First, ensure that the value is >= 0.
|
||||
DefinedSVal zeroVal = svalBuilder.makeIntVal(0, valTy);
|
||||
SVal greaterThanOrEqualToZeroVal =
|
||||
svalBuilder.evalBinOp(state, BO_GE, *DV, zeroVal,
|
||||
|
@ -91,13 +91,13 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
|
|||
|
||||
if (!greaterThanEqualToZero) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
ProgramStateRef stateLT, stateGE;
|
||||
std::tie(stateGE, stateLT) = CM.assumeDual(state, *greaterThanEqualToZero);
|
||||
|
||||
|
||||
// Is it possible for the value to be less than zero?
|
||||
if (stateLT) {
|
||||
// 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.
|
||||
if (!stateGE)
|
||||
emitReport(stateLT, C);
|
||||
|
||||
|
||||
// In either case, we are done.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If we reach here, it must be the case that the value is constrained
|
||||
// to only be >= 0.
|
||||
assert(stateGE == state);
|
||||
|
||||
|
||||
// At this point we know that the value is >= 0.
|
||||
// Now check to ensure that the value is <= 1.
|
||||
DefinedSVal OneVal = svalBuilder.makeIntVal(1, valTy);
|
||||
|
@ -127,13 +127,13 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
|
|||
|
||||
if (!lessThanEqToOne) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
ProgramStateRef stateGT, stateLE;
|
||||
std::tie(stateLE, stateGT) = CM.assumeDual(state, *lessThanEqToOne);
|
||||
|
||||
|
||||
// Is it possible for the value to be greater than one?
|
||||
if (stateGT) {
|
||||
// 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.
|
||||
if (!stateLE)
|
||||
emitReport(stateGT, C);
|
||||
|
||||
|
||||
// In either case, we are done.
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// If we reach here, it must be the case that the value is constrained
|
||||
// to only be <= 1.
|
||||
assert(stateLE == state);
|
||||
|
|
|
@ -65,7 +65,7 @@ public:
|
|||
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
|
||||
bool wantsRegionChangeUpdate(ProgramStateRef state) const;
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
checkRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
|
@ -92,7 +92,7 @@ public:
|
|||
void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
|
||||
void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
|
||||
void evalstrLengthCommon(CheckerContext &C,
|
||||
const CallExpr *CE,
|
||||
const CallExpr *CE,
|
||||
bool IsStrnlen = false) const;
|
||||
|
||||
void evalStrcpy(CheckerContext &C, const CallExpr *CE) const;
|
||||
|
@ -137,9 +137,9 @@ public:
|
|||
SVal Buf,
|
||||
bool hypothetical = false) const;
|
||||
|
||||
const StringLiteral *getCStringLiteral(CheckerContext &C,
|
||||
const StringLiteral *getCStringLiteral(CheckerContext &C,
|
||||
ProgramStateRef &state,
|
||||
const Expr *expr,
|
||||
const Expr *expr,
|
||||
SVal val) const;
|
||||
|
||||
static ProgramStateRef InvalidateBuffer(CheckerContext &C,
|
||||
|
@ -282,7 +282,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
|
|||
// Get the size of the array.
|
||||
const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
|
||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||
SVal Extent =
|
||||
SVal Extent =
|
||||
svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
|
||||
DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>();
|
||||
|
||||
|
@ -327,7 +327,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
|
|||
C.emitReport(std::move(report));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Array bound check succeeded. From this point forward the array bound
|
||||
// should always succeed.
|
||||
return StInBound;
|
||||
|
@ -442,7 +442,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
|
|||
return state;
|
||||
|
||||
// Are the two values the same?
|
||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||
SValBuilder &svalBuilder = C.getSValBuilder();
|
||||
std::tie(stateTrue, stateFalse) =
|
||||
state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc));
|
||||
|
||||
|
@ -489,7 +489,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
|
|||
// Bail out if the cast fails.
|
||||
ASTContext &Ctx = svalBuilder.getContext();
|
||||
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
|
||||
SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy,
|
||||
SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy,
|
||||
First->getType());
|
||||
Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
|
||||
if (!FirstStartLoc)
|
||||
|
@ -568,7 +568,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
|
|||
} else {
|
||||
// Try switching the operands. (The order of these two assignments is
|
||||
// important!)
|
||||
maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left,
|
||||
maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left,
|
||||
sizeTy);
|
||||
left = right;
|
||||
}
|
||||
|
@ -723,7 +723,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
|
|||
auto report = llvm::make_unique<BugReport>(*BT_NotCString, os.str(), N);
|
||||
|
||||
report->addRange(Ex->getSourceRange());
|
||||
C.emitReport(std::move(report));
|
||||
C.emitReport(std::move(report));
|
||||
}
|
||||
return UndefinedVal();
|
||||
|
||||
|
@ -787,7 +787,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
|
|||
auto report = llvm::make_unique<BugReport>(*BT_NotCString, os.str(), N);
|
||||
|
||||
report->addRange(Ex->getSourceRange());
|
||||
C.emitReport(std::move(report));
|
||||
C.emitReport(std::move(report));
|
||||
}
|
||||
|
||||
return UndefinedVal();
|
||||
|
@ -843,13 +843,13 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
|
|||
// Invalidate and escape only indirect regions accessible through the source
|
||||
// buffer.
|
||||
if (IsSourceBuffer) {
|
||||
ITraits.setTrait(R,
|
||||
ITraits.setTrait(R,
|
||||
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
|
||||
ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
|
||||
CausesPointerEscape = true;
|
||||
}
|
||||
|
||||
return state->invalidateRegions(R, E, C.blockCount(), LCtx,
|
||||
return state->invalidateRegions(R, E, C.blockCount(), LCtx,
|
||||
CausesPointerEscape, nullptr, nullptr,
|
||||
&ITraits);
|
||||
}
|
||||
|
@ -901,7 +901,7 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
|
|||
// evaluation of individual function calls.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void CStringChecker::evalCopyCommon(CheckerContext &C,
|
||||
void CStringChecker::evalCopyCommon(CheckerContext &C,
|
||||
const CallExpr *CE,
|
||||
ProgramStateRef state,
|
||||
const Expr *Size, const Expr *Dest,
|
||||
|
@ -941,7 +941,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
|
|||
|
||||
// Get the value of the Src.
|
||||
SVal srcVal = state->getSVal(Source, LCtx);
|
||||
|
||||
|
||||
// Ensure the source is not null. If it is NULL there will be a
|
||||
// NULL pointer dereference.
|
||||
state = checkNonNull(C, state, Source, srcVal);
|
||||
|
@ -959,11 +959,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
|
|||
if (!state)
|
||||
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.
|
||||
if (IsMempcpy) {
|
||||
loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>();
|
||||
|
||||
|
||||
// Get the length to copy.
|
||||
if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) {
|
||||
// Get the byte after the last byte copied.
|
||||
|
@ -972,11 +972,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
|
|||
QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
|
||||
loc::MemRegionVal DestRegCharVal = SvalBuilder.evalCast(destRegVal,
|
||||
CharPtrTy, Dest->getType()).castAs<loc::MemRegionVal>();
|
||||
SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
|
||||
SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add,
|
||||
DestRegCharVal,
|
||||
*lenValNonLoc,
|
||||
*lenValNonLoc,
|
||||
Dest->getType());
|
||||
|
||||
|
||||
// The byte after the last byte copied is the return value.
|
||||
state = state->BindExpr(CE, LCtx, lastElement);
|
||||
} else {
|
||||
|
@ -999,12 +999,12 @@ void CStringChecker::evalCopyCommon(CheckerContext &C,
|
|||
// can use LazyCompoundVals to copy the source values into the destination.
|
||||
// This would probably remove any existing bindings past the end of the
|
||||
// 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);
|
||||
|
||||
// Invalidate the source (const-invalidation without const-pointer-escaping
|
||||
// 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);
|
||||
|
||||
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.
|
||||
const Expr *Dest = CE->getArg(0);
|
||||
ProgramStateRef state = C.getState();
|
||||
|
||||
|
||||
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;
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
|
@ -1244,7 +1244,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
|
|||
state, BO_LE, resultNL, *strLengthNL, cmpTy)
|
||||
.castAs<DefinedOrUnknownSVal>(), true);
|
||||
}
|
||||
|
||||
|
||||
if (maxlenValNL) {
|
||||
state = state->assume(C.getSValBuilder().evalBinOpNN(
|
||||
state, BO_LE, resultNL, *maxlenValNL, cmpTy)
|
||||
|
@ -1275,8 +1275,8 @@ void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
|
|||
return;
|
||||
|
||||
// char *strcpy(char *restrict dst, const char *restrict src);
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ false,
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ false,
|
||||
/* isBounded = */ false,
|
||||
/* isAppending = */ false);
|
||||
}
|
||||
|
@ -1286,8 +1286,8 @@ void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
|
|||
return;
|
||||
|
||||
// char *strncpy(char *restrict dst, const char *restrict src, size_t n);
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ false,
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ false,
|
||||
/* isBounded = */ true,
|
||||
/* isAppending = */ false);
|
||||
}
|
||||
|
@ -1297,8 +1297,8 @@ void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
|
|||
return;
|
||||
|
||||
// char *stpcpy(char *restrict dst, const char *restrict src);
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ true,
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ true,
|
||||
/* isBounded = */ false,
|
||||
/* isAppending = */ false);
|
||||
}
|
||||
|
@ -1308,8 +1308,8 @@ void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
|
|||
return;
|
||||
|
||||
//char *strcat(char *restrict s1, const char *restrict s2);
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ false,
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ false,
|
||||
/* isBounded = */ false,
|
||||
/* isAppending = */ true);
|
||||
}
|
||||
|
@ -1319,8 +1319,8 @@ void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
|
|||
return;
|
||||
|
||||
//char *strncat(char *restrict s1, const char *restrict s2, size_t n);
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ false,
|
||||
evalStrcpyCommon(C, CE,
|
||||
/* returnEnd = */ false,
|
||||
/* isBounded = */ true,
|
||||
/* isAppending = */ true);
|
||||
}
|
||||
|
@ -1515,7 +1515,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
|
|||
|
||||
Optional<NonLoc> srcStrLengthNL = amountCopied.getAs<NonLoc>();
|
||||
Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
|
||||
|
||||
|
||||
// If we know both string lengths, we might know the final string length.
|
||||
if (srcStrLengthNL && dstStrLengthNL) {
|
||||
// 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)
|
||||
return;
|
||||
|
||||
finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *srcStrLengthNL,
|
||||
finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *srcStrLengthNL,
|
||||
*dstStrLengthNL, sizeTy);
|
||||
}
|
||||
|
||||
|
@ -1586,7 +1586,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
|
|||
if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
|
||||
SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
|
||||
*maxLastNL, ptrTy);
|
||||
state = CheckLocation(C, state, CE->getArg(2), maxLastElement,
|
||||
state = CheckLocation(C, state, CE->getArg(2), maxLastElement,
|
||||
boundWarning);
|
||||
if (!state)
|
||||
return;
|
||||
|
@ -1667,7 +1667,7 @@ void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const {
|
|||
evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false);
|
||||
}
|
||||
|
||||
void CStringChecker::evalStrcasecmp(CheckerContext &C,
|
||||
void CStringChecker::evalStrcasecmp(CheckerContext &C,
|
||||
const CallExpr *CE) const {
|
||||
if (CE->getNumArgs() < 2)
|
||||
return;
|
||||
|
@ -1676,7 +1676,7 @@ void CStringChecker::evalStrcasecmp(CheckerContext &C,
|
|||
evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true);
|
||||
}
|
||||
|
||||
void CStringChecker::evalStrncasecmp(CheckerContext &C,
|
||||
void CStringChecker::evalStrncasecmp(CheckerContext &C,
|
||||
const CallExpr *CE) const {
|
||||
if (CE->getNumArgs() < 3)
|
||||
return;
|
||||
|
@ -1915,7 +1915,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
|
|||
evalFunction = &CStringChecker::evalBcopy;
|
||||
else if (C.isCLibraryFunction(FDecl, "bcmp"))
|
||||
evalFunction = &CStringChecker::evalMemcmp;
|
||||
|
||||
|
||||
// If the callee isn't a string function, let another checker handle it.
|
||||
if (!evalFunction)
|
||||
return false;
|
||||
|
@ -1975,7 +1975,7 @@ bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const {
|
|||
return !Entries.isEmpty();
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
CStringChecker::checkRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
|
|
|
@ -51,7 +51,7 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
|
|||
if (E->getDecl()->getIdentifier() == SelfII)
|
||||
if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
|
||||
ME->getNumArgs() == 1 &&
|
||||
ME->getArg(0)->isNullPointerConstant(Ctx,
|
||||
ME->getArg(0)->isNullPointerConstant(Ctx,
|
||||
Expr::NPC_ValueDependentIsNull))
|
||||
return true;
|
||||
|
||||
|
@ -61,7 +61,7 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID,
|
|||
if (ObjCPropertyRefExpr *PRE =
|
||||
dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
|
||||
if (PRE->isExplicitProperty() && PRE->getExplicitProperty() == PD)
|
||||
if (BO->getRHS()->isNullPointerConstant(Ctx,
|
||||
if (BO->getRHS()->isNullPointerConstant(Ctx,
|
||||
Expr::NPC_ValueDependentIsNull)) {
|
||||
// This is only a 'release' if the property kind is not
|
||||
// 'assign'.
|
||||
|
|
|
@ -115,7 +115,7 @@ void WalkAST::VisitChildren(Stmt *S) {
|
|||
}
|
||||
|
||||
void WalkAST::VisitCallExpr(CallExpr *CE) {
|
||||
// Get the callee.
|
||||
// Get the callee.
|
||||
const FunctionDecl *FD = CE->getDirectCallee();
|
||||
|
||||
if (!FD)
|
||||
|
@ -307,7 +307,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
|
|||
void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
|
||||
if (!filter.check_gets)
|
||||
return;
|
||||
|
||||
|
||||
const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
|
||||
if (!FPT)
|
||||
return;
|
||||
|
@ -434,18 +434,18 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
|
|||
.Case("mkdtemp", std::make_pair(0,-1))
|
||||
.Case("mkstemps", std::make_pair(0,1))
|
||||
.Default(std::make_pair(-1, -1));
|
||||
|
||||
|
||||
assert(ArgSuffix.first >= 0 && "Unsupported function");
|
||||
|
||||
// Check if the number of arguments is consistent with out expectations.
|
||||
unsigned numArgs = CE->getNumArgs();
|
||||
if ((signed) numArgs <= ArgSuffix.first)
|
||||
return;
|
||||
|
||||
|
||||
const StringLiteral *strArg =
|
||||
dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
|
||||
->IgnoreParenImpCasts());
|
||||
|
||||
|
||||
// Currently we only handle string literals. It is possible to do better,
|
||||
// either by looking at references to const variables, or by doing real
|
||||
// flow analysis.
|
||||
|
@ -470,13 +470,13 @@ void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
|
|||
suffix = (unsigned) Result.getZExtValue();
|
||||
n = (n > suffix) ? n - suffix : 0;
|
||||
}
|
||||
|
||||
|
||||
for (unsigned i = 0; i < n; ++i)
|
||||
if (str[i] == 'X') ++numX;
|
||||
|
||||
|
||||
if (numX >= 6)
|
||||
return;
|
||||
|
||||
|
||||
// Issue a warning.
|
||||
PathDiagnosticLocation CELoc =
|
||||
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.
|
||||
//
|
||||
// CWE-119: Improper Restriction of Operations within
|
||||
// the Bounds of a Memory Buffer
|
||||
// CWE-119: Improper Restriction of Operations within
|
||||
// the Bounds of a Memory Buffer
|
||||
//===----------------------------------------------------------------------===//
|
||||
void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
|
||||
if (!filter.check_strcpy)
|
||||
return;
|
||||
|
||||
|
||||
if (!checkCall_strCommon(CE, FD))
|
||||
return;
|
||||
|
||||
|
@ -529,8 +529,8 @@ void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
|
|||
//===----------------------------------------------------------------------===//
|
||||
// Check: Any use of 'strcat' is insecure.
|
||||
//
|
||||
// CWE-119: Improper Restriction of Operations within
|
||||
// the Bounds of a Memory Buffer
|
||||
// CWE-119: Improper Restriction of Operations within
|
||||
// the Bounds of a Memory Buffer
|
||||
//===----------------------------------------------------------------------===//
|
||||
void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
|
||||
if (!filter.check_strcpy)
|
||||
|
@ -684,7 +684,7 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
|
|||
void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
|
||||
if (!filter.check_UncheckedReturn)
|
||||
return;
|
||||
|
||||
|
||||
const FunctionDecl *FD = CE->getDirectCallee();
|
||||
if (!FD)
|
||||
return;
|
||||
|
@ -749,7 +749,7 @@ namespace {
|
|||
class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
|
||||
public:
|
||||
ChecksFilter filter;
|
||||
|
||||
|
||||
void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
|
||||
BugReporter &BR) const {
|
||||
WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
|
||||
|
|
|
@ -55,8 +55,8 @@ void WalkAST::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) {
|
|||
QualType T = E->getTypeOfArgument();
|
||||
if (T->isPointerType()) {
|
||||
|
||||
// Many false positives have the form 'sizeof *p'. This is reasonable
|
||||
// because people know what they are doing when they intentionally
|
||||
// Many false positives have the form 'sizeof *p'. This is reasonable
|
||||
// because people know what they are doing when they intentionally
|
||||
// dereference the pointer.
|
||||
Expr *ArgEx = E->getArgumentExpr();
|
||||
if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
|
||||
|
|
|
@ -222,7 +222,7 @@ public:
|
|||
/// changed, this allows the analyzer core to skip the more expensive
|
||||
/// #checkRegionChanges when no checkers are tracking any state.
|
||||
bool wantsRegionChangeUpdate(ProgramStateRef St) const { return true; }
|
||||
|
||||
|
||||
/// \brief Called when the contents of one or more regions change.
|
||||
///
|
||||
/// This can occur in many different ways: an explicit bind, a blanket
|
||||
|
@ -246,7 +246,7 @@ public:
|
|||
/// #wantsRegionChangeUpdate returns \c true.
|
||||
///
|
||||
/// check::RegionChanges
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
checkRegionChanges(ProgramStateRef State,
|
||||
const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
|
@ -259,12 +259,12 @@ public:
|
|||
///
|
||||
/// This notifies the checkers about pointer escape, which occurs whenever
|
||||
/// 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.
|
||||
///
|
||||
///
|
||||
/// \param State The state at the point of escape.
|
||||
/// \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.
|
||||
/// \param Kind How the symbols have escaped.
|
||||
/// \returns Checkers can modify the state by returning a new state.
|
||||
|
@ -285,7 +285,7 @@ public:
|
|||
PointerEscapeKind Kind) const {
|
||||
return State;
|
||||
}
|
||||
|
||||
|
||||
/// check::Event<ImplicitNullDerefEvent>
|
||||
void checkEvent(ImplicitNullDerefEvent Event) const {}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden;
|
|||
def Security : Package <"security">;
|
||||
def InsecureAPI : Package<"insecureAPI">, InPackage<Security>;
|
||||
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 UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden;
|
||||
|
@ -192,7 +192,7 @@ def UndefBranchChecker : Checker<"Branch">,
|
|||
def UndefCapturedBlockVarChecker : Checker<"CapturedBlockVariable">,
|
||||
HelpText<"Check for blocks that capture uninitialized values">,
|
||||
DescFile<"UndefCapturedBlockVarChecker.cpp">;
|
||||
|
||||
|
||||
def ReturnUndefChecker : Checker<"UndefReturn">,
|
||||
HelpText<"Check for uninitialized values being returned to the caller">,
|
||||
DescFile<"ReturnUndefChecker.cpp">;
|
||||
|
@ -206,11 +206,11 @@ def ReturnUndefChecker : Checker<"UndefReturn">,
|
|||
let ParentPackage = Cplusplus in {
|
||||
|
||||
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">;
|
||||
|
||||
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">;
|
||||
|
||||
} // end: "cplusplus"
|
||||
|
@ -218,7 +218,7 @@ def NewDeleteLeaksChecker : Checker<"NewDeleteLeaks">,
|
|||
let ParentPackage = CplusplusAlpha in {
|
||||
|
||||
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">;
|
||||
|
||||
} // end: "alpha.cplusplus"
|
||||
|
@ -282,7 +282,7 @@ let ParentPackage = SecurityAlpha in {
|
|||
|
||||
def ArrayBoundChecker : Checker<"ArrayBound">,
|
||||
HelpText<"Warn about buffer overflows (older checker)">,
|
||||
DescFile<"ArrayBoundChecker.cpp">;
|
||||
DescFile<"ArrayBoundChecker.cpp">;
|
||||
|
||||
def ArrayBoundCheckerV2 : Checker<"ArrayBoundV2">,
|
||||
HelpText<"Warn about buffer overflows (newer checker)">,
|
||||
|
@ -323,7 +323,7 @@ def UnixAPIChecker : Checker<"API">,
|
|||
def MallocChecker: Checker<"Malloc">,
|
||||
HelpText<"Check for memory leaks, double free, and use-after-free problems. Traces memory managed by malloc()/free().">,
|
||||
DescFile<"MallocChecker.cpp">;
|
||||
|
||||
|
||||
def MallocSizeofChecker : Checker<"MallocSizeof">,
|
||||
HelpText<"Check for dubious malloc arguments involving sizeof">,
|
||||
DescFile<"MallocSizeofChecker.cpp">;
|
||||
|
@ -331,7 +331,7 @@ def MallocSizeofChecker : Checker<"MallocSizeof">,
|
|||
def MismatchedDeallocatorChecker : Checker<"MismatchedDeallocator">,
|
||||
HelpText<"Check for mismatched deallocators.">,
|
||||
DescFile<"MallocChecker.cpp">;
|
||||
|
||||
|
||||
} // end "unix"
|
||||
|
||||
let ParentPackage = UnixAlpha in {
|
||||
|
@ -362,7 +362,7 @@ def CStringNullArg : Checker<"NullArg">,
|
|||
|
||||
def CStringSyntaxChecker : Checker<"BadSizeArg">,
|
||||
HelpText<"Check the size argument passed into C string functions for common erroneous patterns">,
|
||||
DescFile<"CStringSyntaxChecker.cpp">;
|
||||
DescFile<"CStringSyntaxChecker.cpp">;
|
||||
}
|
||||
|
||||
let ParentPackage = CStringAlpha in {
|
||||
|
@ -514,7 +514,7 @@ def ObjCContainersASTChecker : Checker<"PointerSizedValues">,
|
|||
def ObjCContainersChecker : Checker<"OutOfBounds">,
|
||||
HelpText<"Checks for index out-of-bounds when using 'CFArray' API">,
|
||||
DescFile<"ObjCContainersChecker.cpp">;
|
||||
|
||||
|
||||
}
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Checkers for LLVM development.
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace {
|
|||
|
||||
// enum value that represent the jail state
|
||||
enum Kind { NO_CHROOT, ROOT_CHANGED, JAIL_ENTERED };
|
||||
|
||||
|
||||
bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
|
||||
//bool isJailEntered(intptr_t k) { return k == JAIL_ENTERED; }
|
||||
|
||||
|
@ -50,7 +50,7 @@ public:
|
|||
static int x;
|
||||
return &x;
|
||||
}
|
||||
|
||||
|
||||
bool evalCall(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 {
|
||||
ProgramStateRef state = C.getState();
|
||||
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.
|
||||
state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
|
||||
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.
|
||||
const Expr *ArgExpr = CE->getArg(0);
|
||||
SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext());
|
||||
|
||||
|
||||
if (const MemRegion *R = ArgVal.getAsRegion()) {
|
||||
R = R->StripCasts();
|
||||
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.
|
||||
if (FD->getIdentifier() == II_chroot || FD->getIdentifier() == II_chdir)
|
||||
return;
|
||||
|
||||
|
||||
// If jail state is ROOT_CHANGED, generate BugReport.
|
||||
void *const* k = C.getState()->FindGDM(ChrootChecker::getTag());
|
||||
if (k)
|
||||
|
|
|
@ -28,36 +28,36 @@
|
|||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
|
||||
namespace {
|
||||
|
||||
/// A simple visitor to record what VarDecls occur in EH-handling code.
|
||||
class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
|
||||
public:
|
||||
bool inEH;
|
||||
llvm::DenseSet<const VarDecl *> &S;
|
||||
|
||||
|
||||
bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
|
||||
SaveAndRestore<bool> inFinally(inEH, true);
|
||||
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
|
||||
}
|
||||
|
||||
|
||||
bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
|
||||
SaveAndRestore<bool> inCatch(inEH, true);
|
||||
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
|
||||
}
|
||||
|
||||
|
||||
bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
|
||||
SaveAndRestore<bool> inCatch(inEH, true);
|
||||
return TraverseStmt(S->getHandlerBlock());
|
||||
}
|
||||
|
||||
|
||||
bool VisitDeclRefExpr(DeclRefExpr *DR) {
|
||||
if (inEH)
|
||||
if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
|
||||
S.insert(D);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
|
||||
inEH(false), S(S) {}
|
||||
};
|
||||
|
@ -70,9 +70,9 @@ class ReachableCode {
|
|||
public:
|
||||
ReachableCode(const CFG &cfg)
|
||||
: cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
|
||||
|
||||
|
||||
void computeReachableBlocks();
|
||||
|
||||
|
||||
bool isReachable(const CFGBlock *block) const {
|
||||
return reachable[block->getBlockID()];
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ public:
|
|||
void ReachableCode::computeReachableBlocks() {
|
||||
if (!cfg.getNumBlockIDs())
|
||||
return;
|
||||
|
||||
|
||||
SmallVector<const CFGBlock*, 10> worklist;
|
||||
worklist.push_back(&cfg.getEntry());
|
||||
|
||||
|
@ -160,19 +160,19 @@ public:
|
|||
// to analyze that yet.
|
||||
return InEH->count(D);
|
||||
}
|
||||
|
||||
|
||||
void Report(const VarDecl *V, DeadStoreKind dsk,
|
||||
PathDiagnosticLocation L, SourceRange R) {
|
||||
if (Escaped.count(V))
|
||||
return;
|
||||
|
||||
|
||||
// Compute reachable blocks within the CFG for trivial cases
|
||||
// where a bogus dead store can be reported because itself is unreachable.
|
||||
if (!reachableCode.get()) {
|
||||
reachableCode.reset(new ReachableCode(cfg));
|
||||
reachableCode->computeReachableBlocks();
|
||||
}
|
||||
|
||||
|
||||
if (!reachableCode->isReachable(currentBlock))
|
||||
return;
|
||||
|
||||
|
@ -196,7 +196,7 @@ public:
|
|||
|
||||
case Enclosing:
|
||||
// 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.
|
||||
return;
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ public:
|
|||
const LiveVariables::LivenessValues &Live) override {
|
||||
|
||||
currentBlock = block;
|
||||
|
||||
|
||||
// Skip statements in macros.
|
||||
if (S->getLocStart().isMacroID())
|
||||
return;
|
||||
|
@ -276,7 +276,7 @@ public:
|
|||
const Expr *RHS =
|
||||
LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
|
||||
RHS = RHS->IgnoreParenCasts();
|
||||
|
||||
|
||||
QualType T = VD->getType();
|
||||
if (T->isPointerType() || T->isObjCObjectPointerType()) {
|
||||
if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
|
||||
|
@ -318,27 +318,27 @@ public:
|
|||
|
||||
if (!V)
|
||||
continue;
|
||||
|
||||
if (V->hasLocalStorage()) {
|
||||
|
||||
if (V->hasLocalStorage()) {
|
||||
// Reference types confuse the dead stores checker. Skip them
|
||||
// for now.
|
||||
if (V->getType()->getAs<ReferenceType>())
|
||||
return;
|
||||
|
||||
|
||||
if (const Expr *E = V->getInit()) {
|
||||
while (const ExprWithCleanups *exprClean =
|
||||
dyn_cast<ExprWithCleanups>(E))
|
||||
E = exprClean->getSubExpr();
|
||||
|
||||
|
||||
// Look through transitive assignments, e.g.:
|
||||
// int x = y = 0;
|
||||
E = LookThroughTransitiveAssignmentsAndCommaOperators(E);
|
||||
|
||||
|
||||
// Don't warn on C++ objects (yet) until we can show that their
|
||||
// constructors/destructors don't have side effects.
|
||||
if (isa<CXXConstructExpr>(E))
|
||||
return;
|
||||
|
||||
|
||||
// A dead initialization is a variable that is dead after it
|
||||
// is initialized. We don't flag warnings for those variables
|
||||
// marked 'unused' or 'objc_precise_lifetime'.
|
||||
|
|
|
@ -84,7 +84,7 @@ DereferenceChecker::AddDerefSource(raw_ostream &os,
|
|||
SourceLocation L = IV->getLocation();
|
||||
Ranges.push_back(SourceRange(L, L));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
|
|||
CheckerContext &C) const ;
|
||||
public:
|
||||
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
|
||||
};
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void DivZeroChecker::reportBug(const char *Msg,
|
||||
|
|
|
@ -113,7 +113,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
|
|||
|
||||
ProgramStateRef State = C.getState();
|
||||
const ObjCMethodDecl *D = Msg->getDecl();
|
||||
|
||||
|
||||
if (D && D->hasRelatedResultType()) {
|
||||
switch (Msg->getMethodFamily()) {
|
||||
default:
|
||||
|
@ -201,7 +201,7 @@ void DynamicTypePropagation::checkPostStmt(const CXXNewExpr *NewE,
|
|||
const MemRegion *MR = C.getSVal(NewE).getAsRegion();
|
||||
if (!MR)
|
||||
return;
|
||||
|
||||
|
||||
C.addTransition(C.getState()->setDynamicTypeInfo(MR, NewE->getType(),
|
||||
/*CanBeSubclass=*/false));
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ using namespace clang;
|
|||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class FixedAddressChecker
|
||||
class FixedAddressChecker
|
||||
: public Checker< check::PreStmt<BinaryOperator> > {
|
||||
mutable std::unique_ptr<BuiltinBug> BT;
|
||||
|
||||
|
|
|
@ -100,8 +100,8 @@ private:
|
|||
/// Generate a report if the expression is tainted or points to tainted data.
|
||||
bool generateReportIfTainted(const Expr *E, const char Msg[],
|
||||
CheckerContext &C) const;
|
||||
|
||||
|
||||
|
||||
|
||||
typedef SmallVector<unsigned, 2> ArgVector;
|
||||
|
||||
/// \brief A struct used to specify taint propagation rules for a function.
|
||||
|
@ -441,7 +441,7 @@ SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
|
|||
return Val.getAsSymbol();
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
|
||||
CheckerContext &C) const {
|
||||
ProgramStateRef State = C.getState();
|
||||
|
@ -667,8 +667,8 @@ bool GenericTaintChecker::checkUncontrolledFormatString(const CallExpr *CE,
|
|||
bool GenericTaintChecker::checkSystemCall(const CallExpr *CE,
|
||||
StringRef Name,
|
||||
CheckerContext &C) const {
|
||||
// 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
|
||||
// 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
|
||||
// need to know if the user was reset before these calls(seteuid).
|
||||
unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
|
||||
.Case("system", 0)
|
||||
|
|
|
@ -96,7 +96,7 @@ void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
|
|||
}
|
||||
LHS = B2->getLHS();
|
||||
}
|
||||
|
||||
|
||||
if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
|
||||
Sr[0] = RHS->getSourceRange();
|
||||
Sr[1] = LHS->getSourceRange();
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
// been called on them. An invalidation method should either invalidate all
|
||||
// the ivars or call another invalidation method (on self).
|
||||
//
|
||||
// Partial invalidor annotation allows to addess cases when ivars are
|
||||
// invalidated by other methods, which might or might not be called from
|
||||
// Partial invalidor annotation allows to addess cases when ivars are
|
||||
// invalidated by other methods, which might or might not be called from
|
||||
// the invalidation method. The checker checks that each invalidation
|
||||
// method and all the partial methods cumulatively invalidate all ivars.
|
||||
// __attribute__((annotate("objc_instance_variable_invalidator_partial")));
|
||||
|
@ -310,7 +310,7 @@ const ObjCIvarDecl *IvarInvalidationCheckerImpl::findPropertyBackingIvar(
|
|||
|
||||
// Lookup for the synthesized case.
|
||||
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).
|
||||
if (IvarD && IvarD->getContainingInterface() == InterfaceD) {
|
||||
if (TrackedIvars.count(IvarD)) {
|
||||
|
|
|
@ -118,7 +118,7 @@ private:
|
|||
SValBuilder &Builder) const {
|
||||
return definitelyReturnedError(RetSym, State, Builder, true);
|
||||
}
|
||||
|
||||
|
||||
/// Mark an AllocationPair interesting for diagnostic reporting.
|
||||
void markInteresting(BugReport *R, const AllocationPair &AP) const {
|
||||
R->markInteresting(AP.first);
|
||||
|
@ -282,7 +282,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
|
|||
const FunctionDecl *FD = C.getCalleeDecl(CE);
|
||||
if (!FD || FD->getKind() != Decl::Function)
|
||||
return;
|
||||
|
||||
|
||||
StringRef funName = C.getCalleeName(FD);
|
||||
if (funName.empty())
|
||||
return;
|
||||
|
|
|
@ -79,7 +79,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
|
|||
if (TrimmedFName != FName)
|
||||
FName = TrimmedFName;
|
||||
}
|
||||
|
||||
|
||||
SmallString<256> S;
|
||||
llvm::raw_svector_ostream os(S);
|
||||
os << "Call to '" << FName << "' uses";
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===##
|
||||
#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# 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.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
|
|
|
@ -65,10 +65,10 @@ class RefState {
|
|||
|
||||
const Stmt *S;
|
||||
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.
|
||||
|
||||
RefState(Kind k, const Stmt *s, unsigned family)
|
||||
RefState(Kind k, const Stmt *s, unsigned family)
|
||||
: S(s), K(k), Family(family) {
|
||||
assert(family != AF_None);
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ public:
|
|||
return RefState(AllocatedOfSizeZero, RS->getStmt(),
|
||||
RS->getAllocationFamily());
|
||||
}
|
||||
static RefState getReleased(unsigned family, const Stmt *s) {
|
||||
static RefState getReleased(unsigned family, const Stmt *s) {
|
||||
return RefState(Released, s, family);
|
||||
}
|
||||
static RefState getRelinquished(unsigned family, const Stmt *s) {
|
||||
|
@ -169,9 +169,9 @@ class MallocChecker : public Checker<check::DeadSymbols,
|
|||
{
|
||||
public:
|
||||
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_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_if_freenameindex(nullptr) {}
|
||||
|
||||
|
@ -185,7 +185,7 @@ public:
|
|||
CK_NumCheckKinds
|
||||
};
|
||||
|
||||
enum class MemoryOperationKind {
|
||||
enum class MemoryOperationKind {
|
||||
MOK_Allocate,
|
||||
MOK_Free,
|
||||
MOK_Any
|
||||
|
@ -245,19 +245,19 @@ private:
|
|||
/// \brief Print names of allocators and deallocators.
|
||||
///
|
||||
/// \returns true on success.
|
||||
bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
|
||||
bool printAllocDeallocName(raw_ostream &os, CheckerContext &C,
|
||||
const Expr *E) const;
|
||||
|
||||
/// \brief Print expected name of an allocator based on the deallocator's
|
||||
/// family derived from the DeallocExpr.
|
||||
void printExpectedAllocName(raw_ostream &os, CheckerContext &C,
|
||||
void printExpectedAllocName(raw_ostream &os, CheckerContext &C,
|
||||
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.
|
||||
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.
|
||||
bool isMemFunction(const FunctionDecl *FD, ASTContext &C) const;
|
||||
bool isCMemFunction(const FunctionDecl *FD,
|
||||
|
@ -292,7 +292,7 @@ private:
|
|||
const ProgramStateRef &State) const;
|
||||
|
||||
/// Update the RefState to reflect the new memory allocation.
|
||||
static ProgramStateRef
|
||||
static ProgramStateRef
|
||||
MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
|
||||
AllocationFamily Family = AF_Malloc);
|
||||
|
||||
|
@ -312,17 +312,17 @@ private:
|
|||
bool ReturnsNullOnFailure = false) const;
|
||||
|
||||
ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE,
|
||||
bool FreesMemOnFailure,
|
||||
bool FreesMemOnFailure,
|
||||
ProgramStateRef State) const;
|
||||
static ProgramStateRef CallocMem(CheckerContext &C, const CallExpr *CE,
|
||||
ProgramStateRef State);
|
||||
|
||||
|
||||
///\brief Check if the memory associated with this symbol was released.
|
||||
bool isReleased(SymbolRef Sym, CheckerContext &C) 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;
|
||||
|
||||
bool checkDoubleDelete(SymbolRef Sym, CheckerContext &C) const;
|
||||
|
@ -330,7 +330,7 @@ private:
|
|||
/// Check if the function is known free memory, or if it is
|
||||
/// "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
|
||||
/// returned and the single escaping symbol is returned through the out
|
||||
/// parameter.
|
||||
|
@ -357,20 +357,20 @@ private:
|
|||
Optional<CheckKind> getCheckIfTracked(CheckerContext &C,
|
||||
const Stmt *AllocDeallocStmt,
|
||||
bool IsALeakCheck = false) const;
|
||||
Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
|
||||
Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
|
||||
bool IsALeakCheck = false) const;
|
||||
///@}
|
||||
static bool SummarizeValue(raw_ostream &os, SVal V);
|
||||
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;
|
||||
void ReportFreeAlloca(CheckerContext &C, SVal ArgVal,
|
||||
SourceRange Range) const;
|
||||
void ReportMismatchedDealloc(CheckerContext &C, SourceRange Range,
|
||||
const Expr *DeallocExpr, const RefState *RS,
|
||||
SymbolRef Sym, bool OwnershipTransferred) const;
|
||||
void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
|
||||
const Expr *DeallocExpr,
|
||||
void ReportOffsetFree(CheckerContext &C, SVal ArgVal, SourceRange Range,
|
||||
const Expr *DeallocExpr,
|
||||
const Expr *AllocExpr = nullptr) const;
|
||||
void ReportUseAfterFree(CheckerContext &C, SourceRange Range,
|
||||
SymbolRef Sym) const;
|
||||
|
@ -425,8 +425,8 @@ private:
|
|||
const Stmt *Stmt) {
|
||||
// Did not track -> allocated. Other state (released) -> allocated.
|
||||
return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
|
||||
(S && (S->isAllocated() || S->isAllocatedOfSizeZero())) &&
|
||||
(!SPrev || !(SPrev->isAllocated() ||
|
||||
(S && (S->isAllocated() || S->isAllocatedOfSizeZero())) &&
|
||||
(!SPrev || !(SPrev->isAllocated() ||
|
||||
SPrev->isAllocatedOfSizeZero())));
|
||||
}
|
||||
|
||||
|
@ -509,7 +509,7 @@ private:
|
|||
REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState)
|
||||
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.
|
||||
REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef)
|
||||
|
||||
|
@ -633,7 +633,7 @@ bool MallocChecker::isStandardNewDelete(const FunctionDecl *FD,
|
|||
return false;
|
||||
|
||||
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)
|
||||
return false;
|
||||
|
||||
|
@ -798,8 +798,8 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
|
|||
State = ProcessZeroAllocation(C, CE, 0, State);
|
||||
} else if (isStandardNewDelete(FD, C.getASTContext())) {
|
||||
// Process direct calls to operator new/new[]/delete/delete[] functions
|
||||
// as distinct from new/new[]/delete/delete[] expressions that are
|
||||
// processed by the checkPostStmt callbacks for CXXNewExpr and
|
||||
// as distinct from new/new[]/delete/delete[] expressions that are
|
||||
// processed by the checkPostStmt callbacks for CXXNewExpr and
|
||||
// CXXDeleteExpr.
|
||||
OverloadedOperatorKind K = FD->getOverloadedOperator();
|
||||
if (K == OO_New) {
|
||||
|
@ -869,7 +869,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
|
|||
|
||||
assert(Arg);
|
||||
|
||||
Optional<DefinedSVal> DefArgVal =
|
||||
Optional<DefinedSVal> DefArgVal =
|
||||
State->getSVal(Arg, C.getLocationContext()).getAs<DefinedSVal>();
|
||||
|
||||
if (!DefArgVal)
|
||||
|
@ -881,7 +881,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
|
|||
DefinedSVal Zero =
|
||||
SvalBuilder.makeZeroVal(Arg->getType()).castAs<DefinedSVal>();
|
||||
|
||||
std::tie(TrueState, FalseState) =
|
||||
std::tie(TrueState, FalseState) =
|
||||
State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
|
||||
|
||||
if (TrueState && !FalseState) {
|
||||
|
@ -892,7 +892,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
|
|||
|
||||
const RefState *RS = State->get<RegionState>(Sym);
|
||||
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.
|
||||
|
||||
if (!RS->isAllocated())
|
||||
|
@ -943,7 +943,7 @@ static bool treatUnusedNewEscaped(const CXXNewExpr *NE) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
|
||||
void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
|
||||
CheckerContext &C) const {
|
||||
|
||||
if (NE->getNumPlacementArgs())
|
||||
|
@ -960,17 +960,17 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
|
|||
return;
|
||||
|
||||
ProgramStateRef State = C.getState();
|
||||
// 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
|
||||
// MallocUpdateRefState() instead of MallocMemAux() which breakes the
|
||||
// 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
|
||||
// MallocUpdateRefState() instead of MallocMemAux() which breakes the
|
||||
// existing binding.
|
||||
State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
|
||||
State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
|
||||
: AF_CXXNew);
|
||||
State = ProcessZeroAllocation(C, NE, 0, State);
|
||||
C.addTransition(State);
|
||||
}
|
||||
|
||||
void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
|
||||
void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
|
||||
CheckerContext &C) const {
|
||||
|
||||
if (!ChecksEnabled[CK_NewDeleteChecker])
|
||||
|
@ -1037,7 +1037,7 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
|
|||
|
||||
ProgramStateRef
|
||||
MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
|
||||
const OwnershipAttr *Att,
|
||||
const OwnershipAttr *Att,
|
||||
ProgramStateRef State) const {
|
||||
if (!State)
|
||||
return nullptr;
|
||||
|
@ -1104,7 +1104,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
|
|||
State = State->assume(extentMatchesSize, true);
|
||||
assert(State);
|
||||
}
|
||||
|
||||
|
||||
return MallocUpdateRefState(C, CE, State, Family);
|
||||
}
|
||||
|
||||
|
@ -1131,7 +1131,7 @@ ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
|
|||
|
||||
ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C,
|
||||
const CallExpr *CE,
|
||||
const OwnershipAttr *Att,
|
||||
const OwnershipAttr *Att,
|
||||
ProgramStateRef State) const {
|
||||
if (!State)
|
||||
return nullptr;
|
||||
|
@ -1183,7 +1183,7 @@ static bool didPreviousFreeFail(ProgramStateRef State,
|
|||
return false;
|
||||
}
|
||||
|
||||
AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
|
||||
AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
|
||||
const Stmt *S) const {
|
||||
if (!S)
|
||||
return AF_None;
|
||||
|
@ -1228,14 +1228,14 @@ AllocationFamily MallocChecker::getAllocationFamily(CheckerContext &C,
|
|||
return AF_None;
|
||||
}
|
||||
|
||||
bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
|
||||
bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
|
||||
const Expr *E) const {
|
||||
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
|
||||
// FIXME: This doesn't handle indirect calls.
|
||||
const FunctionDecl *FD = CE->getDirectCallee();
|
||||
if (!FD)
|
||||
return false;
|
||||
|
||||
|
||||
os << *FD;
|
||||
if (!FD->isOverloadedOperator())
|
||||
os << "()";
|
||||
|
@ -1252,14 +1252,14 @@ bool MallocChecker::printAllocDeallocName(raw_ostream &os, CheckerContext &C,
|
|||
}
|
||||
|
||||
if (const CXXNewExpr *NE = dyn_cast<CXXNewExpr>(E)) {
|
||||
os << "'"
|
||||
os << "'"
|
||||
<< getOperatorSpelling(NE->getOperatorNew()->getOverloadedOperator())
|
||||
<< "'";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (const CXXDeleteExpr *DE = dyn_cast<CXXDeleteExpr>(E)) {
|
||||
os << "'"
|
||||
os << "'"
|
||||
<< getOperatorSpelling(DE->getOperatorDelete()->getOverloadedOperator())
|
||||
<< "'";
|
||||
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 {
|
||||
switch(Family) {
|
||||
case AF_Malloc: os << "free()"; return;
|
||||
|
@ -1326,25 +1326,25 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|||
return nullptr;
|
||||
|
||||
const MemRegion *R = ArgVal.getAsRegion();
|
||||
|
||||
|
||||
// Nonlocs can't be freed, of course.
|
||||
// Non-region locations (labels and fixed addresses) also shouldn't be freed.
|
||||
if (!R) {
|
||||
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
R = R->StripCasts();
|
||||
|
||||
|
||||
// Blocks might show up as heap data, but should not be free()d
|
||||
if (isa<BlockDataRegion>(R)) {
|
||||
ReportBadFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) {
|
||||
// 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,
|
||||
// check that the call to free is proper.
|
||||
} else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
|
||||
} else if (RsBase->isAllocated() || RsBase->isAllocatedOfSizeZero() ||
|
||||
RsBase->isEscaped()) {
|
||||
|
||||
// Check if an expected deallocation function matches the real one.
|
||||
|
@ -1409,20 +1409,20 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C,
|
|||
!Offset.hasSymbolicOffset() &&
|
||||
Offset.getOffset() != 0) {
|
||||
const Expr *AllocExpr = cast<Expr>(RsBase->getStmt());
|
||||
ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
|
||||
ReportOffsetFree(C, ArgVal, ArgExpr->getSourceRange(), ParentExpr,
|
||||
AllocExpr);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
|
||||
ReleasedAllocated = (RsBase != nullptr) && (RsBase->isAllocated() ||
|
||||
RsBase->isAllocatedOfSizeZero());
|
||||
|
||||
// Clean out the info on previous call to free return info.
|
||||
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.
|
||||
if (ReturnsNullOnFailure) {
|
||||
SVal RetVal = C.getSVal(ParentExpr);
|
||||
|
@ -1462,7 +1462,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
|
|||
if (IsALeakCheck) {
|
||||
if (ChecksEnabled[CK_NewDeleteLeaksChecker])
|
||||
return CK_NewDeleteLeaksChecker;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ChecksEnabled[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() << "'";
|
||||
else
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1525,7 +1525,7 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
|
|||
return true;
|
||||
default: {
|
||||
const MemSpaceRegion *MS = MR->getMemorySpace();
|
||||
|
||||
|
||||
if (isa<StackLocalsSpaceRegion>(MS)) {
|
||||
const VarRegion *VR = dyn_cast<VarRegion>(MR);
|
||||
const VarDecl *VD;
|
||||
|
@ -1579,8 +1579,8 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os,
|
|||
}
|
||||
}
|
||||
|
||||
void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
|
||||
SourceRange Range,
|
||||
void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
|
||||
SourceRange Range,
|
||||
const Expr *DeallocExpr) const {
|
||||
|
||||
if (!ChecksEnabled[CK_MallocChecker] &&
|
||||
|
@ -1609,7 +1609,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
|
|||
os << "deallocator";
|
||||
|
||||
os << " is ";
|
||||
bool Summarized = MR ? SummarizeRegion(os, MR)
|
||||
bool Summarized = MR ? SummarizeRegion(os, MR)
|
||||
: SummarizeValue(os, ArgVal);
|
||||
if (Summarized)
|
||||
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 {
|
||||
|
||||
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,
|
||||
const Expr *DeallocExpr,
|
||||
const Expr *DeallocExpr,
|
||||
const RefState *RS,
|
||||
SymbolRef Sym,
|
||||
SymbolRef Sym,
|
||||
bool OwnershipTransferred) const {
|
||||
|
||||
if (!ChecksEnabled[CK_MismatchedDeallocatorChecker])
|
||||
|
@ -1679,7 +1679,7 @@ void MallocChecker::ReportMismatchedDealloc(CheckerContext &C,
|
|||
if (OwnershipTransferred) {
|
||||
if (printAllocDeallocName(DeallocOs, C, DeallocExpr))
|
||||
os << DeallocOs.str() << " cannot";
|
||||
else
|
||||
else
|
||||
os << "Cannot";
|
||||
|
||||
os << " take ownership of memory";
|
||||
|
@ -1790,7 +1790,7 @@ void MallocChecker::ReportUseAfterFree(CheckerContext &C, SourceRange Range,
|
|||
}
|
||||
|
||||
void MallocChecker::ReportDoubleFree(CheckerContext &C, SourceRange Range,
|
||||
bool Released, SymbolRef Sym,
|
||||
bool Released, SymbolRef Sym,
|
||||
SymbolRef PrevSym) const {
|
||||
|
||||
if (!ChecksEnabled[CK_MallocChecker] &&
|
||||
|
@ -1920,7 +1920,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
|
|||
bool PrtIsNull = StatePtrIsNull && !StatePtrNotNull;
|
||||
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).
|
||||
if ( PrtIsNull && !SizeIsZero) {
|
||||
ProgramStateRef stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
|
||||
|
@ -1978,7 +1978,7 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
|
||||
ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
|
||||
ProgramStateRef State) {
|
||||
if (!State)
|
||||
return nullptr;
|
||||
|
@ -1991,7 +1991,7 @@ ProgramStateRef MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE,
|
|||
SVal count = State->getSVal(CE->getArg(0), LCtx);
|
||||
SVal elementSize = State->getSVal(CE->getArg(1), LCtx);
|
||||
SVal TotalSize = svalBuilder.evalBinOp(State, BO_Mul, count, elementSize,
|
||||
svalBuilder.getContext().getSizeType());
|
||||
svalBuilder.getContext().getSizeType());
|
||||
SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
|
||||
|
||||
return MallocMemAux(C, CE, TotalSize, zeroVal, State);
|
||||
|
@ -2078,7 +2078,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N,
|
|||
const ExplodedNode *AllocNode = nullptr;
|
||||
const MemRegion *Region = nullptr;
|
||||
std::tie(AllocNode, Region) = getAllocationSite(N, Sym, C);
|
||||
|
||||
|
||||
ProgramPoint P = AllocNode->getLocation();
|
||||
const Stmt *AllocationStmt = nullptr;
|
||||
if (Optional<CallExitEnd> Exit = P.getAs<CallExitEnd>())
|
||||
|
@ -2127,7 +2127,7 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper,
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Cleanup the Realloc Pairs Map.
|
||||
ReallocPairsTy RP = state->get<ReallocPairs>();
|
||||
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
|
||||
// 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.
|
||||
void MallocChecker::checkPostStmt(const BlockExpr *BE,
|
||||
CheckerContext &C) const {
|
||||
|
@ -2446,7 +2446,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
|
|||
StringRef FName = II->getName();
|
||||
|
||||
// White list the 'XXXNoCopy' CoreFoundation functions.
|
||||
// We specifically check these before
|
||||
// We specifically check these before
|
||||
if (FName.endswith("NoCopy")) {
|
||||
// Look for the deallocator argument. We know that the memory ownership
|
||||
// is not transferred only if the deallocator argument is
|
||||
|
@ -2555,7 +2555,7 @@ ProgramStateRef MallocChecker::checkPointerEscapeAux(ProgramStateRef State,
|
|||
|
||||
if (EscapingSymbol && EscapingSymbol != sym)
|
||||
continue;
|
||||
|
||||
|
||||
if (const RefState *RS = State->get<RegionState>(sym)) {
|
||||
if ((RS->isAllocated() || RS->isAllocatedOfSizeZero()) &&
|
||||
CheckRefState(RS)) {
|
||||
|
@ -2702,7 +2702,7 @@ void ento::registerNewDeleteLeaksChecker(CheckerManager &mgr) {
|
|||
checker->ChecksEnabled[MallocChecker::CK_NewDeleteLeaksChecker] = true;
|
||||
checker->CheckNames[MallocChecker::CK_NewDeleteLeaksChecker] =
|
||||
mgr.getCurrentCheckName();
|
||||
// We currently treat NewDeleteLeaks checker as a subchecker of NewDelete
|
||||
// We currently treat NewDeleteLeaks checker as a subchecker of NewDelete
|
||||
// checker.
|
||||
if (!checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker])
|
||||
checker->ChecksEnabled[MallocChecker::CK_NewDeleteChecker] = true;
|
||||
|
|
|
@ -33,7 +33,7 @@ struct MallocOverflowCheck {
|
|||
const BinaryOperator *mulop;
|
||||
const Expr *variable;
|
||||
|
||||
MallocOverflowCheck (const BinaryOperator *m, const Expr *v)
|
||||
MallocOverflowCheck (const BinaryOperator *m, const Expr *v)
|
||||
: mulop(m), variable (v)
|
||||
{}
|
||||
};
|
||||
|
|
|
@ -143,20 +143,20 @@ static bool typesCompatible(ASTContext &C, QualType A, QualType B) {
|
|||
while (true) {
|
||||
A = A.getCanonicalType();
|
||||
B = B.getCanonicalType();
|
||||
|
||||
|
||||
if (A.getTypePtr() == B.getTypePtr())
|
||||
return true;
|
||||
|
||||
|
||||
if (const PointerType *ptrA = A->getAs<PointerType>())
|
||||
if (const PointerType *ptrB = B->getAs<PointerType>()) {
|
||||
A = ptrA->getPointeeType();
|
||||
B = ptrB->getPointeeType();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// about subpar uses of NSAutoreleasePool. Note that while the check itself
|
||||
// (in its current form) could be written as a flow-insensitive check, in
|
||||
// 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();
|
||||
if (!OD)
|
||||
return;
|
||||
return;
|
||||
if (!OD->getIdentifier()->isStr("NSAutoreleasePool"))
|
||||
return;
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ void NSErrorMethodChecker::checkASTDecl(const ObjCMethodDecl *D,
|
|||
return;
|
||||
|
||||
if (!II)
|
||||
II = &D->getASTContext().Idents.get("NSError");
|
||||
II = &D->getASTContext().Idents.get("NSError");
|
||||
|
||||
bool hasNSError = false;
|
||||
for (const auto *I : D->params()) {
|
||||
|
@ -105,7 +105,7 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
|
|||
return;
|
||||
|
||||
if (!II)
|
||||
II = &D->getASTContext().Idents.get("CFErrorRef");
|
||||
II = &D->getASTContext().Idents.get("CFErrorRef");
|
||||
|
||||
bool hasCFError = false;
|
||||
for (auto I : D->params()) {
|
||||
|
|
|
@ -133,7 +133,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
|
|||
if (IdxVal.isUnknownOrUndef())
|
||||
return;
|
||||
DefinedSVal Idx = IdxVal.castAs<DefinedSVal>();
|
||||
|
||||
|
||||
// Now, check if 'Idx in [0, Size-1]'.
|
||||
const QualType T = IdxExpr->getType();
|
||||
ProgramStateRef StInBound = State->assumeInBound(Idx, *Size, true, T);
|
||||
|
|
|
@ -49,7 +49,7 @@ public:
|
|||
DoesCallSuper = true;
|
||||
|
||||
// Recurse if we didn't find the super call yet.
|
||||
return !DoesCallSuper;
|
||||
return !DoesCallSuper;
|
||||
}
|
||||
|
||||
bool DoesCallSuper;
|
||||
|
@ -59,7 +59,7 @@ private:
|
|||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ObjCSuperCallChecker
|
||||
// ObjCSuperCallChecker
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
class ObjCSuperCallChecker : public Checker<
|
||||
|
@ -202,7 +202,7 @@ void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D,
|
|||
SmallString<320> Buf;
|
||||
llvm::raw_svector_ostream os(Buf);
|
||||
|
||||
os << "The '" << S.getAsString()
|
||||
os << "The '" << S.getAsString()
|
||||
<< "' instance method in " << SuperclassName.str() << " subclass '"
|
||||
<< *D << "' is missing a [super " << S.getAsString() << "] call";
|
||||
|
||||
|
|
|
@ -145,13 +145,13 @@ void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,
|
|||
const char *errorStr) const {
|
||||
if (!E)
|
||||
return;
|
||||
|
||||
|
||||
if (!C.getState()->get<CalledInit>())
|
||||
return;
|
||||
|
||||
|
||||
if (!isInvalidSelf(E, C))
|
||||
return;
|
||||
|
||||
|
||||
// Generate an error node.
|
||||
ExplodedNode *N = C.generateSink();
|
||||
if (!N)
|
||||
|
@ -177,12 +177,12 @@ void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,
|
|||
if (isInitMessage(Msg)) {
|
||||
// Tag the return value as the result of an initializer.
|
||||
ProgramStateRef state = C.getState();
|
||||
|
||||
|
||||
// FIXME this really should be context sensitive, where we record
|
||||
// the current stack frame (for IPA). Also, we need to clean this
|
||||
// value out when we return from this method.
|
||||
state = state->set<CalledInit>(true);
|
||||
|
||||
|
||||
SVal V = state->getSVal(Msg.getOriginExpr(), C.getLocationContext());
|
||||
addSelfFlag(state, V, SelfFlag_InitRes, C);
|
||||
return;
|
||||
|
@ -318,7 +318,7 @@ void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S,
|
|||
CheckerContext &C) const {
|
||||
// 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
|
||||
// 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.
|
||||
// (Only continue checking if the assigned value should be treated as self.)
|
||||
if ((isSelfVar(loc, C)) &&
|
||||
|
@ -412,7 +412,7 @@ static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) {
|
|||
|
||||
/// \brief Returns true if the location is 'self'.
|
||||
static bool isSelfVar(SVal location, CheckerContext &C) {
|
||||
AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext();
|
||||
AnalysisDeclContext *analCtx = C.getCurrentAnalysisDeclContext();
|
||||
if (!analCtx->getSelfDecl())
|
||||
return false;
|
||||
if (!location.getAs<loc::MemRegionVal>())
|
||||
|
|
|
@ -22,7 +22,7 @@ using namespace clang;
|
|||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class PointerArithChecker
|
||||
class PointerArithChecker
|
||||
: public Checker< check::PreStmt<BinaryOperator> > {
|
||||
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
|
||||
// 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)) {
|
||||
|
||||
if (ExplodedNode *N = C.addTransition()) {
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -23,7 +23,7 @@ using namespace clang;
|
|||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class PointerSubChecker
|
||||
class PointerSubChecker
|
||||
: public Checker< check::PreStmt<BinaryOperator> > {
|
||||
mutable std::unique_ptr<BuiltinBug> BT;
|
||||
|
||||
|
|
|
@ -62,10 +62,10 @@ class PthreadLockChecker : public Checker< check::PostStmt<CallExpr> > {
|
|||
};
|
||||
public:
|
||||
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
|
||||
|
||||
|
||||
void AcquireLock(CheckerContext &C, const CallExpr *CE, SVal lock,
|
||||
bool isTryLock, enum LockingSemantics semantics) const;
|
||||
|
||||
|
||||
void ReleaseLock(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;
|
||||
|
@ -96,7 +96,7 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
|
|||
false, PthreadSemantics);
|
||||
else if (FName == "lck_mtx_lock" ||
|
||||
FName == "lck_rw_lock_exclusive" ||
|
||||
FName == "lck_rw_lock_shared")
|
||||
FName == "lck_rw_lock_shared")
|
||||
AcquireLock(C, CE, state->getSVal(CE->getArg(0), LCtx),
|
||||
false, XNUSemantics);
|
||||
else if (FName == "pthread_mutex_trylock" ||
|
||||
|
@ -124,17 +124,17 @@ void PthreadLockChecker::checkPostStmt(const CallExpr *CE,
|
|||
void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
|
||||
SVal lock, bool isTryLock,
|
||||
enum LockingSemantics semantics) const {
|
||||
|
||||
|
||||
const MemRegion *lockR = lock.getAsRegion();
|
||||
if (!lockR)
|
||||
return;
|
||||
|
||||
|
||||
ProgramStateRef state = C.getState();
|
||||
|
||||
|
||||
SVal X = state->getSVal(CE, C.getLocationContext());
|
||||
if (X.isUnknownOrUndef())
|
||||
return;
|
||||
|
||||
|
||||
DefinedSVal retVal = X.castAs<DefinedSVal>();
|
||||
|
||||
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");
|
||||
lockSucc = state;
|
||||
}
|
||||
|
||||
// Record that the lock was acquired.
|
||||
|
||||
// Record that the lock was acquired.
|
||||
lockSucc = lockSucc->add<LockSet>(lockR);
|
||||
lockSucc = lockSucc->set<LockMap>(lockR, LockState::getLocked());
|
||||
C.addTransition(lockSucc);
|
||||
|
@ -196,7 +196,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
|
|||
const MemRegion *lockR = lock.getAsRegion();
|
||||
if (!lockR)
|
||||
return;
|
||||
|
||||
|
||||
ProgramStateRef state = C.getState();
|
||||
|
||||
if (const LockState *LState = state->get<LockMap>(lockR)) {
|
||||
|
|
|
@ -250,7 +250,7 @@ public:
|
|||
bool operator==(const RefVal& X) const {
|
||||
return T == X.T && hasSameState(X) && getObjKind() == X.getObjKind();
|
||||
}
|
||||
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID& ID) const {
|
||||
ID.Add(T);
|
||||
ID.AddInteger(RawKind);
|
||||
|
@ -426,16 +426,16 @@ public:
|
|||
/// setRetEffect - Set the effect of the return value of the call.
|
||||
void setRetEffect(RetEffect E) { Ret = E; }
|
||||
|
||||
|
||||
|
||||
/// Sets the effect on the receiver of the message.
|
||||
void setReceiverEffect(ArgEffect e) { Receiver = e; }
|
||||
|
||||
|
||||
/// getReceiverEffect - Returns the effect on the receiver of the call.
|
||||
/// This is only meaningful if the summary applies to an ObjCMessageExpr*.
|
||||
ArgEffect getReceiverEffect() const { return Receiver; }
|
||||
|
||||
/// 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).
|
||||
bool operator==(const RetainSummary &Other) const {
|
||||
return Args == Other.Args && DefaultArgEffect == Other.DefaultArgEffect &&
|
||||
|
@ -621,7 +621,7 @@ class RetainSummaryManager {
|
|||
ArgEffects::Factory AF;
|
||||
|
||||
/// ScratchArgs - A holding buffer for construct ArgEffects.
|
||||
ArgEffects ScratchArgs;
|
||||
ArgEffects ScratchArgs;
|
||||
|
||||
/// ObjCAllocRetE - Default return effect for methods returning Objective-C
|
||||
/// objects.
|
||||
|
@ -644,7 +644,7 @@ class RetainSummaryManager {
|
|||
ArgEffects getArgEffects();
|
||||
|
||||
enum UnaryFuncKind { cfretain, cfrelease, cfautorelease, cfmakecollectable };
|
||||
|
||||
|
||||
const RetainSummary *getUnarySummary(const FunctionType* FT,
|
||||
UnaryFuncKind func);
|
||||
|
||||
|
@ -664,7 +664,7 @@ class RetainSummaryManager {
|
|||
const RetainSummary *getDoNothingSummary() {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
|
||||
}
|
||||
|
||||
|
||||
const RetainSummary *getDefaultSummary() {
|
||||
return getPersistentSummary(RetEffect::MakeNoRet(),
|
||||
DoNothing, MayEscape);
|
||||
|
@ -689,7 +689,7 @@ private:
|
|||
void addClassMethSummary(const char* Cls, const char* name,
|
||||
const RetainSummary *Summ, bool isNullary = true) {
|
||||
IdentifierInfo* ClsII = &Ctx.Idents.get(Cls);
|
||||
Selector S = isNullary ? GetNullarySelector(name, Ctx)
|
||||
Selector S = isNullary ? GetNullarySelector(name, Ctx)
|
||||
: GetUnarySelector(name, Ctx);
|
||||
ObjCClassMethodSummaries[ObjCSummaryKey(ClsII, S)] = Summ;
|
||||
}
|
||||
|
@ -739,7 +739,7 @@ public:
|
|||
? RetEffect::MakeGCNotOwned()
|
||||
: (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
|
||||
: RetEffect::MakeOwned(RetEffect::ObjC, true))),
|
||||
ObjCInitRetE(gcenabled
|
||||
ObjCInitRetE(gcenabled
|
||||
? RetEffect::MakeGCNotOwned()
|
||||
: (usesARC ? RetEffect::MakeNotOwned(RetEffect::ObjC)
|
||||
: RetEffect::MakeOwnedWhenTrackedReceiver())) {
|
||||
|
@ -803,7 +803,7 @@ public:
|
|||
bool isGCEnabled() const { return GCEnabled; }
|
||||
|
||||
bool isARCEnabled() const { return ARCEnabled; }
|
||||
|
||||
|
||||
bool isARCorGCEnabled() const { return GCEnabled || ARCEnabled; }
|
||||
|
||||
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
|
||||
// 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
|
||||
// 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'.
|
||||
// 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
|
||||
|
@ -1150,7 +1150,7 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) {
|
|||
if (S)
|
||||
break;
|
||||
|
||||
if (RetTy->isPointerType()) {
|
||||
if (RetTy->isPointerType()) {
|
||||
// For CoreFoundation ('CF') types.
|
||||
if (cocoa::isRefType(RetTy, "CF", FName)) {
|
||||
if (isRetain(FD, FName)) {
|
||||
|
@ -1278,14 +1278,14 @@ RetainSummaryManager::getUnarySummary(const FunctionType* FT,
|
|||
return getPersistentSummary(RetEffect::MakeNoRet(), DoNothing, DoNothing);
|
||||
}
|
||||
|
||||
const RetainSummary *
|
||||
const RetainSummary *
|
||||
RetainSummaryManager::getCFSummaryCreateRule(const FunctionDecl *FD) {
|
||||
assert (ScratchArgs.isEmpty());
|
||||
|
||||
return getPersistentSummary(RetEffect::MakeOwned(RetEffect::CF, true));
|
||||
}
|
||||
|
||||
const RetainSummary *
|
||||
const RetainSummary *
|
||||
RetainSummaryManager::getCFSummaryGetRule(const FunctionDecl *FD) {
|
||||
assert (ScratchArgs.isEmpty());
|
||||
return getPersistentSummary(RetEffect::MakeNotOwned(RetEffect::CF),
|
||||
|
@ -1331,7 +1331,7 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
|
|||
|
||||
// Effects on the parameters.
|
||||
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) {
|
||||
const ParmVarDecl *pd = *pi;
|
||||
if (pd->hasAttr<NSConsumedAttr>())
|
||||
|
@ -1367,8 +1367,8 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
|
|||
|
||||
// Effects on the receiver.
|
||||
if (MD->hasAttr<NSConsumesSelfAttr>())
|
||||
Template->setReceiverEffect(DecRefMsg);
|
||||
|
||||
Template->setReceiverEffect(DecRefMsg);
|
||||
|
||||
// Effects on the parameters.
|
||||
unsigned parm_idx = 0;
|
||||
for (ObjCMethodDecl::param_const_iterator
|
||||
|
@ -1376,9 +1376,9 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ,
|
|||
pi != pe; ++pi, ++parm_idx) {
|
||||
const ParmVarDecl *pd = *pi;
|
||||
if (pd->hasAttr<NSConsumedAttr>())
|
||||
Template->addArg(AF, parm_idx, DecRefMsg);
|
||||
Template->addArg(AF, parm_idx, DecRefMsg);
|
||||
else if (pd->hasAttr<CFConsumedAttr>()) {
|
||||
Template->addArg(AF, parm_idx, DecRef);
|
||||
Template->addArg(AF, parm_idx, DecRef);
|
||||
} else if (pd->hasAttr<CFReturnsRetainedAttr>()) {
|
||||
QualType PointeeTy = pd->getType()->getPointeeType();
|
||||
if (!PointeeTy.isNull())
|
||||
|
@ -1415,7 +1415,7 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
|
|||
if (cocoa::isCocoaObjectRef(RetTy))
|
||||
ResultEff = RetEffect::MakeNotOwned(RetEffect::ObjC);
|
||||
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
|
||||
// double-check with the selector. This is ugly, but there aren't that
|
||||
// many Objective-C methods that return CF objects, right?
|
||||
|
@ -1428,11 +1428,11 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD,
|
|||
ResultEff = RetEffect::MakeOwned(RetEffect::CF, true);
|
||||
break;
|
||||
default:
|
||||
ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
|
||||
ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
|
||||
ResultEff = RetEffect::MakeNotOwned(RetEffect::CF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1749,7 +1749,7 @@ namespace {
|
|||
SymbolRef Sym;
|
||||
const SummaryLogTy &SummaryLog;
|
||||
bool GCEnabled;
|
||||
|
||||
|
||||
public:
|
||||
CFRefReportVisitor(SymbolRef sym, bool gcEnabled, const SummaryLogTy &log)
|
||||
: Sym(sym), SummaryLog(log), GCEnabled(gcEnabled) {}
|
||||
|
@ -1869,7 +1869,7 @@ void CFRefReport::addGCModeDescription(const LangOptions &LOpts,
|
|||
|
||||
static bool isNumericLiteralExpression(const Expr *E) {
|
||||
// FIXME: This set of cases was copied from SemaExprObjC.
|
||||
return isa<IntegerLiteral>(E) ||
|
||||
return isa<IntegerLiteral>(E) ||
|
||||
isa<CharacterLiteral>(E) ||
|
||||
isa<FloatingLiteral>(E) ||
|
||||
isa<ObjCBoolLiteralExpr>(E) ||
|
||||
|
@ -1948,7 +1948,7 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
|
|||
else if (isa<ObjCIvarRefExpr>(S)) {
|
||||
os << "Object loaded from instance variable";
|
||||
}
|
||||
else {
|
||||
else {
|
||||
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
|
||||
// Get the name of the callee (if it is available).
|
||||
SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
|
||||
|
@ -2228,7 +2228,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N,
|
|||
|
||||
StoreManager::FindUniqueBinding FB(Sym);
|
||||
StateMgr.iterBindings(St, FB);
|
||||
|
||||
|
||||
if (FB) {
|
||||
const MemRegion *R = FB.getRegion();
|
||||
const VarRegion *VR = R->getBaseRegion()->getAs<VarRegion>();
|
||||
|
@ -2345,10 +2345,10 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
|
|||
// objects. Only "copy", "alloc", "retain" and "new" transfer ownership
|
||||
// to the caller for NS objects.
|
||||
const Decl *D = &EndN->getCodeDecl();
|
||||
|
||||
|
||||
os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
|
||||
: " is returned from a function ");
|
||||
|
||||
|
||||
if (D->hasAttr<CFReturnsNotRetainedAttr>())
|
||||
os << "that is annotated as CF_RETURNS_NOT_RETAINED";
|
||||
else if (D->hasAttr<NSReturnsNotRetainedAttr>())
|
||||
|
@ -2385,7 +2385,7 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
|
|||
}
|
||||
|
||||
CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
|
||||
bool GCEnabled, const SummaryLogTy &Log,
|
||||
bool GCEnabled, const SummaryLogTy &Log,
|
||||
ExplodedNode *n, SymbolRef sym,
|
||||
CheckerContext &Ctx,
|
||||
bool IncludeAllocationLine)
|
||||
|
@ -2492,7 +2492,7 @@ class RetainCountChecker
|
|||
/// the allocation line.
|
||||
mutable bool IncludeAllocationLine;
|
||||
|
||||
public:
|
||||
public:
|
||||
RetainCountChecker(AnalyzerOptions &AO)
|
||||
: ShouldResetSummaryLog(false),
|
||||
IncludeAllocationLine(shouldIncludeAllocationSiteInLeakDiagnostics(AO)) {}
|
||||
|
@ -2617,7 +2617,7 @@ public:
|
|||
void checkPostStmt(const ObjCIvarRefExpr *IRE, CheckerContext &C) const;
|
||||
|
||||
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
|
||||
|
||||
|
||||
void checkSummary(const RetainSummary &Summ, const CallEvent &Call,
|
||||
CheckerContext &C) const;
|
||||
|
||||
|
@ -2630,13 +2630,13 @@ public:
|
|||
ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond,
|
||||
bool Assumption) const;
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
checkRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const CallEvent *Call) const;
|
||||
|
||||
|
||||
bool wantsRegionChangeUpdate(ProgramStateRef state) const {
|
||||
return true;
|
||||
}
|
||||
|
@ -2645,7 +2645,7 @@ public:
|
|||
void checkReturnWithRetEffect(const ReturnStmt *S, CheckerContext &C,
|
||||
ExplodedNode *Pred, RetEffect RE, RefVal X,
|
||||
SymbolRef Sym, ProgramStateRef state) const;
|
||||
|
||||
|
||||
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
|
||||
void checkEndFunction(CheckerContext &C) const;
|
||||
|
||||
|
@ -2656,7 +2656,7 @@ public:
|
|||
void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange,
|
||||
RefVal::Kind ErrorKind, SymbolRef Sym,
|
||||
CheckerContext &C) const;
|
||||
|
||||
|
||||
void processObjCLiterals(CheckerContext &C, const Expr *Ex) const;
|
||||
|
||||
const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const;
|
||||
|
@ -2740,21 +2740,21 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
|
|||
const ObjCBridgedCastExpr *BE = dyn_cast<ObjCBridgedCastExpr>(CE);
|
||||
if (!BE)
|
||||
return;
|
||||
|
||||
|
||||
ArgEffect AE = IncRef;
|
||||
|
||||
|
||||
switch (BE->getBridgeKind()) {
|
||||
case clang::OBC_Bridge:
|
||||
// Do nothing.
|
||||
return;
|
||||
case clang::OBC_BridgeRetained:
|
||||
AE = IncRef;
|
||||
break;
|
||||
break;
|
||||
case clang::OBC_BridgeTransfer:
|
||||
AE = DecRefBridgedTransferred;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
ProgramStateRef state = C.getState();
|
||||
SymbolRef Sym = state->getSVal(CE, C.getLocationContext()).getAsLocSymbol();
|
||||
if (!Sym)
|
||||
|
@ -2765,7 +2765,7 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
|
|||
|
||||
RefVal::Kind hasErr = (RefVal::Kind) 0;
|
||||
state = updateSymbol(state, Sym, *T, AE, hasErr, C);
|
||||
|
||||
|
||||
if (hasErr) {
|
||||
// FIXME: If we get an error during a bridge cast, should we report it?
|
||||
return;
|
||||
|
@ -2777,7 +2777,7 @@ void RetainCountChecker::checkPostStmt(const CastExpr *CE,
|
|||
void RetainCountChecker::processObjCLiterals(CheckerContext &C,
|
||||
const Expr *Ex) const {
|
||||
ProgramStateRef state = C.getState();
|
||||
const ExplodedNode *pred = C.getPredecessor();
|
||||
const ExplodedNode *pred = C.getPredecessor();
|
||||
for (const Stmt *Child : Ex->children()) {
|
||||
SVal V = state->getSVal(Child, pred->getLocationContext());
|
||||
if (SymbolRef sym = V.getAsSymbol())
|
||||
|
@ -2790,17 +2790,17 @@ void RetainCountChecker::processObjCLiterals(CheckerContext &C,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Return the object as autoreleased.
|
||||
// RetEffect RE = RetEffect::MakeNotOwned(RetEffect::ObjC);
|
||||
if (SymbolRef sym =
|
||||
if (SymbolRef sym =
|
||||
state->getSVal(Ex, pred->getLocationContext()).getAsSymbol()) {
|
||||
QualType ResultTy = Ex->getType();
|
||||
state = setRefBinding(state, sym,
|
||||
RefVal::makeNotOwned(RetEffect::ObjC, ResultTy));
|
||||
}
|
||||
|
||||
C.addTransition(state);
|
||||
|
||||
C.addTransition(state);
|
||||
}
|
||||
|
||||
void RetainCountChecker::checkPostStmt(const ObjCArrayLiteral *AL,
|
||||
|
@ -2817,7 +2817,7 @@ void RetainCountChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
|
|||
|
||||
void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
|
||||
CheckerContext &C) const {
|
||||
const ExplodedNode *Pred = C.getPredecessor();
|
||||
const ExplodedNode *Pred = C.getPredecessor();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
ProgramStateRef State = Pred->getState();
|
||||
|
||||
|
@ -2966,7 +2966,7 @@ void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ,
|
|||
if (Sym)
|
||||
state = removeRefBinding(state, Sym);
|
||||
}
|
||||
|
||||
|
||||
C.addTransition(state);
|
||||
}
|
||||
|
||||
|
@ -3062,7 +3062,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
|
|||
|
||||
if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
|
||||
if (ReceiverIsTracked)
|
||||
RE = getSummaryManager(C).getObjAllocRetEffect();
|
||||
RE = getSummaryManager(C).getObjAllocRetEffect();
|
||||
else
|
||||
RE = RetEffect::MakeNoRet();
|
||||
}
|
||||
|
@ -3130,7 +3130,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
|
|||
}
|
||||
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym,
|
||||
RefVal V, ArgEffect E, RefVal::Kind &hasErr,
|
||||
CheckerContext &C) const {
|
||||
|
@ -3388,7 +3388,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
|
|||
isMakeCollectable(FD, FName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!canEval)
|
||||
return false;
|
||||
|
||||
|
@ -3700,7 +3700,7 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state,
|
|||
return state;
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RetainCountChecker::checkRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
|
@ -3810,7 +3810,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RetainCountChecker::handleSymbolDeath(ProgramStateRef state,
|
||||
SymbolRef sid, RefVal V,
|
||||
SmallVectorImpl<SymbolRef> &Leaked) const {
|
||||
|
@ -3890,7 +3890,7 @@ void RetainCountChecker::checkEndFunction(CheckerContext &Ctx) const {
|
|||
// and suggest annotations.
|
||||
if (LCtx->getParent())
|
||||
return;
|
||||
|
||||
|
||||
B = state->get<RefBindings>();
|
||||
SmallVector<SymbolRef, 10> Leaked;
|
||||
|
||||
|
@ -3910,7 +3910,7 @@ RetainCountChecker::getDeadSymbolTag(SymbolRef sym) const {
|
|||
sym->dumpToStream(out);
|
||||
tag = new CheckerProgramPointTag(this, out.str());
|
||||
}
|
||||
return tag;
|
||||
return tag;
|
||||
}
|
||||
|
||||
void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper,
|
||||
|
|
|
@ -23,7 +23,7 @@ using namespace clang;
|
|||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class ReturnPointerRangeChecker :
|
||||
class ReturnPointerRangeChecker :
|
||||
public Checker< check::PreStmt<ReturnStmt> > {
|
||||
mutable std::unique_ptr<BuiltinBug> BT;
|
||||
|
||||
|
@ -39,7 +39,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
|
|||
const Expr *RetE = RS->getRetValue();
|
||||
if (!RetE)
|
||||
return;
|
||||
|
||||
|
||||
SVal V = state->getSVal(RetE, C.getLocationContext());
|
||||
const MemRegion *R = V.getAsRegion();
|
||||
|
||||
|
@ -66,7 +66,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
|
|||
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
|
||||
// FIXME: This bug correspond to CWE-466. Eventually we should have bug
|
||||
// types explicitly reference such exploit categories (when applicable).
|
||||
if (!BT)
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -49,20 +49,20 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
|
|||
SourceManager &SM = Ctx.getSourceManager();
|
||||
SourceRange range;
|
||||
os << "Address of ";
|
||||
|
||||
|
||||
// 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();
|
||||
os << "stack memory associated with a compound literal "
|
||||
"declared on line "
|
||||
<< SM.getExpansionLineNumber(CL->getLocStart())
|
||||
<< " returned to caller";
|
||||
<< " returned to caller";
|
||||
range = CL->getSourceRange();
|
||||
}
|
||||
else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
|
||||
const Expr *ARE = AR->getExpr();
|
||||
SourceLocation L = ARE->getLocStart();
|
||||
range = ARE->getSourceRange();
|
||||
range = ARE->getSourceRange();
|
||||
os << "stack memory allocated by call to alloca() on line "
|
||||
<< SM.getExpansionLineNumber(L);
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
|
|||
}
|
||||
else {
|
||||
llvm_unreachable("Invalid region in ReturnStackAddressChecker.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
|
@ -118,7 +118,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion *
|
|||
|
||||
void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
|
||||
CheckerContext &C) const {
|
||||
|
||||
|
||||
const Expr *RetE = RS->getRetValue();
|
||||
if (!RetE)
|
||||
return;
|
||||
|
@ -130,10 +130,10 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
|
|||
|
||||
if (!R)
|
||||
return;
|
||||
|
||||
|
||||
const StackSpaceRegion *SS =
|
||||
dyn_cast_or_null<StackSpaceRegion>(R->getMemorySpace());
|
||||
|
||||
|
||||
if (!SS)
|
||||
return;
|
||||
|
||||
|
@ -175,35 +175,35 @@ void StackAddrEscapeChecker::checkEndFunction(CheckerContext &Ctx) const {
|
|||
Ctx(CC),
|
||||
CurSFC(CC.getLocationContext()->getCurrentStackFrame())
|
||||
{}
|
||||
|
||||
|
||||
bool HandleBinding(StoreManager &SMgr, Store store,
|
||||
const MemRegion *region, SVal val) override {
|
||||
|
||||
if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
|
||||
return true;
|
||||
|
||||
|
||||
const MemRegion *vR = val.getAsRegion();
|
||||
if (!vR)
|
||||
return true;
|
||||
|
||||
|
||||
// Under automated retain release, it is okay to assign a block
|
||||
// directly to a global variable.
|
||||
if (Ctx.getASTContext().getLangOpts().ObjCAutoRefCount &&
|
||||
isa<BlockDataRegion>(vR))
|
||||
return true;
|
||||
|
||||
if (const StackSpaceRegion *SSR =
|
||||
if (const StackSpaceRegion *SSR =
|
||||
dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
|
||||
// If the global variable holds a location in the current stack frame,
|
||||
// record the binding to emit a warning.
|
||||
if (SSR->getStackFrame() == CurSFC)
|
||||
V.push_back(std::make_pair(region, vR));
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
CallBack cb(Ctx);
|
||||
state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
|
||||
|
||||
|
|
|
@ -43,8 +43,8 @@ struct StreamState {
|
|||
|
||||
static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); }
|
||||
static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); }
|
||||
static StreamState getOpenFailed(const Stmt *s) {
|
||||
return StreamState(OpenFailed, s);
|
||||
static StreamState getOpenFailed(const Stmt *s) {
|
||||
return StreamState(OpenFailed, s);
|
||||
}
|
||||
static StreamState getEscaped(const Stmt *s) {
|
||||
return StreamState(Escaped, s);
|
||||
|
@ -59,14 +59,14 @@ struct StreamState {
|
|||
class StreamChecker : public Checker<eval::Call,
|
||||
check::DeadSymbols > {
|
||||
mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread,
|
||||
*II_fwrite,
|
||||
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
|
||||
*II_fwrite,
|
||||
*II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
|
||||
*II_clearerr, *II_feof, *II_ferror, *II_fileno;
|
||||
mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence,
|
||||
BT_doubleclose, BT_ResourceLeak;
|
||||
|
||||
public:
|
||||
StreamChecker()
|
||||
StreamChecker()
|
||||
: II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr),
|
||||
II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr),
|
||||
II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr),
|
||||
|
@ -93,10 +93,10 @@ private:
|
|||
void Fileno(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;
|
||||
ProgramStateRef CheckDoubleClose(const CallExpr *CE, ProgramStateRef state,
|
||||
ProgramStateRef CheckDoubleClose(const CallExpr *CE, ProgramStateRef state,
|
||||
CheckerContext &C) const;
|
||||
};
|
||||
|
||||
|
@ -216,13 +216,13 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const {
|
|||
C.blockCount())
|
||||
.castAs<DefinedSVal>();
|
||||
state = state->BindExpr(CE, C.getLocationContext(), RetVal);
|
||||
|
||||
|
||||
ConstraintManager &CM = C.getConstraintManager();
|
||||
// Bifurcate the state into two: one with a valid FILE* pointer, the other
|
||||
// with a NULL.
|
||||
ProgramStateRef stateNotNull, stateNull;
|
||||
std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
|
||||
|
||||
|
||||
if (SymbolRef Sym = RetVal.getAsSymbol()) {
|
||||
// if RetVal is not NULL, set the symbol's state to Opened.
|
||||
stateNotNull =
|
||||
|
@ -368,13 +368,13 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
|
|||
state->getSVal(CE->getArg(0), C.getLocationContext()).getAsSymbol();
|
||||
if (!Sym)
|
||||
return state;
|
||||
|
||||
|
||||
const StreamState *SS = state->get<StreamMap>(Sym);
|
||||
|
||||
// If the file stream is not tracked, return.
|
||||
if (!SS)
|
||||
return state;
|
||||
|
||||
|
||||
// Check: Double close a File Descriptor could cause undefined behaviour.
|
||||
// Conforming to man-pages
|
||||
if (SS->isClosed()) {
|
||||
|
@ -389,7 +389,7 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE,
|
|||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// Close the File Descriptor.
|
||||
return state->set<StreamMap>(Sym, StreamState::getClosed(CE));
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
|
|||
ProgramStateRef St;
|
||||
const LocationContext *LCtx;
|
||||
|
||||
FindUndefExpr(ProgramStateRef S, const LocationContext *L)
|
||||
FindUndefExpr(ProgramStateRef S, const LocationContext *L)
|
||||
: St(S), LCtx(L) {}
|
||||
|
||||
const Expr *FindExpr(const Expr *Ex) {
|
||||
|
@ -45,7 +45,7 @@ class UndefBranchChecker : public Checker<check::BranchCondition> {
|
|||
return Ex;
|
||||
}
|
||||
|
||||
bool MatchesCriteria(const Expr *Ex) {
|
||||
bool MatchesCriteria(const Expr *Ex) {
|
||||
return St->getSVal(Ex, LCtx).isUndef();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -83,7 +83,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
|
|||
SmallString<128> buf;
|
||||
llvm::raw_svector_ostream os(buf);
|
||||
|
||||
os << "Variable '" << VD->getName()
|
||||
os << "Variable '" << VD->getName()
|
||||
<< "' is uninitialized when captured by block";
|
||||
|
||||
auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -25,7 +25,7 @@ using namespace clang;
|
|||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
class UndefResultChecker
|
||||
class UndefResultChecker
|
||||
: public Checker< check::PostStmt<BinaryOperator> > {
|
||||
|
||||
mutable std::unique_ptr<BugType> BT;
|
||||
|
@ -53,7 +53,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
|
|||
ExplodedNode *N = C.generateSink();
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
|
||||
if (!BT)
|
||||
BT.reset(
|
||||
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);
|
||||
const Expr *Ex = nullptr;
|
||||
bool isLeft = true;
|
||||
|
||||
|
||||
if (state->getSVal(B->getLHS(), LCtx).isUndef()) {
|
||||
Ex = B->getLHS()->IgnoreParenCasts();
|
||||
isLeft = true;
|
||||
|
@ -71,13 +71,13 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
|
|||
Ex = B->getRHS()->IgnoreParenCasts();
|
||||
isLeft = false;
|
||||
}
|
||||
|
||||
|
||||
if (Ex) {
|
||||
OS << "The " << (isLeft ? "left" : "right")
|
||||
<< " operand of '"
|
||||
<< BinaryOperator::getOpcodeStr(B->getOpcode())
|
||||
<< "' is a garbage value";
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Neither operand was undefined, but the result is undefined.
|
||||
OS << "The result of the '"
|
||||
|
@ -91,7 +91,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
|
|||
}
|
||||
else
|
||||
bugreporter::trackNullOrUndefValue(N, B, *report);
|
||||
|
||||
|
||||
C.emitReport(std::move(report));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void
|
||||
void
|
||||
UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
|
||||
CheckerContext &C) const {
|
||||
const Expr *Index = A->getIdx();
|
||||
|
|
|
@ -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
|
||||
// of querying this information from the checking environment.
|
||||
if (!Val_O_CREAT.hasValue()) {
|
||||
if (C.getASTContext().getTargetInfo().getTriple().getVendor()
|
||||
if (C.getASTContext().getTargetInfo().getTriple().getVendor()
|
||||
== llvm::Triple::Apple)
|
||||
Val_O_CREAT = 0x0200;
|
||||
else {
|
||||
|
@ -220,7 +220,7 @@ static bool IsZeroByteAllocation(ProgramStateRef state,
|
|||
ProgramStateRef *falseState) {
|
||||
std::tie(*trueState, *falseState) =
|
||||
state->assume(argVal.castAs<DefinedSVal>());
|
||||
|
||||
|
||||
return (*falseState && !*trueState);
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,
|
|||
"Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
|
||||
|
||||
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";
|
||||
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?
|
||||
if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {
|
||||
(void) ReportZeroByteAllocation(C, falseState, arg, fn);
|
||||
(void) ReportZeroByteAllocation(C, falseState, arg, fn);
|
||||
return;
|
||||
}
|
||||
// Assume the value is non-zero going forward.
|
||||
assert(trueState);
|
||||
if (trueState != state)
|
||||
C.addTransition(trueState);
|
||||
C.addTransition(trueState);
|
||||
}
|
||||
|
||||
void UnixAPIChecker::CheckCallocZero(CheckerContext &C,
|
||||
|
|
|
@ -54,7 +54,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
|
|||
BugReporter &B,
|
||||
ExprEngine &Eng) const {
|
||||
CFGBlocksSet reachable, visited;
|
||||
|
||||
|
||||
if (Eng.hasWorkRemaining())
|
||||
return;
|
||||
|
||||
|
@ -88,7 +88,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
|
|||
// Bail out if we didn't get the CFG or the ParentMap.
|
||||
if (!D || !C || !PM)
|
||||
return;
|
||||
|
||||
|
||||
// Don't do anything for template instantiations. Proving that code
|
||||
// in a template instantiation is unreachable means proving that it is
|
||||
// unreachable in all instantiations.
|
||||
|
|
|
@ -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.
|
||||
// In addition, VLASizeChecker is responsible for defining the extent
|
||||
// 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 {
|
||||
if (!DS->isSingleDecl())
|
||||
return;
|
||||
|
||||
|
||||
const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
|
||||
if (!VD)
|
||||
return;
|
||||
|
@ -106,7 +106,7 @@ void VLASizeChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
|
|||
// warned about that already.
|
||||
if (sizeV.isUnknown())
|
||||
return;
|
||||
|
||||
|
||||
// Check if the size is tainted.
|
||||
if (state->isTainted(sizeV)) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// From this point on, assume that the size is not zero.
|
||||
state = stateNotZero;
|
||||
|
||||
|
|
|
@ -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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -37,13 +37,13 @@ class WalkAST : public StmtVisitor<WalkAST> {
|
|||
|
||||
/// A vector representing the worklist which has a chain of CallExprs.
|
||||
DFSWorkList WList;
|
||||
|
||||
|
||||
// PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
|
||||
// body has not been visited yet.
|
||||
// PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
|
||||
// body has been visited.
|
||||
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
|
||||
visited. */
|
||||
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
|
||||
/// constructor or destructor.
|
||||
const CallExpr *visitingCallExpr;
|
||||
|
||||
|
||||
public:
|
||||
WalkAST(const CheckerBase *checker, BugReporter &br,
|
||||
AnalysisDeclContext *ac)
|
||||
|
@ -70,7 +70,7 @@ public:
|
|||
void Enqueue(WorkListUnit WLUnit) {
|
||||
const FunctionDecl *FD = WLUnit->getDirectCallee();
|
||||
if (!FD || !FD->getBody())
|
||||
return;
|
||||
return;
|
||||
Kind &K = VisitedFunctions[FD];
|
||||
if (K != NotVisited)
|
||||
return;
|
||||
|
@ -81,9 +81,9 @@ public:
|
|||
/// This method returns an item from the worklist without removing it.
|
||||
WorkListUnit Dequeue() {
|
||||
assert(!WList.empty());
|
||||
return WList.back();
|
||||
return WList.back();
|
||||
}
|
||||
|
||||
|
||||
void Execute() {
|
||||
while (hasWork()) {
|
||||
WorkListUnit WLUnit = Dequeue();
|
||||
|
@ -95,7 +95,7 @@ public:
|
|||
// Visit the body.
|
||||
SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
|
||||
Visit(FD->getBody());
|
||||
|
||||
|
||||
// Mark the function as being PostVisited to indicate we have
|
||||
// scanned the body.
|
||||
VisitedFunctions[FD] = PostVisited;
|
||||
|
@ -114,7 +114,7 @@ public:
|
|||
void VisitCXXMemberCallExpr(CallExpr *CE);
|
||||
void VisitStmt(Stmt *S) { VisitChildren(S); }
|
||||
void VisitChildren(Stmt *S);
|
||||
|
||||
|
||||
void ReportVirtualCall(const CallExpr *CE, bool isPure);
|
||||
|
||||
};
|
||||
|
@ -138,7 +138,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
|
|||
void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
|
||||
VisitChildren(CE);
|
||||
bool callIsNonVirtual = false;
|
||||
|
||||
|
||||
// Several situations to elide for checking.
|
||||
if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
|
||||
// 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) {
|
||||
SmallString<100> buf;
|
||||
llvm::raw_svector_ostream os(buf);
|
||||
|
||||
|
||||
os << "Call Path : ";
|
||||
// Name of current visiting CallExpr.
|
||||
os << *CE->getDirectCallee();
|
||||
|
@ -190,7 +190,7 @@ void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
|
|||
PathDiagnosticLocation CELoc =
|
||||
PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
|
||||
SourceRange R = CE->getCallee()->getSourceRange();
|
||||
|
||||
|
||||
if (isPure) {
|
||||
os << "\n" << "Call pure virtual functions during construction or "
|
||||
<< "destruction may leads undefined behaviour";
|
||||
|
|
|
@ -18,7 +18,7 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
|
|||
const LangOptions &lang,
|
||||
const PathDiagnosticConsumers &PDC,
|
||||
StoreManagerCreator storemgr,
|
||||
ConstraintManagerCreator constraintmgr,
|
||||
ConstraintManagerCreator constraintmgr,
|
||||
CheckerManager *checkerMgr,
|
||||
AnalyzerOptions &Options,
|
||||
CodeInjector *injector)
|
||||
|
|
|
@ -65,7 +65,7 @@ IPAKind AnalyzerOptions::getIPAMode() {
|
|||
// Set the member variable.
|
||||
IPAMode = IPAConfig;
|
||||
}
|
||||
|
||||
|
||||
return IPAMode;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class CountKey {
|
|||
unsigned BlockID;
|
||||
|
||||
public:
|
||||
CountKey(const StackFrameContext *CS, unsigned ID)
|
||||
CountKey(const StackFrameContext *CS, unsigned ID)
|
||||
: CallSite(CS), BlockID(ID) {}
|
||||
|
||||
bool operator==(const CountKey &RHS) const {
|
||||
|
@ -55,7 +55,7 @@ static inline CountMap::Factory& GetFactory(void *F) {
|
|||
return *static_cast<CountMap::Factory*>(F);
|
||||
}
|
||||
|
||||
unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite,
|
||||
unsigned BlockCounter::getNumVisited(const StackFrameContext *CallSite,
|
||||
unsigned BlockID) const {
|
||||
CountMap M = GetMap(Data);
|
||||
CountMap::data_type* T = M.lookup(CountKey(CallSite, BlockID));
|
||||
|
@ -71,10 +71,10 @@ BlockCounter::Factory::~Factory() {
|
|||
}
|
||||
|
||||
BlockCounter
|
||||
BlockCounter::Factory::IncrementCount(BlockCounter BC,
|
||||
BlockCounter::Factory::IncrementCount(BlockCounter BC,
|
||||
const StackFrameContext *CallSite,
|
||||
unsigned BlockID) {
|
||||
return BlockCounter(GetFactory(F).add(GetMap(BC.Data),
|
||||
return BlockCounter(GetFactory(F).add(GetMap(BC.Data),
|
||||
CountKey(CallSite, BlockID),
|
||||
BC.getNumVisited(CallSite, BlockID)+1).getRoot());
|
||||
}
|
||||
|
|
|
@ -81,13 +81,13 @@ eventsDescribeSameCondition(PathDiagnosticEventPiece *X,
|
|||
// those that came from TrackConstraintBRVisitor.
|
||||
const void *tagPreferred = ConditionBRVisitor::getTag();
|
||||
const void *tagLesser = TrackConstraintBRVisitor::getTag();
|
||||
|
||||
|
||||
if (X->getLocation() != Y->getLocation())
|
||||
return nullptr;
|
||||
|
||||
if (X->getTag() == tagPreferred && Y->getTag() == tagLesser)
|
||||
return X;
|
||||
|
||||
|
||||
if (Y->getTag() == tagPreferred && X->getTag() == tagLesser)
|
||||
return Y;
|
||||
|
||||
|
@ -110,7 +110,7 @@ static void removeRedundantMsgs(PathPieces &path) {
|
|||
for (unsigned i = 0; i < N; ++i) {
|
||||
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(path.front());
|
||||
path.pop_front();
|
||||
|
||||
|
||||
switch (piece->getKind()) {
|
||||
case clang::ento::PathDiagnosticPiece::Call:
|
||||
removeRedundantMsgs(cast<PathDiagnosticCallPiece>(piece)->path);
|
||||
|
@ -123,7 +123,7 @@ static void removeRedundantMsgs(PathPieces &path) {
|
|||
case clang::ento::PathDiagnosticPiece::Event: {
|
||||
if (i == N-1)
|
||||
break;
|
||||
|
||||
|
||||
if (PathDiagnosticEventPiece *nextEvent =
|
||||
dyn_cast<PathDiagnosticEventPiece>(path.front().get())) {
|
||||
PathDiagnosticEventPiece *event =
|
||||
|
@ -157,13 +157,13 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
|
|||
LocationContextMap &LCM) {
|
||||
bool containsSomethingInteresting = false;
|
||||
const unsigned N = pieces.size();
|
||||
|
||||
|
||||
for (unsigned i = 0 ; i < N ; ++i) {
|
||||
// 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.
|
||||
IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front());
|
||||
pieces.pop_front();
|
||||
|
||||
|
||||
switch (piece->getKind()) {
|
||||
case PathDiagnosticPiece::Call: {
|
||||
PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece);
|
||||
|
@ -176,7 +176,7 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
|
|||
|
||||
if (!removeUnneededCalls(call->path, R, LCM))
|
||||
continue;
|
||||
|
||||
|
||||
containsSomethingInteresting = true;
|
||||
break;
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
|
|||
}
|
||||
case PathDiagnosticPiece::Event: {
|
||||
PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece);
|
||||
|
||||
|
||||
// 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.
|
||||
containsSomethingInteresting |= !event->isPrunable();
|
||||
|
@ -198,10 +198,10 @@ static bool removeUnneededCalls(PathPieces &pieces, BugReport *R,
|
|||
case PathDiagnosticPiece::ControlFlow:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
pieces.push_back(piece);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
/// valid locations.
|
||||
/// valid locations.
|
||||
static void
|
||||
adjustCallLocations(PathPieces &Pieces,
|
||||
PathDiagnosticLocation *LastCallLocation = nullptr) {
|
||||
|
@ -323,7 +323,7 @@ class PathDiagnosticBuilder : public BugReporterContext {
|
|||
NodeMapClosure NMC;
|
||||
public:
|
||||
const LocationContext *LC;
|
||||
|
||||
|
||||
PathDiagnosticBuilder(GRBugReporter &br,
|
||||
BugReport *r, InterExplodedGraphMap &Backmap,
|
||||
PathDiagnosticConsumer *pdc)
|
||||
|
@ -339,7 +339,7 @@ public:
|
|||
BugReport *getBugReport() { return R; }
|
||||
|
||||
Decl const &getCodeDecl() { return R->getErrorNode()->getCodeDecl(); }
|
||||
|
||||
|
||||
ParentMap& getParentMap() { return LC->getParentMap(); }
|
||||
|
||||
const Stmt *getParent(const Stmt *S) {
|
||||
|
@ -957,7 +957,7 @@ static PathDiagnosticLocation cleanUpLocation(PathDiagnosticLocation L,
|
|||
|
||||
if (firstCharOnly)
|
||||
L = PathDiagnosticLocation::createSingleLocation(L);
|
||||
|
||||
|
||||
return L;
|
||||
}
|
||||
|
||||
|
@ -1001,7 +1001,7 @@ public:
|
|||
|
||||
~EdgeBuilder() {
|
||||
while (!CLocs.empty()) popLocation();
|
||||
|
||||
|
||||
// Finally, add an initial edge from the start location of the first
|
||||
// statement (if it doesn't already exist).
|
||||
PathDiagnosticLocation L = PathDiagnosticLocation::createDeclBegin(
|
||||
|
@ -1016,7 +1016,7 @@ public:
|
|||
popLocation();
|
||||
PrevLoc = PathDiagnosticLocation();
|
||||
}
|
||||
|
||||
|
||||
void addEdge(PathDiagnosticLocation NewLoc, bool alwaysAdd = false,
|
||||
bool IsPostJump = false);
|
||||
|
||||
|
@ -1101,7 +1101,7 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) {
|
|||
PrevLoc = NewLoc;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (NewLocClean.asLocation() == PrevLocClean.asLocation())
|
||||
return;
|
||||
|
||||
|
@ -1242,7 +1242,7 @@ static void reversePropagateIntererstingSymbols(BugReport &R,
|
|||
SVal V = State->getSVal(Ex, LCtx);
|
||||
if (!(R.isInteresting(V) || IE.count(Ex)))
|
||||
return;
|
||||
|
||||
|
||||
switch (Ex->getStmtClass()) {
|
||||
default:
|
||||
if (!isa<CastExpr>(Ex))
|
||||
|
@ -1260,7 +1260,7 @@ static void reversePropagateIntererstingSymbols(BugReport &R,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
R.markInteresting(V);
|
||||
}
|
||||
|
||||
|
@ -1275,7 +1275,7 @@ static void reversePropagateInterestingSymbols(BugReport &R,
|
|||
const Stmt *CallSite = Callee->getCallSite();
|
||||
if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(CallSite)) {
|
||||
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();
|
||||
CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
|
||||
for (; AI != AE && PI != PE; ++AI, ++PI) {
|
||||
|
@ -1406,7 +1406,7 @@ static bool GenerateExtensivePathDiagnostic(
|
|||
N->getState().get(), Ex,
|
||||
N->getLocationContext());
|
||||
}
|
||||
|
||||
|
||||
if (Optional<CallExitEnd> CE = P.getAs<CallExitEnd>()) {
|
||||
const Stmt *S = CE->getCalleeContext()->getCallSite();
|
||||
if (const Expr *Ex = dyn_cast_or_null<Expr>(S)) {
|
||||
|
@ -1414,7 +1414,7 @@ static bool GenerateExtensivePathDiagnostic(
|
|||
N->getState().get(), Ex,
|
||||
N->getLocationContext());
|
||||
}
|
||||
|
||||
|
||||
PathDiagnosticCallPiece *C =
|
||||
PathDiagnosticCallPiece::construct(N, *CE, SM);
|
||||
LCM[&C->path] = CE->getCalleeContext();
|
||||
|
@ -1427,7 +1427,7 @@ static bool GenerateExtensivePathDiagnostic(
|
|||
CallStack.push_back(StackDiagPair(C, N));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Pop the call hierarchy if we are done walking the contents
|
||||
// of a function call.
|
||||
if (Optional<CallEnter> CE = P.getAs<CallEnter>()) {
|
||||
|
@ -1436,7 +1436,7 @@ static bool GenerateExtensivePathDiagnostic(
|
|||
PathDiagnosticLocation pos =
|
||||
PathDiagnosticLocation::createBegin(D, SM);
|
||||
EB.addEdge(pos);
|
||||
|
||||
|
||||
// Flush all locations, and pop the active path.
|
||||
bool VisitedEntireCall = PD.isWithinCall();
|
||||
EB.flushLocations();
|
||||
|
@ -1466,7 +1466,7 @@ static bool GenerateExtensivePathDiagnostic(
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Note that is important that we update the LocationContext
|
||||
// after looking at CallExits. CallExit basically adds an
|
||||
// edge in the *caller*, so we don't want to update the LocationContext
|
||||
|
@ -1486,7 +1486,7 @@ static bool GenerateExtensivePathDiagnostic(
|
|||
CalleeCtx, CallerCtx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Are we jumping to the head of a loop? Add a special diagnostic.
|
||||
if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) {
|
||||
PathDiagnosticLocation L(Loop, SM, PDB.LC);
|
||||
|
@ -1552,11 +1552,11 @@ static bool GenerateExtensivePathDiagnostic(
|
|||
else
|
||||
EB.addExtendedContext(PDB.getEnclosingStmtLocation(stmt).asStmt());
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} while (0);
|
||||
|
||||
if (!NextNode)
|
||||
|
@ -2410,7 +2410,7 @@ static bool optimizeEdges(PathPieces &path, SourceManager &SM,
|
|||
// Trim edges on expressions that are consumed by
|
||||
// the parent expression.
|
||||
if (isa<Expr>(s1End) && PM.isConsumedExpr(cast<Expr>(s1End))) {
|
||||
removeEdge = true;
|
||||
removeEdge = true;
|
||||
}
|
||||
// Trim edges where a lexical containment doesn't exist.
|
||||
// For example:
|
||||
|
@ -2557,7 +2557,7 @@ BugReport::~BugReport() {
|
|||
const Decl *BugReport::getDeclWithIssue() const {
|
||||
if (DeclWithIssue)
|
||||
return DeclWithIssue;
|
||||
|
||||
|
||||
const ExplodedNode *N = getErrorNode();
|
||||
if (!N)
|
||||
return nullptr;
|
||||
|
@ -2973,14 +2973,14 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) {
|
|||
|
||||
for (PathPieces::const_iterator I = path.begin(), E = path.end();
|
||||
I!=E; ++I) {
|
||||
|
||||
|
||||
PathDiagnosticPiece *piece = I->get();
|
||||
|
||||
// Recursively compact calls.
|
||||
if (PathDiagnosticCallPiece *call=dyn_cast<PathDiagnosticCallPiece>(piece)){
|
||||
CompactPathDiagnostic(call->path, SM);
|
||||
}
|
||||
|
||||
|
||||
// Get the location of the PathDiagnosticPiece.
|
||||
const FullSourceLoc Loc = piece->getLocation().asLocation();
|
||||
|
||||
|
@ -3126,7 +3126,7 @@ bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD,
|
|||
PD.resetPath();
|
||||
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.
|
||||
std::unique_ptr<PathDiagnosticPiece> LastPiece;
|
||||
for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end();
|
||||
|
@ -3234,7 +3234,7 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
|
|||
!DeclCtx->isBodyAutosynthesizedFromModelFile())
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool ValidSourceLoc = R->getLocation(getSourceManager()).isValid();
|
||||
assert(ValidSourceLoc);
|
||||
// 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 {
|
||||
const ExplodedNode *N;
|
||||
ExplodedNode::const_succ_iterator I, E;
|
||||
|
||||
|
||||
FRIEC_WLItem(const ExplodedNode *n)
|
||||
: N(n), I(N->succ_begin()), E(N->succ_end()) {}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
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
|
||||
// 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 SmallVector<WLItem, 10> DFSWorkList;
|
||||
llvm::DenseMap<const ExplodedNode *, unsigned> Visited;
|
||||
|
||||
|
||||
DFSWorkList WL;
|
||||
WL.push_back(errorNode);
|
||||
Visited[errorNode] = 1;
|
||||
|
||||
|
||||
while (!WL.empty()) {
|
||||
WLItem &WI = WL.back();
|
||||
assert(!WI.N->succ_empty());
|
||||
|
||||
|
||||
for (; WI.I != WI.E; ++WI.I) {
|
||||
const ExplodedNode *Succ = *WI.I;
|
||||
const ExplodedNode *Succ = *WI.I;
|
||||
// End-of-path node?
|
||||
if (Succ->succ_empty()) {
|
||||
// If we found an end-of-path node that is not a sink.
|
||||
|
|
|
@ -169,7 +169,7 @@ public:
|
|||
bool InEnableNullFPSuppression) {
|
||||
if (!CallEvent::isCallStmt(S))
|
||||
return;
|
||||
|
||||
|
||||
// First, find when we processed the statement.
|
||||
do {
|
||||
if (Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>())
|
||||
|
@ -192,11 +192,11 @@ public:
|
|||
Optional<CallExitEnd> CEE = Node->getLocationAs<CallExitEnd>();
|
||||
if (!CEE)
|
||||
return;
|
||||
|
||||
|
||||
const StackFrameContext *CalleeContext = CEE->getCalleeContext();
|
||||
if (CalleeContext->getCallSite() != S)
|
||||
return;
|
||||
|
||||
|
||||
// Check the return value.
|
||||
ProgramStateRef State = Node->getState();
|
||||
SVal RetVal = State->getSVal(S, Node->getLocationContext());
|
||||
|
@ -281,7 +281,7 @@ public:
|
|||
EnableNullFPSuppression);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
// If we're returning 0, we should track where that 0 came from.
|
||||
bugreporter::trackNullOrUndefValue(N, RetE, BR, /*IsArg*/ false,
|
||||
EnableNullFPSuppression);
|
||||
|
@ -472,7 +472,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
|
|||
InitE = PIP->getInitializer()->getInit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Otherwise, see if this is the store site:
|
||||
// (1) Succ has this binding and Pred does not, i.e. this is
|
||||
// where the binding first occurred.
|
||||
|
@ -504,7 +504,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
|
|||
if (Optional<CallEnter> CE = Succ->getLocationAs<CallEnter>()) {
|
||||
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
|
||||
const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl());
|
||||
|
||||
|
||||
ProgramStateManager &StateMgr = BRC.getStateManager();
|
||||
CallEventManager &CallMgr = StateMgr.getCallEventManager();
|
||||
|
||||
|
@ -681,7 +681,7 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ,
|
|||
else
|
||||
os << "Assigning value";
|
||||
}
|
||||
|
||||
|
||||
if (R->canPrintPretty()) {
|
||||
os << " to ";
|
||||
R->printPretty(os);
|
||||
|
@ -931,7 +931,7 @@ bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N,
|
|||
if (!N)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
ProgramStateRef state = N->getState();
|
||||
|
||||
// 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.");
|
||||
ProgramStateRef LVState = LVNode->getState();
|
||||
SVal LVal = LVState->getSVal(Inner, LVNode->getLocationContext());
|
||||
|
||||
|
||||
if (LVState->isNull(LVal).isConstrainedTrue()) {
|
||||
// In case of C++ references, we want to differentiate between a null
|
||||
// reference and reference to null pointer.
|
||||
|
@ -1162,11 +1162,11 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N,
|
|||
const ExplodedNode *Prev,
|
||||
BugReporterContext &BRC,
|
||||
BugReport &BR) {
|
||||
|
||||
|
||||
ProgramPoint progPoint = N->getLocation();
|
||||
ProgramStateRef CurrentState = N->getState();
|
||||
ProgramStateRef PrevState = Prev->getState();
|
||||
|
||||
|
||||
// Compare the GDMs of the state, because that is where constraints
|
||||
// are managed. Note that ensure that we only look at nodes that
|
||||
// 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
|
||||
// here by looking at the state transition.
|
||||
if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) {
|
||||
const CFGBlock *srcBlk = BE->getSrc();
|
||||
const CFGBlock *srcBlk = BE->getSrc();
|
||||
if (const Stmt *term = srcBlk->getTerminator())
|
||||
return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
if (Optional<PostStmt> PS = progPoint.getAs<PostStmt>()) {
|
||||
// FIXME: Assuming that BugReporter is a GRBugReporter is a layering
|
||||
// violation.
|
||||
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
|
||||
const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags =
|
||||
cast<GRBugReporter>(BRC.getBugReporter()).
|
||||
getEngine().geteagerlyAssumeBinOpBifurcationTags();
|
||||
|
||||
|
@ -1222,7 +1222,7 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term,
|
|||
case Stmt::ConditionalOperatorClass:
|
||||
Cond = cast<ConditionalOperator>(Term)->getCond();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(Cond);
|
||||
assert(srcBlk->succ_size() == 2);
|
||||
|
@ -1236,9 +1236,9 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
|
|||
BugReporterContext &BRC,
|
||||
BugReport &R,
|
||||
const ExplodedNode *N) {
|
||||
|
||||
|
||||
const Expr *Ex = Cond;
|
||||
|
||||
|
||||
while (true) {
|
||||
Ex = Ex->IgnoreParenCasts();
|
||||
switch (Ex->getStmtClass()) {
|
||||
|
@ -1294,7 +1294,7 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out,
|
|||
Out << '\'';
|
||||
return quotes;
|
||||
}
|
||||
|
||||
|
||||
if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(Ex)) {
|
||||
QualType OriginalTy = OriginalExpr->getType();
|
||||
if (OriginalTy->isPointerType()) {
|
||||
|
@ -1309,11 +1309,11 @@ bool ConditionBRVisitor::patternMatch(const Expr *Ex, raw_ostream &Out,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Out << IL->getValue();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1324,10 +1324,10 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
|
|||
BugReporterContext &BRC,
|
||||
BugReport &R,
|
||||
const ExplodedNode *N) {
|
||||
|
||||
|
||||
bool shouldInvert = false;
|
||||
Optional<bool> shouldPrune;
|
||||
|
||||
|
||||
SmallString<128> LhsString, RhsString;
|
||||
{
|
||||
llvm::raw_svector_ostream OutLHS(LhsString), OutRHS(RhsString);
|
||||
|
@ -1335,10 +1335,10 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
|
|||
shouldPrune);
|
||||
const bool isVarRHS = patternMatch(BExpr->getRHS(), OutRHS, BRC, R, N,
|
||||
shouldPrune);
|
||||
|
||||
shouldInvert = !isVarLHS && isVarRHS;
|
||||
|
||||
shouldInvert = !isVarLHS && isVarRHS;
|
||||
}
|
||||
|
||||
|
||||
BinaryOperator::Opcode Op = BExpr->getOpcode();
|
||||
|
||||
if (BinaryOperator::isAssignmentOp(Op)) {
|
||||
|
@ -1380,7 +1380,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
|
|||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
switch (Op) {
|
||||
case BO_EQ:
|
||||
Out << "equal to ";
|
||||
|
@ -1392,7 +1392,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
|
|||
Out << BinaryOperator::getOpcodeStr(Op) << ' ';
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Out << (shouldInvert ? LhsString : RhsString);
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
|
||||
|
@ -1416,7 +1416,7 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
|
|||
SmallString<256> buf;
|
||||
llvm::raw_svector_ostream Out(buf);
|
||||
Out << "Assuming " << LhsString << " is ";
|
||||
|
||||
|
||||
QualType Ty = CondVarExpr->getType();
|
||||
|
||||
if (Ty->isPointerType())
|
||||
|
@ -1444,10 +1444,10 @@ ConditionBRVisitor::VisitConditionVariable(StringRef LhsString,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
PathDiagnosticPiece *
|
||||
ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
|
||||
const DeclRefExpr *DR,
|
||||
|
@ -1462,11 +1462,11 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
|
|||
|
||||
SmallString<256> Buf;
|
||||
llvm::raw_svector_ostream Out(Buf);
|
||||
|
||||
|
||||
Out << "Assuming '" << VD->getDeclName() << "' is ";
|
||||
|
||||
|
||||
QualType VDTy = VD->getType();
|
||||
|
||||
|
||||
if (VDTy->isPointerType())
|
||||
Out << (tookTrue ? "non-null" : "null");
|
||||
else if (VDTy->isObjCObjectPointerType())
|
||||
|
@ -1480,7 +1480,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond,
|
|||
PathDiagnosticLocation Loc(Cond, BRC.getSourceManager(), LCtx);
|
||||
PathDiagnosticEventPiece *event =
|
||||
new PathDiagnosticEventPiece(Loc, Out.str());
|
||||
|
||||
|
||||
const ProgramState *state = N->getState().get();
|
||||
if (const MemRegion *R = state->getLValue(VD, LCtx).getAsRegion()) {
|
||||
if (report.isInteresting(R))
|
||||
|
@ -1615,13 +1615,13 @@ UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N,
|
|||
// Function can only change the value passed in by address.
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// If it is a const pointer value, the function does not intend to
|
||||
// change the value.
|
||||
if (T->getPointeeType().isConstQualified())
|
||||
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'.
|
||||
SVal BoundVal = State->getSVal(R);
|
||||
if (BoundVal.isUndef() || BoundVal.isZeroConstant()) {
|
||||
|
|
|
@ -96,7 +96,7 @@ bool CallEvent::hasNonZeroCallbackArg() const {
|
|||
if (isCallbackArg(getArgSVal(Idx), *I))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,7 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
|
|||
// below for efficiency.
|
||||
if (PreserveArgs.count(Idx))
|
||||
if (const MemRegion *MR = getArgSVal(Idx).getAsRegion())
|
||||
ETraits.setTrait(MR->StripCasts(),
|
||||
ETraits.setTrait(MR->StripCasts(),
|
||||
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
|
||||
// TODO: Factor this out + handle the lower level const pointers.
|
||||
|
||||
|
@ -184,7 +184,7 @@ ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
|
|||
}
|
||||
|
||||
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();
|
||||
if (IsPreVisit)
|
||||
|
@ -265,7 +265,7 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) {
|
|||
|
||||
return QualType();
|
||||
}
|
||||
|
||||
|
||||
llvm_unreachable("unknown callable kind");
|
||||
}
|
||||
|
||||
|
@ -336,7 +336,7 @@ bool AnyFunctionCall::argumentsMayEscape() const {
|
|||
if (!II)
|
||||
return false;
|
||||
|
||||
// This set of "escaping" APIs is
|
||||
// This set of "escaping" APIs is
|
||||
|
||||
// - 'int pthread_setspecific(ptheread_key k, const void *)' stores a
|
||||
// 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
|
||||
// hierarchy, and some real bugs have been caught by checking this.
|
||||
assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method");
|
||||
|
||||
|
||||
// FIXME: This is checking that our DynamicTypeInfo is at least as good as
|
||||
// the static type. However, because we currently don't update
|
||||
// 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 (ME->hasQualifier())
|
||||
return AnyFunctionCall::getRuntimeDefinition();
|
||||
|
||||
|
||||
return CXXInstanceCall::getRuntimeDefinition();
|
||||
}
|
||||
|
||||
|
@ -628,7 +628,7 @@ SVal ObjCMethodCall::getReceiverSVal() const {
|
|||
// FIXME: Is this the best way to handle class receivers?
|
||||
if (!isInstanceMessage())
|
||||
return UnknownVal();
|
||||
|
||||
|
||||
if (const Expr *RecE = getOriginExpr()->getInstanceReceiver())
|
||||
return getSVal(RecE);
|
||||
|
||||
|
@ -709,7 +709,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const {
|
|||
return K;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const_cast<ObjCMethodCall *>(this)->Data
|
||||
= ObjCMessageDataTy(nullptr, 1).getOpaqueValue();
|
||||
assert(getMessageKind() == OCM_Message);
|
||||
|
@ -730,7 +730,7 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
|
|||
getState()->getStateManager().getContext().getSourceManager();
|
||||
|
||||
// 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.
|
||||
// This is probably very rare.
|
||||
SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc();
|
||||
|
|
|
@ -23,7 +23,7 @@ StringRef CheckerBase::getTagDescription() const {
|
|||
|
||||
CheckName CheckerBase::getCheckName() const { return Name; }
|
||||
|
||||
CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName,
|
||||
CheckerProgramPointTag::CheckerProgramPointTag(StringRef CheckerName,
|
||||
StringRef Msg)
|
||||
: SimpleProgramPointTag(CheckerName, Msg) {}
|
||||
|
||||
|
|
|
@ -357,9 +357,9 @@ void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC,
|
|||
ExplodedNodeSet &Dst,
|
||||
ExplodedNode *Pred,
|
||||
ExprEngine &Eng) {
|
||||
|
||||
|
||||
// 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.
|
||||
NodeBuilder Bldr(Pred, Dst, BC);
|
||||
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.
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
|
@ -478,7 +478,7 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state,
|
|||
// bail out.
|
||||
if (!state)
|
||||
return nullptr;
|
||||
state = RegionChangesCheckers[i].CheckFn(state, invalidated,
|
||||
state = RegionChangesCheckers[i].CheckFn(state, invalidated,
|
||||
ExplicitRegions, Regions, Call);
|
||||
}
|
||||
return state;
|
||||
|
@ -506,7 +506,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State,
|
|||
}
|
||||
|
||||
/// \brief Run checkers for handling assumptions on symbolic values.
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
CheckerManager::runCheckersForEvalAssume(ProgramStateRef state,
|
||||
SVal Cond, bool Assumption) {
|
||||
for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) {
|
||||
|
@ -558,7 +558,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
|
|||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If none of the checkers evaluated the call, ask ExprEngine to handle it.
|
||||
if (!anyEvaluated) {
|
||||
NodeBuilder B(Pred, Dst, Eng.getBuilderContext());
|
||||
|
|
|
@ -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 {
|
||||
// Sort checkers for efficient collection.
|
||||
std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
|
||||
|
|
|
@ -26,7 +26,7 @@ static DefinedSVal getLocFromSymbol(const ProgramStateRef &State,
|
|||
}
|
||||
|
||||
ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State,
|
||||
SymbolRef Sym) {
|
||||
SymbolRef Sym) {
|
||||
QualType Ty = Sym->getType();
|
||||
DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym)
|
||||
: nonloc::SymbolVal(Sym);
|
||||
|
|
|
@ -271,7 +271,7 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
|
|||
|
||||
bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
|
||||
unsigned Steps,
|
||||
ProgramStateRef InitState,
|
||||
ProgramStateRef InitState,
|
||||
ExplodedNodeSet &Dst) {
|
||||
bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
case Stmt::DoStmtClass:
|
||||
HandleBranch(cast<DoStmt>(Term)->getCond(), Term, B, Pred);
|
||||
return;
|
||||
|
@ -456,7 +456,7 @@ void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *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) {
|
||||
assert(B->succ_size() == 2);
|
||||
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) {
|
||||
assert(B);
|
||||
assert(!B->empty());
|
||||
|
|
|
@ -97,9 +97,9 @@ SVal Environment::getSVal(const EnvironmentEntry &Entry,
|
|||
const ReturnStmt *RS = cast<ReturnStmt>(S);
|
||||
if (const Expr *RE = RS->getRetValue())
|
||||
return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder);
|
||||
return UndefinedVal();
|
||||
return UndefinedVal();
|
||||
}
|
||||
|
||||
|
||||
// Handle all other Stmt* using a lookup.
|
||||
default:
|
||||
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) {
|
||||
const EnvironmentEntry &En = I.getKey();
|
||||
|
||||
|
||||
if (isFirst) {
|
||||
Out << NL << NL
|
||||
<< "Expressions:"
|
||||
<< NL;
|
||||
<< NL;
|
||||
isFirst = false;
|
||||
} else {
|
||||
Out << NL;
|
||||
}
|
||||
|
||||
|
||||
const Stmt *S = En.getStmt();
|
||||
assert(S != nullptr && "Expected non-null Stmt");
|
||||
|
||||
|
|
|
@ -90,8 +90,8 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
|
|||
// (7) The LocationContext is the same as the predecessor.
|
||||
// (8) Expressions that are *not* lvalue expressions.
|
||||
// (9) The PostStmt isn't for a non-consumed Stmt or Expr.
|
||||
// (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
|
||||
// (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
|
||||
// call with no inlining).
|
||||
// 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());
|
||||
if (pred->succ_size() != 1)
|
||||
return false;
|
||||
|
||||
|
||||
const ExplodedNode *succ = *(node->succ_begin());
|
||||
if (succ->pred_size() != 1)
|
||||
return false;
|
||||
|
@ -123,7 +123,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
|
|||
|
||||
// Conditions 5, 6, and 7.
|
||||
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 ||
|
||||
progPoint.getLocationContext() != pred->getLocationContext())
|
||||
return false;
|
||||
|
@ -174,7 +174,7 @@ void ExplodedGraph::collectNode(ExplodedNode *node) {
|
|||
FreeNodes.push_back(node);
|
||||
Nodes.RemoveNode(node);
|
||||
--NumNodes;
|
||||
node->~ExplodedNode();
|
||||
node->~ExplodedNode();
|
||||
}
|
||||
|
||||
void ExplodedGraph::reclaimRecentlyAllocatedNodes() {
|
||||
|
|
|
@ -174,7 +174,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ bool ExprEngine::wantsRegionChangeUpdate(ProgramStateRef state) {
|
|||
return getCheckerManager().wantsRegionChangeUpdate(state);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
ExprEngine::processRegionChanges(ProgramStateRef state,
|
||||
const InvalidatedSymbols *invalidated,
|
||||
ArrayRef<const MemRegion *> Explicits,
|
||||
|
@ -315,7 +315,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
|
|||
const CFGStmt S,
|
||||
const ExplodedNode *Pred,
|
||||
const LocationContext *LC) {
|
||||
|
||||
|
||||
// Are we never purging state values?
|
||||
if (AMgr.options.AnalysisPurgeOpt == PurgeNone)
|
||||
return false;
|
||||
|
@ -327,7 +327,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr,
|
|||
// Is this on a non-expression?
|
||||
if (!isa<Expr>(S.getStmt()))
|
||||
return true;
|
||||
|
||||
|
||||
// Run before processing a call.
|
||||
if (CallEvent::isCallStmt(S.getStmt()))
|
||||
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.begin() == Pred && "have not generated any new nodes yet");
|
||||
Tmp.clear();
|
||||
|
||||
|
||||
PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
|
||||
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());
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case Stmt::ParenExprClass:
|
||||
llvm_unreachable("ParenExprs already handled.");
|
||||
case Stmt::GenericSelectionExprClass:
|
||||
|
@ -966,7 +966,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
|
||||
ExplodedNodeSet preVisit;
|
||||
getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this);
|
||||
|
||||
|
||||
ExplodedNodeSet Tmp;
|
||||
StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx);
|
||||
|
||||
|
@ -974,7 +974,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
QualType resultType = Ex->getType();
|
||||
|
||||
for (ExplodedNodeSet::iterator it = preVisit.begin(), et = preVisit.end();
|
||||
it != et; ++it) {
|
||||
it != et; ++it) {
|
||||
ExplodedNode *N = *it;
|
||||
const LocationContext *LCtx = N->getLocationContext();
|
||||
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);
|
||||
Bldr2.generateNode(S, N, state);
|
||||
}
|
||||
|
||||
|
||||
getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this);
|
||||
Bldr.addNodes(Dst);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
case Stmt::ArraySubscriptExprClass:
|
||||
|
@ -1031,7 +1031,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
}
|
||||
|
||||
Bldr.takeNodes(Pred);
|
||||
|
||||
|
||||
if (AMgr.options.eagerlyAssumeBinOpBifurcation &&
|
||||
(B->isRelationalOp() || B->isEqualityOp())) {
|
||||
ExplodedNodeSet Tmp;
|
||||
|
@ -1076,7 +1076,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
Bldr.addNodes(Dst);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case Stmt::CXXCatchStmtClass: {
|
||||
Bldr.takeNodes(Pred);
|
||||
VisitCXXCatchStmt(cast<CXXCatchStmt>(S), Pred, Dst);
|
||||
|
@ -1085,7 +1085,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
}
|
||||
|
||||
case Stmt::CXXTemporaryObjectExprClass:
|
||||
case Stmt::CXXConstructExprClass: {
|
||||
case Stmt::CXXConstructExprClass: {
|
||||
Bldr.takeNodes(Pred);
|
||||
VisitCXXConstructExpr(cast<CXXConstructExpr>(S), Pred, Dst);
|
||||
Bldr.addNodes(Dst);
|
||||
|
@ -1107,7 +1107,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
|
||||
getCheckerManager().runCheckersForPreStmt(PreVisit, Pred, S, *this);
|
||||
|
||||
for (ExplodedNodeSet::iterator i = PreVisit.begin(),
|
||||
for (ExplodedNodeSet::iterator i = PreVisit.begin(),
|
||||
e = PreVisit.end(); i != e ; ++i)
|
||||
VisitCXXDeleteExpr(CDE, *i, Dst);
|
||||
|
||||
|
@ -1173,18 +1173,18 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
case Stmt::CXXDynamicCastExprClass:
|
||||
case Stmt::CXXReinterpretCastExprClass:
|
||||
case Stmt::CXXConstCastExprClass:
|
||||
case Stmt::CXXFunctionalCastExprClass:
|
||||
case Stmt::CXXFunctionalCastExprClass:
|
||||
case Stmt::ObjCBridgedCastExprClass: {
|
||||
Bldr.takeNodes(Pred);
|
||||
const CastExpr *C = cast<CastExpr>(S);
|
||||
// Handle the previsit checks.
|
||||
ExplodedNodeSet dstPrevisit;
|
||||
getCheckerManager().runCheckersForPreStmt(dstPrevisit, Pred, C, *this);
|
||||
|
||||
|
||||
// Handle the expression itself.
|
||||
ExplodedNodeSet dstExpr;
|
||||
for (ExplodedNodeSet::iterator i = dstPrevisit.begin(),
|
||||
e = dstPrevisit.end(); i != e ; ++i) {
|
||||
e = dstPrevisit.end(); i != e ; ++i) {
|
||||
VisitCast(C, C->getSubExpr(), *i, dstExpr);
|
||||
}
|
||||
|
||||
|
@ -1201,7 +1201,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
Bldr.addNodes(Dst);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case Stmt::InitListExprClass:
|
||||
Bldr.takeNodes(Pred);
|
||||
VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
|
||||
|
@ -1296,7 +1296,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
|||
Bldr.takeNodes(Pred);
|
||||
ProgramStateRef state = Pred->getState();
|
||||
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());
|
||||
Bldr.generateNode(S, Pred,
|
||||
state->BindExpr(S, Pred->getLocationContext(), V));
|
||||
|
@ -1377,7 +1377,7 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
|
|||
|
||||
/// Block entrance. (Update counters).
|
||||
void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
|
||||
NodeBuilderWithSinks &nodeBuilder,
|
||||
NodeBuilderWithSinks &nodeBuilder,
|
||||
ExplodedNode *Pred) {
|
||||
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 (X.isUnknownOrUndef()) {
|
||||
builder.generateNode(PrevState, true, PredI);
|
||||
|
@ -1752,7 +1752,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
|
|||
DefinedOrUnknownSVal CondV = CondV_untested.castAs<DefinedOrUnknownSVal>();
|
||||
|
||||
ProgramStateRef DefaultSt = state;
|
||||
|
||||
|
||||
iterator I = builder.begin(), EI = builder.end();
|
||||
bool defaultIsFeasible = I == EI;
|
||||
|
||||
|
@ -1760,7 +1760,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) {
|
|||
// Successor may be pruned out during CFG construction.
|
||||
if (!I.getBlock())
|
||||
continue;
|
||||
|
||||
|
||||
const CaseStmt *Case = I.getCase();
|
||||
|
||||
// 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)) {
|
||||
// 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());
|
||||
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 *Idx = A->getIdx()->IgnoreParens();
|
||||
|
||||
|
||||
|
||||
ExplodedNodeSet checkerPreStmt;
|
||||
getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this);
|
||||
|
@ -2066,14 +2066,14 @@ ProgramStateRef ExprEngine::processPointerEscapedOnBind(ProgramStateRef State,
|
|||
return State;
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
|
||||
const InvalidatedSymbols *Invalidated,
|
||||
ArrayRef<const MemRegion *> ExplicitRegions,
|
||||
ArrayRef<const MemRegion *> Regions,
|
||||
const CallEvent *Call,
|
||||
RegionAndSymbolInvalidationTraits &ITraits) {
|
||||
|
||||
|
||||
if (!Invalidated || Invalidated->empty())
|
||||
return State;
|
||||
|
||||
|
@ -2084,7 +2084,7 @@ ExprEngine::notifyCheckersOfPointerEscape(ProgramStateRef State,
|
|||
PSK_EscapeOther,
|
||||
&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.
|
||||
InvalidatedSymbols SymbolsDirectlyInvalidated;
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
|
||||
I!=E; ++I) {
|
||||
ExplodedNode *PredI = *I;
|
||||
ProgramStateRef state = PredI->getState();
|
||||
|
||||
|
||||
state = processPointerEscapedOnBind(state, location, Val);
|
||||
|
||||
// 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
|
||||
// instead "int *p" is noted as
|
||||
// "Variable 'p' initialized to a null pointer value"
|
||||
|
||||
|
||||
static SimpleProgramPointTag tag(TagProviderName, "Location");
|
||||
Bldr.generateNode(NodeEx, Pred, state, &tag);
|
||||
}
|
||||
|
@ -2328,7 +2328,7 @@ void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst,
|
|||
ExplodedNodeSet &Src,
|
||||
const Expr *Ex) {
|
||||
StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx);
|
||||
|
||||
|
||||
for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
|
||||
ExplodedNode *Pred = *I;
|
||||
// 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.
|
||||
if (StateTrue) {
|
||||
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
|
||||
SVal Val = svalBuilder.makeIntVal(1U, Ex->getType());
|
||||
StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val);
|
||||
Bldr.generateNode(Ex, Pred, StateTrue, tags.first);
|
||||
}
|
||||
|
@ -2643,10 +2643,10 @@ struct DOTGraphTraits<ExplodedNode*> :
|
|||
<< " NodeID: " << (const void*) N << "\\|";
|
||||
state->printDOT(Out);
|
||||
|
||||
Out << "\\l";
|
||||
Out << "\\l";
|
||||
|
||||
if (const ProgramPointTag *tag = Loc.getTag()) {
|
||||
Out << "\\|Tag: " << tag->getTagDescription();
|
||||
Out << "\\|Tag: " << tag->getTagDescription();
|
||||
Out << "\\l";
|
||||
}
|
||||
return Out.str();
|
||||
|
|
|
@ -25,23 +25,23 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
|
||||
Expr *LHS = B->getLHS()->IgnoreParens();
|
||||
Expr *RHS = B->getRHS()->IgnoreParens();
|
||||
|
||||
|
||||
// FIXME: Prechecks eventually go in ::Visit().
|
||||
ExplodedNodeSet CheckedSet;
|
||||
ExplodedNodeSet Tmp2;
|
||||
getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, B, *this);
|
||||
|
||||
|
||||
// With both the LHS and RHS evaluated, process the operation itself.
|
||||
for (ExplodedNodeSet::iterator it=CheckedSet.begin(), ei=CheckedSet.end();
|
||||
it != ei; ++it) {
|
||||
|
||||
|
||||
ProgramStateRef state = (*it)->getState();
|
||||
const LocationContext *LCtx = (*it)->getLocationContext();
|
||||
SVal LeftV = state->getSVal(LHS, LCtx);
|
||||
SVal RightV = state->getSVal(RHS, LCtx);
|
||||
|
||||
|
||||
BinaryOperator::Opcode Op = B->getOpcode();
|
||||
|
||||
|
||||
if (Op == BO_Assign) {
|
||||
// EXPERIMENTAL: "Conjured" symbols.
|
||||
// FIXME: Handle structs.
|
||||
|
@ -57,7 +57,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
LeftV, RightV);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!B->isAssignmentOp()) {
|
||||
StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx);
|
||||
|
||||
|
@ -90,19 +90,19 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
|
||||
// Process non-assignments except commas or short-circuited
|
||||
// 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()) {
|
||||
Bldr.generateNode(B, *it, state);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
state = state->BindExpr(B, LCtx, Result);
|
||||
state = state->BindExpr(B, LCtx, Result);
|
||||
Bldr.generateNode(B, *it, state);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
assert (B->isCompoundAssignmentOp());
|
||||
|
||||
|
||||
switch (Op) {
|
||||
default:
|
||||
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_OrAssign: Op = BO_Or; break;
|
||||
}
|
||||
|
||||
|
||||
// Perform a load (the LHS). This performs the checks for
|
||||
// null dereferences, and so on.
|
||||
ExplodedNodeSet Tmp;
|
||||
SVal location = LeftV;
|
||||
evalLoad(Tmp, B, LHS, *it, state, location);
|
||||
|
||||
|
||||
for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E;
|
||||
++I) {
|
||||
|
||||
state = (*I)->getState();
|
||||
const LocationContext *LCtx = (*I)->getLocationContext();
|
||||
SVal V = state->getSVal(LHS, LCtx);
|
||||
|
||||
|
||||
// Get the computation type.
|
||||
QualType CTy =
|
||||
cast<CompoundAssignOperator>(B)->getComputationResultType();
|
||||
CTy = getContext().getCanonicalType(CTy);
|
||||
|
||||
|
||||
QualType CLHSTy =
|
||||
cast<CompoundAssignOperator>(B)->getComputationLHSType();
|
||||
CLHSTy = getContext().getCanonicalType(CLHSTy);
|
||||
|
||||
|
||||
QualType LTy = getContext().getCanonicalType(LHS->getType());
|
||||
|
||||
|
||||
// Promote LHS.
|
||||
V = svalBuilder.evalCast(V, CLHSTy, LTy);
|
||||
|
||||
|
||||
// Compute the result of the operation.
|
||||
SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
|
||||
B->getType(), CTy);
|
||||
|
||||
|
||||
// EXPERIMENTAL: "Conjured" symbols.
|
||||
// FIXME: Handle structs.
|
||||
|
||||
|
||||
SVal LHSVal;
|
||||
|
||||
|
||||
if (Result.isUnknown()) {
|
||||
// The symbolic value is actually for the type of the left-hand side
|
||||
// expression, not the computation type, as this is the value the
|
||||
|
@ -168,42 +168,42 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
|
|||
// computation type.
|
||||
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.
|
||||
if (B->isGLValue())
|
||||
state = state->BindExpr(B, LCtx, location);
|
||||
else
|
||||
state = state->BindExpr(B, LCtx, Result);
|
||||
|
||||
|
||||
evalStore(Tmp2, B, LHS, *I, state, location, LHSVal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// FIXME: postvisits eventually go in ::Visit()
|
||||
getCheckerManager().runCheckersForPostStmt(Dst, Tmp2, B, *this);
|
||||
}
|
||||
|
||||
void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
|
||||
|
||||
CanQualType T = getContext().getCanonicalType(BE->getType());
|
||||
|
||||
// Get the value of the block itself.
|
||||
SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
|
||||
Pred->getLocationContext(),
|
||||
currBldrCtx->blockCount());
|
||||
|
||||
|
||||
ProgramStateRef State = Pred->getState();
|
||||
|
||||
|
||||
// If we created a new MemRegion for the block, we should explicitly bind
|
||||
// the captured variables.
|
||||
if (const BlockDataRegion *BDR =
|
||||
dyn_cast_or_null<BlockDataRegion>(V.getAsRegion())) {
|
||||
|
||||
|
||||
BlockDataRegion::referenced_vars_iterator I = BDR->referenced_vars_begin(),
|
||||
E = BDR->referenced_vars_end();
|
||||
|
||||
|
||||
for (; I != E; ++I) {
|
||||
const MemRegion *capturedR = I.getCapturedRegion();
|
||||
const MemRegion *originalR = I.getOriginalRegion();
|
||||
|
@ -213,7 +213,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ExplodedNodeSet Tmp;
|
||||
StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx);
|
||||
Bldr.generateNode(BE, Pred,
|
||||
|
@ -224,12 +224,12 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
|
|||
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) {
|
||||
|
||||
|
||||
ExplodedNodeSet dstPreStmt;
|
||||
getCheckerManager().runCheckersForPreStmt(dstPreStmt, Pred, CastE, *this);
|
||||
|
||||
|
||||
if (CastE->getCastKind() == CK_LValueToRValue) {
|
||||
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
|
||||
I!=E; ++I) {
|
||||
|
@ -240,18 +240,18 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// All other casts.
|
||||
|
||||
// All other casts.
|
||||
QualType T = CastE->getType();
|
||||
QualType ExTy = Ex->getType();
|
||||
|
||||
|
||||
if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
|
||||
T = ExCast->getTypeAsWritten();
|
||||
|
||||
|
||||
StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx);
|
||||
for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end();
|
||||
I != E; ++I) {
|
||||
|
||||
|
||||
Pred = *I;
|
||||
ProgramStateRef state = Pred->getState();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
|
@ -316,8 +316,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
case CK_IntegralComplexToFloatingComplex:
|
||||
case CK_CPointerToObjCPointerCast:
|
||||
case CK_BlockPointerToObjCPointerCast:
|
||||
case CK_AnyPointerToBlockPointerCast:
|
||||
case CK_ObjCObjectLValueCast:
|
||||
case CK_AnyPointerToBlockPointerCast:
|
||||
case CK_ObjCObjectLValueCast:
|
||||
case CK_ZeroToOCLEvent:
|
||||
case CK_LValueBitCast: {
|
||||
// Delegate to SValBuilder to process.
|
||||
|
@ -371,7 +371,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
|
|||
svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, resultType,
|
||||
currBldrCtx->blockCount());
|
||||
state = state->BindExpr(CastE, LCtx, NewSym);
|
||||
} else
|
||||
} else
|
||||
// Else, bind to the derived region value.
|
||||
state = state->BindExpr(CastE, LCtx, val);
|
||||
}
|
||||
|
@ -417,7 +417,7 @@ void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL,
|
|||
|
||||
const Expr *Init = CL->getInitializer();
|
||||
SVal V = State->getSVal(CL->getInitializer(), LCtx);
|
||||
|
||||
|
||||
if (isa<CXXConstructExpr>(Init)) {
|
||||
// No work needed. Just pass the value up to this expression.
|
||||
} else {
|
||||
|
@ -450,11 +450,11 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
|
|||
Dst.insert(Pred);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: all pre/post visits should eventually be handled by ::Visit().
|
||||
ExplodedNodeSet dstPreVisit;
|
||||
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this);
|
||||
|
||||
|
||||
ExplodedNodeSet dstEvaluated;
|
||||
StmtNodeBuilder B(dstPreVisit, dstEvaluated, *currBldrCtx);
|
||||
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>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Recover some path-sensitivity if a scalar value evaluated to
|
||||
// UnknownVal.
|
||||
if (InitVal.isUnknown()) {
|
||||
|
@ -596,7 +596,7 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
|
|||
(T->isArrayType() || T->isRecordType() || T->isVectorType() ||
|
||||
T->isAnyComplexType())) {
|
||||
llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList();
|
||||
|
||||
|
||||
// Handle base case where the initializer has no elements.
|
||||
// e.g: static int* myArray[] = {};
|
||||
if (NumInitElements == 0) {
|
||||
|
@ -604,13 +604,13 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
|
|||
B.generateNode(IE, Pred, state->BindExpr(IE, LCtx, V));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (InitListExpr::const_reverse_iterator it = IE->rbegin(),
|
||||
ei = IE->rend(); it != ei; ++it) {
|
||||
SVal V = state->getSVal(cast<Expr>(*it), LCtx);
|
||||
vals = getBasicVals().consVals(V, vals);
|
||||
}
|
||||
|
||||
|
||||
B.generateNode(IE, Pred,
|
||||
state->BindExpr(IE, LCtx,
|
||||
svalBuilder.makeCompoundVal(T, vals)));
|
||||
|
@ -632,7 +632,7 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE,
|
|||
}
|
||||
|
||||
void ExprEngine::VisitGuardedExpr(const Expr *Ex,
|
||||
const Expr *L,
|
||||
const Expr *L,
|
||||
const Expr *R,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
|
@ -692,7 +692,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex,
|
|||
}
|
||||
|
||||
void ExprEngine::
|
||||
VisitOffsetOfExpr(const OffsetOfExpr *OOE,
|
||||
VisitOffsetOfExpr(const OffsetOfExpr *OOE,
|
||||
ExplodedNode *Pred, ExplodedNodeSet &Dst) {
|
||||
StmtNodeBuilder B(Pred, Dst, *currBldrCtx);
|
||||
APSInt IV;
|
||||
|
@ -728,7 +728,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
|
|||
if (Ex->getKind() == UETT_SizeOf) {
|
||||
if (!T->isIncompleteType() && !T->isConstantSizeType()) {
|
||||
assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
|
||||
|
||||
|
||||
// FIXME: Add support for VLA type arguments and VLA expressions.
|
||||
// When that happens, we should probably refactor VLASizeChecker's code.
|
||||
continue;
|
||||
|
@ -739,10 +739,10 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
APSInt Value = Ex->EvaluateKnownConstInt(getContext());
|
||||
CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue());
|
||||
|
||||
|
||||
ProgramStateRef state = (*I)->getState();
|
||||
state = state->BindExpr(Ex, (*I)->getLocationContext(),
|
||||
svalBuilder.makeIntVal(amt.getQuantity(),
|
||||
|
@ -753,7 +753,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex,
|
|||
getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this);
|
||||
}
|
||||
|
||||
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
|
||||
void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
// FIXME: Prechecks eventually go in ::Visit().
|
||||
|
@ -775,13 +775,13 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
|
|||
}
|
||||
case UO_Real: {
|
||||
const Expr *Ex = U->getSubExpr()->IgnoreParens();
|
||||
|
||||
|
||||
// FIXME: We don't have complex SValues yet.
|
||||
if (Ex->getType()->isAnyComplexType()) {
|
||||
// Just report "Unknown."
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// For all other types, UO_Real is an identity operation.
|
||||
assert (U->getType() == Ex->getType());
|
||||
ProgramStateRef state = (*I)->getState();
|
||||
|
@ -790,8 +790,8 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
|
|||
state->getSVal(Ex, LCtx)));
|
||||
break;
|
||||
}
|
||||
|
||||
case UO_Imag: {
|
||||
|
||||
case UO_Imag: {
|
||||
const Expr *Ex = U->getSubExpr()->IgnoreParens();
|
||||
// FIXME: We don't have complex SValues yet.
|
||||
if (Ex->getType()->isAnyComplexType()) {
|
||||
|
@ -805,7 +805,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
|
|||
Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, X));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case UO_Plus:
|
||||
assert(!U->isGLValue());
|
||||
// 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
|
||||
// where it may be a block-level expression, so we need to
|
||||
// generate an extra node that just propagates the value of the
|
||||
// subexpression.
|
||||
// subexpression.
|
||||
const Expr *Ex = U->getSubExpr()->IgnoreParens();
|
||||
ProgramStateRef state = (*I)->getState();
|
||||
const LocationContext *LCtx = (*I)->getLocationContext();
|
||||
|
@ -826,7 +826,7 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
|
|||
state->getSVal(Ex, LCtx)));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case UO_LNot:
|
||||
case UO_Minus:
|
||||
case UO_Not: {
|
||||
|
@ -834,15 +834,15 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
|
|||
const Expr *Ex = U->getSubExpr()->IgnoreParens();
|
||||
ProgramStateRef state = (*I)->getState();
|
||||
const LocationContext *LCtx = (*I)->getLocationContext();
|
||||
|
||||
|
||||
// Get the value of the subexpression.
|
||||
SVal V = state->getSVal(Ex, LCtx);
|
||||
|
||||
|
||||
if (V.isUnknownOrUndef()) {
|
||||
Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (U->getOpcode()) {
|
||||
default:
|
||||
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
|
||||
// transfer functions as "0 == E".
|
||||
SVal Result;
|
||||
SVal Result;
|
||||
if (Optional<Loc> LV = V.getAs<Loc>()) {
|
||||
Loc X = svalBuilder.makeNull();
|
||||
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,
|
||||
U->getType());
|
||||
}
|
||||
|
||||
state = state->BindExpr(U, LCtx, Result);
|
||||
|
||||
state = state->BindExpr(U, LCtx, Result);
|
||||
break;
|
||||
}
|
||||
Bldr.generateNode(U, *I, state);
|
||||
|
@ -891,81 +891,81 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U,
|
|||
// Handle ++ and -- (both pre- and post-increment).
|
||||
assert (U->isIncrementDecrementOp());
|
||||
const Expr *Ex = U->getSubExpr()->IgnoreParens();
|
||||
|
||||
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
ProgramStateRef state = Pred->getState();
|
||||
SVal loc = state->getSVal(Ex, LCtx);
|
||||
|
||||
|
||||
// Perform a load.
|
||||
ExplodedNodeSet Tmp;
|
||||
evalLoad(Tmp, U, Ex, Pred, state, loc);
|
||||
|
||||
|
||||
ExplodedNodeSet Dst2;
|
||||
StmtNodeBuilder Bldr(Tmp, Dst2, *currBldrCtx);
|
||||
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) {
|
||||
|
||||
|
||||
state = (*I)->getState();
|
||||
assert(LCtx == (*I)->getLocationContext());
|
||||
SVal V2_untested = state->getSVal(Ex, LCtx);
|
||||
|
||||
|
||||
// Propagate unknown and undefined values.
|
||||
if (V2_untested.isUnknownOrUndef()) {
|
||||
Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, V2_untested));
|
||||
continue;
|
||||
}
|
||||
DefinedSVal V2 = V2_untested.castAs<DefinedSVal>();
|
||||
|
||||
|
||||
// Handle all other values.
|
||||
BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add : BO_Sub;
|
||||
|
||||
|
||||
// If the UnaryOperator has non-location type, use its type to create the
|
||||
// constant value. If the UnaryOperator has location type, create the
|
||||
// constant with int type and pointer width.
|
||||
SVal RHS;
|
||||
|
||||
|
||||
if (U->getType()->isAnyPointerType())
|
||||
RHS = svalBuilder.makeArrayIndex(1);
|
||||
else if (U->getType()->isIntegralOrEnumerationType())
|
||||
RHS = svalBuilder.makeIntVal(1, U->getType());
|
||||
else
|
||||
RHS = UnknownVal();
|
||||
|
||||
|
||||
SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
|
||||
|
||||
|
||||
// Conjure a new symbol if necessary to recover precision.
|
||||
if (Result.isUnknown()){
|
||||
DefinedOrUnknownSVal SymVal =
|
||||
svalBuilder.conjureSymbolVal(nullptr, Ex, LCtx,
|
||||
currBldrCtx->blockCount());
|
||||
Result = SymVal;
|
||||
|
||||
|
||||
// If the value is a location, ++/-- should always preserve
|
||||
// non-nullness. Check if the original value was non-null, and if so
|
||||
// propagate that constraint.
|
||||
if (Loc::isLocType(U->getType())) {
|
||||
DefinedOrUnknownSVal Constraint =
|
||||
svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType()));
|
||||
|
||||
|
||||
if (!state->assume(Constraint, true)) {
|
||||
// It isn't feasible for the original value to be null.
|
||||
// Propagate this constraint.
|
||||
Constraint = svalBuilder.evalEQ(state, SymVal,
|
||||
svalBuilder.makeZeroVal(U->getType()));
|
||||
|
||||
|
||||
|
||||
|
||||
state = state->assume(Constraint, false);
|
||||
assert(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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++).
|
||||
if (U->isGLValue())
|
||||
state = state->BindExpr(U, LCtx, loc);
|
||||
else
|
||||
state = state->BindExpr(U, LCtx, U->isPostfix() ? V2 : Result);
|
||||
|
||||
|
||||
// Perform the store.
|
||||
Bldr.takeNodes(*I);
|
||||
ExplodedNodeSet Dst3;
|
||||
|
|
|
@ -300,7 +300,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType,
|
|||
const MemRegion *Dest,
|
||||
const Stmt *S,
|
||||
bool IsBaseDtor,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
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
|
||||
// really part of the CXXNewExpr because they happen BEFORE the
|
||||
// CXXConstructExpr subexpression. See PR12014 for some discussion.
|
||||
|
||||
|
||||
unsigned blockCount = currBldrCtx->blockCount();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
DefinedOrUnknownSVal symVal = UnknownVal();
|
||||
|
@ -392,8 +392,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
|
|||
IsStandardGlobalOpNewFunction = (FD->getNumParams() == 1);
|
||||
}
|
||||
|
||||
// We assume all standard global 'operator new' functions allocate memory in
|
||||
// heap. We realize this is an approximation that might not correctly model
|
||||
// We assume all standard global 'operator new' functions allocate memory in
|
||||
// heap. We realize this is an approximation that might not correctly model
|
||||
// a custom global allocator.
|
||||
if (IsStandardGlobalOpNewFunction)
|
||||
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) {
|
||||
StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx);
|
||||
ProgramStateRef state = Pred->getState();
|
||||
|
|
|
@ -44,19 +44,19 @@ void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) {
|
|||
|
||||
const CFG *CalleeCFG = calleeCtx->getCFG();
|
||||
const CFGBlock *Entry = &(CalleeCFG->getEntry());
|
||||
|
||||
|
||||
// Validate the CFG.
|
||||
assert(Entry->empty());
|
||||
assert(Entry->succ_size() == 1);
|
||||
|
||||
|
||||
// Get the solitary successor.
|
||||
const CFGBlock *Succ = *(Entry->succ_begin());
|
||||
|
||||
|
||||
// Construct an edge representing the starting location in the callee.
|
||||
BlockEdge Loc(Entry, Succ, calleeCtx);
|
||||
|
||||
ProgramStateRef state = Pred->getState();
|
||||
|
||||
|
||||
// Construct a new node and add it to the worklist.
|
||||
bool 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);
|
||||
}
|
||||
|
||||
/// The call exit is simulated with a sequence of nodes, which occur between
|
||||
/// CallExitBegin and CallExitEnd. The following operations occur between the
|
||||
/// The call exit is simulated with a sequence of nodes, which occur between
|
||||
/// CallExitBegin and CallExitEnd. The following operations occur between the
|
||||
/// two program points:
|
||||
/// 1. CallExitBegin (triggers the start of call exit sequence)
|
||||
/// 2. Bind the return value
|
||||
|
@ -220,12 +220,12 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) {
|
|||
PrettyStackTraceLocationContext CrashInfo(CEBNode->getLocationContext());
|
||||
const StackFrameContext *calleeCtx =
|
||||
CEBNode->getLocationContext()->getCurrentStackFrame();
|
||||
|
||||
|
||||
// The parent context might not be a stack frame, so make sure we
|
||||
// look up the first enclosing stack frame.
|
||||
const StackFrameContext *callerCtx =
|
||||
calleeCtx->getParent()->getCurrentStackFrame();
|
||||
|
||||
|
||||
const Stmt *CE = calleeCtx->getCallSite();
|
||||
ProgramStateRef state = CEBNode->getState();
|
||||
// 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),
|
||||
BR);
|
||||
}
|
||||
|
||||
|
||||
// This may be NULL, but that's fine.
|
||||
const Expr *CallE = Call.getOriginExpr();
|
||||
|
||||
|
@ -439,8 +439,8 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D,
|
|||
CalleeADC->getStackFrame(ParentOfCallee, CallE,
|
||||
currBldrCtx->getBlock(),
|
||||
currStmtIdx);
|
||||
|
||||
|
||||
|
||||
|
||||
CallEnter Loc(CallE, CalleeSFC, CurLC);
|
||||
|
||||
// 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 (isContainerMethod(Ctx, FD))
|
||||
return false;
|
||||
|
||||
|
||||
// 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
|
||||
// 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,
|
||||
ExplodedNodeSet &Dst) {
|
||||
|
||||
|
||||
ExplodedNodeSet dstPreVisit;
|
||||
getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this);
|
||||
|
||||
StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx);
|
||||
|
||||
|
||||
if (RS->getRetValue()) {
|
||||
for (ExplodedNodeSet::iterator it = dstPreVisit.begin(),
|
||||
ei = dstPreVisit.end(); it != ei; ++it) {
|
||||
|
|
|
@ -19,18 +19,18 @@
|
|||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
|
||||
void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
ProgramStateRef state = Pred->getState();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
SVal baseVal = state->getSVal(Ex->getBase(), LCtx);
|
||||
SVal location = state->getLValue(Ex->getDecl(), baseVal);
|
||||
|
||||
|
||||
ExplodedNodeSet dstIvar;
|
||||
StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx);
|
||||
Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location));
|
||||
|
||||
|
||||
// Perform the post-condition check of the ObjCIvarRefExpr and store
|
||||
// the created nodes in 'Dst'.
|
||||
getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this);
|
||||
|
@ -45,7 +45,7 @@ void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
|
|||
void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
|
||||
ExplodedNode *Pred,
|
||||
ExplodedNodeSet &Dst) {
|
||||
|
||||
|
||||
// ObjCForCollectionStmts are processed in two places. This method
|
||||
// handles the case where an ObjCForCollectionStmt* occurs as one of the
|
||||
// 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();
|
||||
ProgramStateRef state = Pred->getState();
|
||||
SVal elementV;
|
||||
|
||||
|
||||
if (const DeclStmt *DS = dyn_cast<DeclStmt>(elem)) {
|
||||
const VarDecl *elemD = cast<VarDecl>(DS->getSingleDecl());
|
||||
assert(elemD->getInit() == nullptr);
|
||||
|
@ -83,7 +83,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
|
|||
else {
|
||||
elementV = state->getSVal(elem, Pred->getLocationContext());
|
||||
}
|
||||
|
||||
|
||||
ExplodedNodeSet dstLocation;
|
||||
evalLocation(dstLocation, S, elem, Pred, state, elementV, nullptr, false);
|
||||
|
||||
|
@ -95,17 +95,17 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
|
|||
Pred = *NI;
|
||||
ProgramStateRef state = Pred->getState();
|
||||
const LocationContext *LCtx = Pred->getLocationContext();
|
||||
|
||||
|
||||
// Handle the case where the container still has elements.
|
||||
SVal TrueV = svalBuilder.makeTruthVal(1);
|
||||
ProgramStateRef hasElems = state->BindExpr(S, LCtx, TrueV);
|
||||
|
||||
|
||||
// Handle the case where the container has no elements.
|
||||
SVal FalseV = svalBuilder.makeTruthVal(0);
|
||||
ProgramStateRef noElems = state->BindExpr(S, LCtx, FalseV);
|
||||
|
||||
if (Optional<loc::MemRegionVal> MV = elementV.getAs<loc::MemRegionVal>())
|
||||
if (const TypedValueRegion *R =
|
||||
if (const TypedValueRegion *R =
|
||||
dyn_cast<TypedValueRegion>(MV->getRegion())) {
|
||||
// FIXME: The proper thing to do is to really iterate over the
|
||||
// container. We will do this with dispatch logic to the store.
|
||||
|
@ -116,12 +116,12 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
|
|||
currBldrCtx->blockCount());
|
||||
SVal V = svalBuilder.makeLoc(Sym);
|
||||
hasElems = hasElems->bindLoc(elementV, V);
|
||||
|
||||
|
||||
// Bind the location to 'nil' on the false branch.
|
||||
SVal nilV = svalBuilder.makeIntVal(0, T);
|
||||
noElems = noElems->bindLoc(elementV, nilV);
|
||||
}
|
||||
|
||||
|
||||
// Create the new nodes.
|
||||
Bldr.generateNode(S, Pred, hasElems);
|
||||
Bldr.generateNode(S, Pred, noElems);
|
||||
|
@ -156,7 +156,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
|
|||
ExplodedNode *Pred = *DI;
|
||||
ProgramStateRef State = Pred->getState();
|
||||
CallEventRef<ObjCMethodCall> UpdatedMsg = Msg.cloneWithState(State);
|
||||
|
||||
|
||||
if (UpdatedMsg->isInstanceMessage()) {
|
||||
SVal recVal = UpdatedMsg->getReceiverSVal();
|
||||
if (!recVal.isUndef()) {
|
||||
|
@ -166,7 +166,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
|
|||
|
||||
ProgramStateRef notNilState, nilState;
|
||||
std::tie(notNilState, nilState) = State->assume(receiverVal);
|
||||
|
||||
|
||||
// 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.
|
||||
// FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
|
||||
|
@ -174,7 +174,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
|
|||
if (nilState && !notNilState) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check if the "raise" message was sent.
|
||||
assert(notNilState);
|
||||
if (ObjCNoRet.isImplicitNoReturn(ME)) {
|
||||
|
@ -183,7 +183,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
|
|||
Bldr.generateSink(ME, Pred, State);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Generate a transition to non-Nil state.
|
||||
if (notNilState != State) {
|
||||
Pred = Bldr.generateNode(ME, Pred, notNilState);
|
||||
|
@ -203,7 +203,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
|
|||
|
||||
defaultEvalCall(Bldr, Pred, *UpdatedMsg);
|
||||
}
|
||||
|
||||
|
||||
ExplodedNodeSet dstPostvisit;
|
||||
getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval,
|
||||
*Msg, *this);
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
##===- clang/lib/StaticAnalyzer/Core/Makefile --------------*- Makefile -*-===##
|
||||
#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# 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.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
|
|
|
@ -756,7 +756,7 @@ getStackOrCaptureRegionForDeclContext(const LocationContext *LC,
|
|||
return cast<VarRegion>(I.getCapturedRegion());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LC = LC->getParent();
|
||||
}
|
||||
return (const StackFrameContext *)nullptr;
|
||||
|
@ -788,18 +788,18 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D,
|
|||
else
|
||||
sReg = getGlobalsRegion();
|
||||
}
|
||||
|
||||
// Finally handle static locals.
|
||||
|
||||
// Finally handle static locals.
|
||||
} else {
|
||||
// FIXME: Once we implement scope handling, we will need to properly lookup
|
||||
// 'D' to the proper LocationContext.
|
||||
const DeclContext *DC = D->getDeclContext();
|
||||
llvm::PointerUnion<const StackFrameContext *, const VarRegion *> V =
|
||||
getStackOrCaptureRegionForDeclContext(LC, DC, D);
|
||||
|
||||
|
||||
if (V.is<const VarRegion*>())
|
||||
return V.get<const VarRegion*>();
|
||||
|
||||
|
||||
const StackFrameContext *STC = V.get<const StackFrameContext*>();
|
||||
|
||||
if (!STC)
|
||||
|
@ -1239,7 +1239,7 @@ RegionOffset MemRegion::getAsOffset() const {
|
|||
Ty = SR->getSymbol()->getType()->getPointeeType();
|
||||
RootIsSymbolic = true;
|
||||
}
|
||||
|
||||
|
||||
const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl();
|
||||
if (!Child) {
|
||||
// We cannot compute the offset of the base class.
|
||||
|
@ -1290,7 +1290,7 @@ RegionOffset MemRegion::getAsOffset() const {
|
|||
if (Optional<nonloc::ConcreteInt> CI =
|
||||
Index.getAs<nonloc::ConcreteInt>()) {
|
||||
// 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)
|
||||
continue;
|
||||
|
||||
|
@ -1324,7 +1324,7 @@ RegionOffset MemRegion::getAsOffset() const {
|
|||
|
||||
// Get the field number.
|
||||
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)
|
||||
if (FR->getDecl() == *FI)
|
||||
break;
|
||||
|
@ -1420,7 +1420,7 @@ BlockDataRegion::referenced_vars_begin() const {
|
|||
|
||||
BumpVector<const MemRegion*> *VecOriginal =
|
||||
static_cast<BumpVector<const MemRegion*>*>(OriginalVars);
|
||||
|
||||
|
||||
return BlockDataRegion::referenced_vars_iterator(Vec->begin(),
|
||||
VecOriginal->begin());
|
||||
}
|
||||
|
@ -1456,12 +1456,12 @@ const VarRegion *BlockDataRegion::getOriginalRegion(const VarRegion *R) const {
|
|||
// RegionAndSymbolInvalidationTraits
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym,
|
||||
void RegionAndSymbolInvalidationTraits::setTrait(SymbolRef Sym,
|
||||
InvalidationKinds IK) {
|
||||
SymTraitsMap[Sym] |= IK;
|
||||
}
|
||||
|
||||
void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
|
||||
void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
|
||||
InvalidationKinds IK) {
|
||||
assert(MR);
|
||||
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
|
||||
|
@ -1470,13 +1470,13 @@ void RegionAndSymbolInvalidationTraits::setTrait(const MemRegion *MR,
|
|||
MRTraitsMap[MR] |= IK;
|
||||
}
|
||||
|
||||
bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym,
|
||||
bool RegionAndSymbolInvalidationTraits::hasTrait(SymbolRef Sym,
|
||||
InvalidationKinds IK) {
|
||||
const_symbol_iterator I = SymTraitsMap.find(Sym);
|
||||
if (I != SymTraitsMap.end())
|
||||
return I->second & IK;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RegionAndSymbolInvalidationTraits::hasTrait(const MemRegion *MR,
|
||||
|
|
|
@ -179,7 +179,7 @@ void PathDiagnostic::resetDiagnosticLocationToMainFile() {
|
|||
// Reset the report containing declaration and location.
|
||||
DeclWithIssue = CP->getCaller();
|
||||
Loc = CP->getLocation();
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
|
|||
std::unique_ptr<PathDiagnostic> D) {
|
||||
if (!D || D->path.empty())
|
||||
return;
|
||||
|
||||
|
||||
// We need to flatten the locations (convert Stmt* to locations) because
|
||||
// the referenced statements may be freed by the time the diagnostics
|
||||
// are emitted.
|
||||
|
@ -221,12 +221,12 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
|
|||
++I) {
|
||||
const PathDiagnosticPiece *piece = I->get();
|
||||
FullSourceLoc L = piece->getLocation().asLocation().getExpansionLoc();
|
||||
|
||||
|
||||
if (FID.isInvalid()) {
|
||||
FID = SMgr.getFileID(L);
|
||||
} else if (SMgr.getFileID(L) != FID)
|
||||
return; // FIXME: Emit a warning?
|
||||
|
||||
|
||||
// Check the source ranges.
|
||||
ArrayRef<SourceRange> Ranges = piece->getRanges();
|
||||
for (ArrayRef<SourceRange>::iterator I = Ranges.begin(),
|
||||
|
@ -238,7 +238,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
|
|||
if (!L.isFileID() || SMgr.getFileID(L) != FID)
|
||||
return; // FIXME: Emit a warning?
|
||||
}
|
||||
|
||||
|
||||
if (const PathDiagnosticCallPiece *call =
|
||||
dyn_cast<PathDiagnosticCallPiece>(piece)) {
|
||||
WorkList.push_back(&call->path);
|
||||
|
@ -249,10 +249,10 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (FID.isInvalid())
|
||||
return; // FIXME: Emit a warning?
|
||||
}
|
||||
}
|
||||
|
||||
// Profile the node to see if we already have something matching it
|
||||
llvm::FoldingSetNodeID profile;
|
||||
|
@ -318,7 +318,7 @@ static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
|
|||
const PathDiagnosticPiece &Y) {
|
||||
if (X.getKind() != Y.getKind())
|
||||
return X.getKind() < Y.getKind();
|
||||
|
||||
|
||||
FullSourceLoc XL = X.getLocation().asLocation();
|
||||
FullSourceLoc YL = Y.getLocation().asLocation();
|
||||
if (XL != YL)
|
||||
|
@ -331,7 +331,7 @@ static Optional<bool> comparePiece(const PathDiagnosticPiece &X,
|
|||
return X.getRanges().size() < Y.getRanges().size();
|
||||
|
||||
const SourceManager &SM = XL.getManager();
|
||||
|
||||
|
||||
for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) {
|
||||
SourceRange XR = X.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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (X.getKind()) {
|
||||
case clang::ento::PathDiagnosticPiece::ControlFlow:
|
||||
return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X),
|
||||
|
@ -418,9 +418,9 @@ void PathDiagnosticConsumer::FlushDiagnostics(
|
|||
PathDiagnosticConsumer::FilesMade *Files) {
|
||||
if (flushed)
|
||||
return;
|
||||
|
||||
|
||||
flushed = true;
|
||||
|
||||
|
||||
std::vector<const PathDiagnostic *> BatchDiags;
|
||||
for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(),
|
||||
et = Diags.end(); it != et; ++it) {
|
||||
|
@ -448,7 +448,7 @@ void PathDiagnosticConsumer::FlushDiagnostics(
|
|||
const PathDiagnostic *D = *it;
|
||||
delete D;
|
||||
}
|
||||
|
||||
|
||||
// Clear out the FoldingSet.
|
||||
Diags.clear();
|
||||
}
|
||||
|
@ -470,7 +470,7 @@ void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD,
|
|||
Entry = new (Entry) PDFileEntry(NodeID);
|
||||
Set.InsertNode(Entry, InsertPos);
|
||||
}
|
||||
|
||||
|
||||
// Allocate persistent storage for the file name.
|
||||
char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1);
|
||||
memcpy(FileName_cstr, FileName.data(), FileName.size());
|
||||
|
@ -845,7 +845,7 @@ PathDiagnosticRange
|
|||
SourceRange R = S->getSourceRange();
|
||||
if (R.isValid())
|
||||
return R;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case DeclK:
|
||||
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
|
||||
|
@ -947,7 +947,7 @@ static bool describeCodeDecl(raw_ostream &Out, const Decl *D,
|
|||
|
||||
Out << "constructor";
|
||||
describeClass(Out, MD->getParent(), " for ");
|
||||
|
||||
|
||||
} else if (isa<CXXDestructorDecl>(MD)) {
|
||||
if (!MD->isUserProvided()) {
|
||||
Out << "destructor";
|
||||
|
@ -1039,7 +1039,7 @@ static void compute_path_size(const PathPieces &pieces, unsigned &size) {
|
|||
for (PathPieces::const_iterator it = pieces.begin(),
|
||||
et = pieces.end(); it != et; ++it) {
|
||||
const PathDiagnosticPiece *piece = it->get();
|
||||
if (const PathDiagnosticCallPiece *cp =
|
||||
if (const PathDiagnosticCallPiece *cp =
|
||||
dyn_cast<PathDiagnosticCallPiece>(piece)) {
|
||||
compute_path_size(cp->path, size);
|
||||
}
|
||||
|
@ -1075,12 +1075,12 @@ void PathDiagnosticPiece::Profile(llvm::FoldingSetNodeID &ID) const {
|
|||
I != E; ++I) {
|
||||
ID.AddInteger(I->getBegin().getRawEncoding());
|
||||
ID.AddInteger(I->getEnd().getRawEncoding());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PathDiagnosticCallPiece::Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
PathDiagnosticPiece::Profile(ID);
|
||||
for (PathPieces::const_iterator it = path.begin(),
|
||||
for (PathPieces::const_iterator it = path.begin(),
|
||||
et = path.end(); it != et; ++it) {
|
||||
ID.Add(**it);
|
||||
}
|
||||
|
|
|
@ -171,7 +171,7 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P,
|
|||
--indent;
|
||||
Indent(o, indent) << "</array>\n";
|
||||
}
|
||||
|
||||
|
||||
// Output the call depth.
|
||||
Indent(o, indent) << "<key>depth</key>";
|
||||
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);
|
||||
EmitString(o, P.getString()) << '\n';
|
||||
|
||||
|
||||
// Finish up.
|
||||
--indent;
|
||||
Indent(o, indent); o << "</dict>\n";
|
||||
|
@ -208,9 +208,9 @@ static void ReportCall(raw_ostream &o,
|
|||
const LangOptions &LangOpts,
|
||||
unsigned indent,
|
||||
unsigned depth) {
|
||||
|
||||
|
||||
IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnter =
|
||||
P.getCallEnterEvent();
|
||||
P.getCallEnterEvent();
|
||||
|
||||
if (callEnter)
|
||||
ReportPiece(o, *callEnter, FM, SM, LangOpts, indent, depth, true,
|
||||
|
@ -218,18 +218,18 @@ static void ReportCall(raw_ostream &o,
|
|||
|
||||
IntrusiveRefCntPtr<PathDiagnosticEventPiece> callEnterWithinCaller =
|
||||
P.getCallEnterWithinCallerEvent();
|
||||
|
||||
|
||||
++depth;
|
||||
|
||||
|
||||
if (callEnterWithinCaller)
|
||||
ReportPiece(o, *callEnterWithinCaller, FM, SM, LangOpts,
|
||||
indent, depth, true);
|
||||
|
||||
|
||||
for (PathPieces::const_iterator I = P.path.begin(), E = P.path.end();I!=E;++I)
|
||||
ReportPiece(o, **I, FM, SM, LangOpts, indent, depth, true);
|
||||
|
||||
--depth;
|
||||
|
||||
|
||||
IntrusiveRefCntPtr<PathDiagnosticEventPiece> callExit =
|
||||
P.getCallExitEvent();
|
||||
|
||||
|
@ -297,7 +297,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
|
|||
if (!Diags.empty())
|
||||
SM = &(*(*Diags.begin())->path.begin())->getLocation().getManager();
|
||||
|
||||
|
||||
|
||||
for (std::vector<const PathDiagnostic*>::iterator DI = Diags.begin(),
|
||||
DE = Diags.end(); DI != DE; ++DI) {
|
||||
|
||||
|
@ -374,7 +374,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
|
|||
|
||||
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)
|
||||
ReportDiag(o, **I, FM, *SM, LangOpts);
|
||||
|
||||
|
@ -389,7 +389,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
|
|||
EmitString(o, D->getBugType()) << '\n';
|
||||
o << " <key>check_name</key>";
|
||||
EmitString(o, D->getCheckName()) << '\n';
|
||||
|
||||
|
||||
// Output information about the semantic context where
|
||||
// the issue occurred.
|
||||
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
|
||||
// offset from the beginning of the function.
|
||||
if (const Stmt *Body = DeclWithIssue->getBody()) {
|
||||
|
||||
|
||||
// If the bug uniqueing location exists, use it for the hash.
|
||||
// For example, this ensures that two leaks reported on the same line
|
||||
// will have different issue_hashes and that the hash will identify
|
||||
|
@ -486,5 +486,5 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
|
|||
o << " </array>\n";
|
||||
|
||||
// Finish.
|
||||
o << "</dict>\n</plist>";
|
||||
o << "</dict>\n</plist>";
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ void ProgramStateRelease(const ProgramState *state) {
|
|||
if (--s->refCount == 0) {
|
||||
ProgramStateManager &Mgr = s->getStateManager();
|
||||
Mgr.StateSet.RemoveNode(s);
|
||||
s->~ProgramState();
|
||||
s->~ProgramState();
|
||||
Mgr.freeStates.push_back(s);
|
||||
}
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ ProgramStateManager::~ProgramStateManager() {
|
|||
I->second.second(I->second.first);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
ProgramStateManager::removeDeadBindings(ProgramStateRef state,
|
||||
const StackFrameContext *LCtx,
|
||||
SymbolReaper& SymReaper) {
|
||||
|
@ -113,7 +113,7 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state,
|
|||
|
||||
ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const {
|
||||
ProgramStateManager &Mgr = getStateManager();
|
||||
ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
|
||||
ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
|
||||
LV, V));
|
||||
const MemRegion *MR = LV.getAsRegion();
|
||||
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 StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V);
|
||||
ProgramStateRef new_state = makeWithStore(newStore);
|
||||
return Mgr.getOwningEngine() ?
|
||||
Mgr.getOwningEngine()->processRegionChange(new_state, R) :
|
||||
return Mgr.getOwningEngine() ?
|
||||
Mgr.getOwningEngine()->processRegionChange(new_state, R) :
|
||||
new_state;
|
||||
}
|
||||
|
||||
typedef ArrayRef<const MemRegion *> RegionList;
|
||||
typedef ArrayRef<SVal> ValueList;
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
ProgramState::invalidateRegions(RegionList Regions,
|
||||
const Expr *E, unsigned Count,
|
||||
const LocationContext *LCtx,
|
||||
|
@ -197,11 +197,11 @@ ProgramState::invalidateRegionsImpl(ValueList Values,
|
|||
if (CausedByPointerEscape) {
|
||||
newState = Eng->notifyCheckersOfPointerEscape(newState, IS,
|
||||
TopLevelInvalidated,
|
||||
Invalidated, Call,
|
||||
Invalidated, Call,
|
||||
*ITraits);
|
||||
}
|
||||
|
||||
return Eng->processRegionChanges(newState, IS, TopLevelInvalidated,
|
||||
return Eng->processRegionChanges(newState, IS, TopLevelInvalidated,
|
||||
Invalidated, Call);
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ ProgramStateRef ProgramState::killBinding(Loc LV) const {
|
|||
return makeWithStore(newStore);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
ProgramState::enterStackFrame(const CallEvent &Call,
|
||||
const StackFrameContext *CalleeCtx) const {
|
||||
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',
|
||||
// not unsigned.
|
||||
const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int);
|
||||
|
||||
|
||||
if (V.getAs<Loc>())
|
||||
return loc::ConcreteInt(NewV);
|
||||
else
|
||||
|
@ -283,7 +283,7 @@ SVal ProgramState::getSVal(Loc location, QualType T) const {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return V;
|
||||
}
|
||||
|
||||
|
@ -353,11 +353,11 @@ ConditionTruthVal ProgramState::isNull(SVal V) const {
|
|||
|
||||
if (V.isConstant())
|
||||
return false;
|
||||
|
||||
|
||||
SymbolRef Sym = V.getAsSymbol(/* IncludeBaseRegion */ true);
|
||||
if (!Sym)
|
||||
return ConditionTruthVal();
|
||||
|
||||
|
||||
return getStateManager().ConstraintMgr->isNull(this, Sym);
|
||||
}
|
||||
|
||||
|
@ -390,7 +390,7 @@ ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {
|
|||
ProgramState *newState = nullptr;
|
||||
if (!freeStates.empty()) {
|
||||
newState = freeStates.back();
|
||||
freeStates.pop_back();
|
||||
freeStates.pop_back();
|
||||
}
|
||||
else {
|
||||
newState = (ProgramState*) Alloc.Allocate<ProgramState>();
|
||||
|
@ -530,10 +530,10 @@ bool ScanReachableSymbols::scan(const SymExpr *sym) {
|
|||
bool wasVisited = !visited.insert(sym).second;
|
||||
if (wasVisited)
|
||||
return true;
|
||||
|
||||
|
||||
if (!visitor.VisitSymbol(sym))
|
||||
return false;
|
||||
|
||||
|
||||
// TODO: should be rewritten using SymExpr::symbol_iterator.
|
||||
switch (sym->getKind()) {
|
||||
case SymExpr::RegionValueKind:
|
||||
|
@ -582,11 +582,11 @@ bool ScanReachableSymbols::scan(SVal val) {
|
|||
bool ScanReachableSymbols::scan(const MemRegion *R) {
|
||||
if (isa<MemSpaceRegion>(R))
|
||||
return true;
|
||||
|
||||
|
||||
bool wasVisited = !visited.insert(R).second;
|
||||
if (wasVisited)
|
||||
return true;
|
||||
|
||||
|
||||
if (!visitor.VisitMemRegion(R))
|
||||
return false;
|
||||
|
||||
|
@ -722,14 +722,14 @@ bool ProgramState::isTainted(const MemRegion *Reg, TaintTagType K) const {
|
|||
bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
|
||||
if (!Sym)
|
||||
return false;
|
||||
|
||||
|
||||
// Traverse all the symbols this symbol depends on to see if any are tainted.
|
||||
bool Tainted = false;
|
||||
for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end();
|
||||
SI != SE; ++SI) {
|
||||
if (!isa<SymbolData>(*SI))
|
||||
continue;
|
||||
|
||||
|
||||
const TaintTagType *Tag = get<TaintMap>(*SI);
|
||||
Tainted = (Tag && *Tag == Kind);
|
||||
|
||||
|
@ -748,7 +748,7 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const {
|
|||
if (Tainted)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return Tainted;
|
||||
}
|
||||
|
||||
|
|
|
@ -365,7 +365,7 @@ ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State,
|
|||
|
||||
/// Scan all symbols referenced by the constraints. If the symbol is not alive
|
||||
/// as marked in LSymbols, mark it as dead in DSymbols.
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RangeConstraintManager::removeDeadBindings(ProgramStateRef state,
|
||||
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,
|
||||
// UINT_MAX, 0, 1, and 2.
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
|
||||
const llvm::APSInt &Int,
|
||||
const llvm::APSInt &Adjustment) {
|
||||
|
@ -435,7 +435,7 @@ RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
|
|||
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
|
||||
const llvm::APSInt &Int,
|
||||
const llvm::APSInt &Adjustment) {
|
||||
|
@ -450,7 +450,7 @@ RangeConstraintManager::assumeSymEQ(ProgramStateRef St, SymbolRef Sym,
|
|||
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
|
||||
const llvm::APSInt &Int,
|
||||
const llvm::APSInt &Adjustment) {
|
||||
|
@ -479,7 +479,7 @@ RangeConstraintManager::assumeSymLT(ProgramStateRef St, SymbolRef Sym,
|
|||
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
|
||||
const llvm::APSInt &Int,
|
||||
const llvm::APSInt &Adjustment) {
|
||||
|
@ -508,7 +508,7 @@ RangeConstraintManager::assumeSymGT(ProgramStateRef St, SymbolRef Sym,
|
|||
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
|
||||
const llvm::APSInt &Int,
|
||||
const llvm::APSInt &Adjustment) {
|
||||
|
@ -537,7 +537,7 @@ RangeConstraintManager::assumeSymGE(ProgramStateRef St, SymbolRef Sym,
|
|||
return New.isEmpty() ? nullptr : St->set<ConstraintRange>(Sym, New);
|
||||
}
|
||||
|
||||
ProgramStateRef
|
||||
ProgramStateRef
|
||||
RangeConstraintManager::assumeSymLE(ProgramStateRef St, SymbolRef Sym,
|
||||
const llvm::APSInt &Int,
|
||||
const llvm::APSInt &Adjustment) {
|
||||
|
|
|
@ -464,9 +464,9 @@ public: // Part of public interface to class.
|
|||
StoreRef killBinding(Store ST, Loc L) override;
|
||||
|
||||
void incrementReferenceCount(Store store) override {
|
||||
getRegionBindings(store).manualRetain();
|
||||
getRegionBindings(store).manualRetain();
|
||||
}
|
||||
|
||||
|
||||
/// If the StoreManager supports it, decrement the reference count of
|
||||
/// the specified Store object. If the reference count hits 0, the memory
|
||||
/// associated with the object is recycled.
|
||||
|
@ -508,7 +508,7 @@ public: // Part of public interface to class.
|
|||
SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
|
||||
const TypedValueRegion *R,
|
||||
QualType Ty);
|
||||
|
||||
|
||||
SVal getLazyBinding(const SubRegion *LazyBindingRegion,
|
||||
RegionBindingsRef LazyBinding);
|
||||
|
||||
|
@ -987,8 +987,8 @@ void invalidateRegionsWorker::VisitBinding(SVal V) {
|
|||
void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
|
||||
const ClusterBindings *C) {
|
||||
|
||||
bool PreserveRegionsContents =
|
||||
ITraits.hasTrait(baseR,
|
||||
bool PreserveRegionsContents =
|
||||
ITraits.hasTrait(baseR,
|
||||
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
|
||||
|
||||
if (C) {
|
||||
|
@ -1456,7 +1456,7 @@ RegionStoreManager::findLazyBinding(RegionBindingsConstRef B,
|
|||
// through to look for lazy compound value. It is like a field region.
|
||||
Result = findLazyBinding(B, cast<SubRegion>(BaseReg->getSuperRegion()),
|
||||
originalRegion);
|
||||
|
||||
|
||||
if (Result.second)
|
||||
Result.second = MRMgr.getCXXBaseObjectRegionWithSuper(BaseReg,
|
||||
Result.second);
|
||||
|
@ -1502,7 +1502,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
|
|||
return svalBuilder.makeIntVal(c, T);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check for loads from a code text region. For such loads, just give up.
|
||||
if (isa<CodeTextRegion>(superR))
|
||||
return UnknownVal();
|
||||
|
@ -1514,12 +1514,12 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
|
|||
// return *y;
|
||||
// FIXME: This is a hack, and doesn't do anything really intelligent yet.
|
||||
const RegionRawOffset &O = R->getAsArrayOffset();
|
||||
|
||||
|
||||
// If we cannot reason about the offset, return an unknown value.
|
||||
if (!O.getRegion())
|
||||
return UnknownVal();
|
||||
|
||||
if (const TypedValueRegion *baseR =
|
||||
|
||||
if (const TypedValueRegion *baseR =
|
||||
dyn_cast_or_null<TypedValueRegion>(O.getRegion())) {
|
||||
QualType baseT = baseR->getValueType();
|
||||
if (baseT->isScalarType()) {
|
||||
|
@ -1610,7 +1610,7 @@ SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion,
|
|||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
SVal
|
||||
RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
|
||||
const TypedValueRegion *R,
|
||||
|
@ -1664,7 +1664,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
|
|||
if (!index.isConstant())
|
||||
hasSymbolicIndex = true;
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
SR = dyn_cast<SubRegion>(Base);
|
||||
|
@ -1674,7 +1674,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
|
|||
if (isa<ElementRegion>(R)) {
|
||||
// Currently we don't reason specially about Clang-style vectors. Check
|
||||
// if superR is a vector and if so return Unknown.
|
||||
if (const TypedValueRegion *typedSuperR =
|
||||
if (const TypedValueRegion *typedSuperR =
|
||||
dyn_cast<TypedValueRegion>(R->getSuperRegion())) {
|
||||
if (typedSuperR->getValueType()->isVectorType())
|
||||
return UnknownVal();
|
||||
|
@ -1801,7 +1801,7 @@ RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
|
|||
List.insert(List.end(), InnerList.begin(), InnerList.end());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
List.push_back(V);
|
||||
}
|
||||
|
||||
|
@ -1838,7 +1838,7 @@ SVal RegionStoreManager::getBindingForArray(RegionBindingsConstRef B,
|
|||
const TypedValueRegion *R) {
|
||||
assert(Ctx.getAsConstantArrayType(R->getValueType()) &&
|
||||
"Only constant array types can have compound bindings.");
|
||||
|
||||
|
||||
return createLazyBinding(B, R);
|
||||
}
|
||||
|
||||
|
@ -2012,11 +2012,11 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
|
|||
QualType T = R->getValueType();
|
||||
assert(T->isVectorType());
|
||||
const VectorType *VT = T->getAs<VectorType>(); // Use getAs for typedefs.
|
||||
|
||||
|
||||
// Handle lazy compound values and symbolic values.
|
||||
if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
|
||||
return bindAggregate(B, R, V);
|
||||
|
||||
|
||||
// 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
|
||||
// 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) {
|
||||
if (VI == VE)
|
||||
break;
|
||||
|
||||
|
||||
NonLoc Idx = svalBuilder.makeArrayIndex(index);
|
||||
const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx);
|
||||
|
||||
|
@ -2075,7 +2075,7 @@ RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B,
|
|||
}
|
||||
|
||||
RegionBindingsRef NewB = B;
|
||||
|
||||
|
||||
for (FieldVector::iterator I = Fields.begin(), E = Fields.end(); I != E; ++I){
|
||||
const FieldRegion *SourceFR = MRMgr.getFieldRegion(*I, LCV.getRegion());
|
||||
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 (const MemRegion *R = V.getAsRegion()) {
|
||||
AddToWorkList(R);
|
||||
|
||||
|
||||
// All regions captured by a block are also live.
|
||||
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
|
||||
BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(),
|
||||
|
@ -2268,7 +2268,7 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) {
|
|||
AddToWorkList(I.getCapturedRegion());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Update the set of live symbols.
|
||||
for (SymExpr::symbol_iterator SI = V.symbol_begin(), SE = V.symbol_end();
|
||||
|
|
|
@ -91,7 +91,7 @@ nonloc::ConcreteInt SValBuilder::makeBoolVal(const CXXBoolLiteralExpr *boolean){
|
|||
return makeTruthVal(boolean->getValue());
|
||||
}
|
||||
|
||||
DefinedOrUnknownSVal
|
||||
DefinedOrUnknownSVal
|
||||
SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) {
|
||||
QualType T = region->getValueType();
|
||||
|
||||
|
@ -146,10 +146,10 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
|
|||
return UnknownVal();
|
||||
|
||||
SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount);
|
||||
|
||||
|
||||
if (Loc::isLocType(type))
|
||||
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
|
||||
|
||||
|
||||
return nonloc::SymbolVal(sym);
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ SVal SValBuilder::makeSymExprValNN(ProgramStateRef State,
|
|||
QualType ResultTy) {
|
||||
if (!State->isTainted(RHS) && !State->isTainted(LHS))
|
||||
return UnknownVal();
|
||||
|
||||
|
||||
const SymExpr *symLHS = LHS.getAsSymExpr();
|
||||
const SymExpr *symRHS = RHS.getAsSymExpr();
|
||||
// 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),
|
||||
Context.getPointerType(originalTy)))
|
||||
return val;
|
||||
|
||||
|
||||
// Check for casts from pointers to integers.
|
||||
if (castTy->isIntegralOrEnumerationType() && Loc::isLocType(originalTy))
|
||||
return evalCastFromLoc(val.castAs<Loc>(), castTy);
|
||||
|
|
|
@ -638,7 +638,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
|
|||
// on the ABI).
|
||||
// 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?
|
||||
return UnknownVal();
|
||||
return UnknownVal();
|
||||
|
||||
case loc::ConcreteIntKind: {
|
||||
// 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.
|
||||
if (rhs.isZeroConstant())
|
||||
return lhs;
|
||||
|
||||
|
||||
// We are dealing with pointer arithmetic.
|
||||
|
||||
// Handle pointer arithmetic on constant values.
|
||||
|
@ -880,7 +880,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
|
|||
// Offset the increment by the pointer size.
|
||||
llvm::APSInt Multiplicand(rightI.getBitWidth(), /* isUnsigned */ true);
|
||||
rightI *= Multiplicand;
|
||||
|
||||
|
||||
// Compute the adjusted pointer.
|
||||
switch (op) {
|
||||
case BO_Add:
|
||||
|
@ -922,7 +922,7 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
|
|||
superR, getContext()));
|
||||
}
|
||||
}
|
||||
return UnknownVal();
|
||||
return UnknownVal();
|
||||
}
|
||||
|
||||
const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
|
||||
|
|
|
@ -52,7 +52,7 @@ StoreRef StoreManager::BindDefault(Store store, const MemRegion *R, SVal V) {
|
|||
return StoreRef(store, *this);
|
||||
}
|
||||
|
||||
const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R,
|
||||
const ElementRegion *StoreManager::GetElementZeroRegion(const MemRegion *R,
|
||||
QualType T) {
|
||||
NonLoc idx = svalBuilder.makeZeroArrayIndex();
|
||||
assert(!T.isNull());
|
||||
|
@ -366,22 +366,22 @@ SVal StoreManager::evalDynamicCast(SVal Base, QualType TargetType,
|
|||
/// as another region.
|
||||
SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R,
|
||||
QualType castTy, bool performTestOnly) {
|
||||
|
||||
|
||||
if (castTy.isNull() || V.isUnknownOrUndef())
|
||||
return V;
|
||||
|
||||
|
||||
ASTContext &Ctx = svalBuilder.getContext();
|
||||
|
||||
if (performTestOnly) {
|
||||
if (performTestOnly) {
|
||||
// Automatically translate references to pointers.
|
||||
QualType T = R->getValueType();
|
||||
if (const ReferenceType *RT = T->getAs<ReferenceType>())
|
||||
T = Ctx.getPointerType(RT->getPointeeType());
|
||||
|
||||
|
||||
assert(svalBuilder.getContext().hasSameUnqualifiedType(castTy, T));
|
||||
return V;
|
||||
}
|
||||
|
||||
|
||||
return svalBuilder.dispatchCast(V, castTy);
|
||||
}
|
||||
|
||||
|
@ -424,7 +424,7 @@ SVal StoreManager::getLValueIvar(const ObjCIvarDecl *decl, SVal base) {
|
|||
return getLValueFieldOrIvar(decl, base);
|
||||
}
|
||||
|
||||
SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
|
||||
SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
|
||||
SVal Base) {
|
||||
|
||||
// If the base is an unknown or undefined value, just return it back.
|
||||
|
|
|
@ -409,7 +409,7 @@ bool SymbolReaper::maybeDead(SymbolRef sym) {
|
|||
bool SymbolReaper::isLiveRegion(const MemRegion *MR) {
|
||||
if (RegionRoots.count(MR))
|
||||
return true;
|
||||
|
||||
|
||||
MR = MR->getBaseRegion();
|
||||
|
||||
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
|
||||
|
@ -442,9 +442,9 @@ bool SymbolReaper::isLive(SymbolRef sym) {
|
|||
markDependentsLive(sym);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool KnownLive;
|
||||
|
||||
|
||||
switch (sym->getKind()) {
|
||||
case SymExpr::RegionValueKind:
|
||||
KnownLive = isLiveRegion(cast<SymbolRegionValue>(sym)->getRegion());
|
||||
|
@ -525,7 +525,7 @@ bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{
|
|||
|
||||
if (!includeStoreBindings)
|
||||
return false;
|
||||
|
||||
|
||||
unsigned &cachedQuery =
|
||||
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.
|
||||
if (Store store = reapedStore.getStore()) {
|
||||
bool hasRegion =
|
||||
bool hasRegion =
|
||||
reapedStore.getStoreManager().includedInBindings(store, VR);
|
||||
cachedQuery = hasRegion ? 1 : 2;
|
||||
return hasRegion;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ public:
|
|||
/// The local declaration to all declarations ratio might be very small when
|
||||
/// working with a PCH file.
|
||||
SetOfDecls LocalTUDecls;
|
||||
|
||||
|
||||
// Set of PathDiagnosticConsumers. Owned by AnalysisManager.
|
||||
PathDiagnosticConsumers PathConsumers;
|
||||
|
||||
|
@ -364,7 +364,7 @@ public:
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool VisitBlockDecl(BlockDecl *BD) {
|
||||
if (BD->hasBody()) {
|
||||
assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);
|
||||
|
@ -475,7 +475,7 @@ void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {
|
|||
|
||||
CallGraphNode *N = *I;
|
||||
Decl *D = N->getDecl();
|
||||
|
||||
|
||||
// Skip the abstract root node.
|
||||
if (!D)
|
||||
continue;
|
||||
|
@ -679,11 +679,11 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,
|
|||
case LangOptions::NonGC:
|
||||
ActionExprEngine(D, false, IMode, Visited);
|
||||
break;
|
||||
|
||||
|
||||
case LangOptions::GCOnly:
|
||||
ActionExprEngine(D, true, IMode, Visited);
|
||||
break;
|
||||
|
||||
|
||||
case LangOptions::HybridGC:
|
||||
ActionExprEngine(D, false, IMode, Visited);
|
||||
ActionExprEngine(D, true, IMode, Visited);
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
ClangCheckerRegistry(ArrayRef<std::string> plugins,
|
||||
DiagnosticsEngine *diags = nullptr);
|
||||
};
|
||||
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
ClangCheckerRegistry::ClangCheckerRegistry(ArrayRef<std::string> plugins,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
##===- clang/lib/StaticAnalyzer/Frontend/Makefile ----------*- Makefile -*-===##
|
||||
#
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
#
|
||||
# Starting point into the static analyzer land for the driver.
|
||||
|
|
|
@ -282,7 +282,7 @@ sub Analyze {
|
|||
# We save the output file in the 'crashes' directory if clang encounters
|
||||
# any problems with the file.
|
||||
my ($ofh, $ofile) = tempfile("clang_output_XXXXXX", DIR => $HtmlDir);
|
||||
|
||||
|
||||
my $OutputStream = silent_system($HtmlDir, $Cmd, @CmdArgs);
|
||||
while ( <$OutputStream> ) {
|
||||
print $ofh $_;
|
||||
|
|
|
@ -1400,7 +1400,7 @@ my $ForceDisplayHelp = 0;
|
|||
|
||||
sub ProcessArgs {
|
||||
my $Args = shift;
|
||||
|
||||
|
||||
while (@$Args) {
|
||||
|
||||
# Scan for options we recognize.
|
||||
|
|
|
@ -5,7 +5,7 @@ CmpRuns - A simple tool for comparing two static analyzer runs to determine
|
|||
which reports have been added, removed, or changed.
|
||||
|
||||
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
|
||||
regression testing.
|
||||
|
||||
|
@ -19,11 +19,11 @@ Usage:
|
|||
#
|
||||
resultsA = loadResultsFromSingleRun(singleRunInfoA, deleteEmpty)
|
||||
resultsB = loadResultsFromSingleRun(singleRunInfoB, deleteEmpty)
|
||||
|
||||
# Generate a relation from diagnostics in run A to diagnostics in run B
|
||||
# to obtain a list of triples (a, b, confidence).
|
||||
|
||||
# Generate a relation from diagnostics in run A to diagnostics in run B
|
||||
# to obtain a list of triples (a, b, confidence).
|
||||
diff = compareResults(resultsA, resultsB)
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
|
@ -32,7 +32,7 @@ import CmpRuns
|
|||
|
||||
# Information about analysis run:
|
||||
# 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
|
||||
class SingleRunInfo:
|
||||
def __init__(self, path, root="", verboseLog=None):
|
||||
|
@ -56,7 +56,7 @@ class AnalysisDiagnostic:
|
|||
|
||||
def getLine(self):
|
||||
return self._loc['line']
|
||||
|
||||
|
||||
def getColumn(self):
|
||||
return self._loc['col']
|
||||
|
||||
|
@ -80,12 +80,12 @@ class AnalysisDiagnostic:
|
|||
return os.path.join(self._report.run.path, self._htmlReport)
|
||||
|
||||
def getReadableName(self):
|
||||
return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(),
|
||||
self.getColumn(), self.getCategory(),
|
||||
return '%s:%d:%d, %s: %s' % (self.getFileName(), self.getLine(),
|
||||
self.getColumn(), self.getCategory(),
|
||||
self.getDescription())
|
||||
|
||||
# Note, the data format is not an API and may change from one analyzer
|
||||
# version to another.
|
||||
|
||||
# Note, the data format is not an API and may change from one analyzer
|
||||
# version to another.
|
||||
def getRawData(self):
|
||||
return self._data
|
||||
|
||||
|
@ -94,7 +94,7 @@ class multidict:
|
|||
self.data = {}
|
||||
for key,value in elts:
|
||||
self[key] = value
|
||||
|
||||
|
||||
def __getitem__(self, item):
|
||||
return self.data[item]
|
||||
def __setitem__(self, key, value):
|
||||
|
@ -134,15 +134,15 @@ class AnalysisRun:
|
|||
# Cumulative list of all diagnostics from all the reports.
|
||||
self.diagnostics = []
|
||||
self.clang_version = None
|
||||
|
||||
|
||||
def getClangVersion(self):
|
||||
return self.clang_version
|
||||
|
||||
def readSingleFile(self, p, deleteEmpty):
|
||||
data = plistlib.readPlist(p)
|
||||
|
||||
# We want to retrieve the clang version even if there are no
|
||||
# reports. Assume that all reports were created using the same
|
||||
# We want to retrieve the clang version even if there are no
|
||||
# reports. Assume that all reports were created using the same
|
||||
# clang version (this is always true and is more efficient).
|
||||
if 'clang_version' in data:
|
||||
if self.clang_version == None:
|
||||
|
@ -166,9 +166,9 @@ class AnalysisRun:
|
|||
htmlFiles.append(d.pop('HTMLDiagnostics_files')[0])
|
||||
else:
|
||||
htmlFiles = [None] * len(data['diagnostics'])
|
||||
|
||||
|
||||
report = AnalysisReport(self, data.pop('files'))
|
||||
diagnostics = [AnalysisDiagnostic(d, report, h)
|
||||
diagnostics = [AnalysisDiagnostic(d, report, h)
|
||||
for d,h in zip(data.pop('diagnostics'),
|
||||
htmlFiles)]
|
||||
|
||||
|
@ -179,7 +179,7 @@ class AnalysisRun:
|
|||
self.diagnostics.extend(diagnostics)
|
||||
|
||||
|
||||
# Backward compatibility API.
|
||||
# Backward compatibility API.
|
||||
def loadResults(path, opts, root = "", deleteEmpty=True):
|
||||
return loadResultsFromSingleRun(SingleRunInfo(path, root, opts.verboseLog),
|
||||
deleteEmpty)
|
||||
|
@ -257,7 +257,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
|
|||
# Load the run results.
|
||||
resultsA = loadResults(dirA, opts, opts.rootA, deleteEmpty)
|
||||
resultsB = loadResults(dirB, opts, opts.rootB, deleteEmpty)
|
||||
|
||||
|
||||
# Open the verbose log, if given.
|
||||
if opts.verboseLog:
|
||||
auxLog = open(opts.verboseLog, "wb")
|
||||
|
@ -285,7 +285,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
|
|||
b.getReadableName())
|
||||
foundDiffs += 1
|
||||
if auxLog:
|
||||
print >>auxLog, ("('CHANGED', %r, %r, %r, %r)"
|
||||
print >>auxLog, ("('CHANGED', %r, %r, %r, %r)"
|
||||
% (a.getReadableName(),
|
||||
b.getReadableName(),
|
||||
a.getReport(),
|
||||
|
@ -299,7 +299,7 @@ def dumpScanBuildResultsDiff(dirA, dirB, opts, deleteEmpty=True):
|
|||
if auxLog:
|
||||
print >>auxLog, "('TOTAL NEW REPORTS', %r)" % TotalReports
|
||||
print >>auxLog, "('TOTAL DIFFERENCES', %r)" % foundDiffs
|
||||
|
||||
|
||||
return foundDiffs, len(resultsA.diagnostics), len(resultsB.diagnostics)
|
||||
|
||||
def main():
|
||||
|
@ -322,7 +322,7 @@ def main():
|
|||
|
||||
dirA,dirB = args
|
||||
|
||||
dumpScanBuildResultsDiff(dirA, dirB, opts)
|
||||
dumpScanBuildResultsDiff(dirA, dirB, opts)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
#!/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.
|
||||
|
||||
Add a new project for testing: build it and add to the Project Map file.
|
||||
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
|
||||
|
||||
|
||||
The project should use the following files for set up:
|
||||
- pre_run_static_analyzer.sh - prepare the build environment.
|
||||
Ex: make clean can be a part of it.
|
||||
- run_static_analyzer.cmd - a list of commands to run through scan-build.
|
||||
Each command should be on a separate line.
|
||||
Choose from: configure, make, xcodebuild
|
||||
Choose from: configure, make, xcodebuild
|
||||
"""
|
||||
import SATestBuild
|
||||
|
||||
|
@ -27,7 +27,7 @@ def isExistingProject(PMapFile, projectID) :
|
|||
for I in PMapReader:
|
||||
if projectID == I[0]:
|
||||
return True
|
||||
return False
|
||||
return False
|
||||
|
||||
# Add a new project for testing: build it and add to the Project Map file.
|
||||
# Params:
|
||||
|
@ -39,7 +39,7 @@ def addNewProject(ID, BuildMode) :
|
|||
if not os.path.exists(Dir):
|
||||
print "Error: Project directory is missing: %s" % Dir
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
# Build the project.
|
||||
SATestBuild.testProject(ID, BuildMode, IsReferenceBuild=True, Dir=Dir)
|
||||
|
||||
|
@ -51,19 +51,19 @@ def addNewProject(ID, BuildMode) :
|
|||
print "Warning: Creating the Project Map file!!"
|
||||
PMapFile = open(ProjectMapPath, "w+b")
|
||||
try:
|
||||
if (isExistingProject(PMapFile, ID)) :
|
||||
if (isExistingProject(PMapFile, ID)) :
|
||||
print >> sys.stdout, 'Warning: Project with ID \'', ID, \
|
||||
'\' already exists.'
|
||||
print >> sys.stdout, "Reference output has been regenerated."
|
||||
else:
|
||||
else:
|
||||
PMapWriter = csv.writer(PMapFile)
|
||||
PMapWriter.writerow( (ID, int(BuildMode)) );
|
||||
print "The project map is updated: ", ProjectMapPath
|
||||
finally:
|
||||
PMapFile.close()
|
||||
|
||||
|
||||
# TODO: Add an option not to build.
|
||||
|
||||
# TODO: Add an option not to build.
|
||||
# TODO: Set the path to the Repository directory.
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
|
@ -73,10 +73,10 @@ if __name__ == '__main__':
|
|||
'1 for scan_build; ' \
|
||||
'2 for single file c++11 project'
|
||||
sys.exit(-1)
|
||||
|
||||
BuildMode = 1
|
||||
|
||||
BuildMode = 1
|
||||
if (len(sys.argv) >= 3):
|
||||
BuildMode = int(sys.argv[2])
|
||||
BuildMode = int(sys.argv[2])
|
||||
assert((BuildMode == 0) | (BuildMode == 1) | (BuildMode == 2))
|
||||
|
||||
|
||||
addNewProject(sys.argv[1], BuildMode)
|
||||
|
|
|
@ -6,8 +6,8 @@ Static Analyzer qualification infrastructure.
|
|||
The goal is to test the analyzer against different projects, check for failures,
|
||||
compare results, and measure performance.
|
||||
|
||||
Repository Directory will contain sources of the projects as well as the
|
||||
information on how to build them and the expected output.
|
||||
Repository Directory will contain sources of the projects as well as the
|
||||
information on how to build them and the expected output.
|
||||
Repository Directory structure:
|
||||
- ProjectMap file
|
||||
- Historical Performance Data
|
||||
|
@ -19,16 +19,16 @@ Repository Directory structure:
|
|||
Note that the build tree must be inside the project dir.
|
||||
|
||||
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).
|
||||
- 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/run_static_analyzer.log
|
||||
|
||||
Assumptions (TODO: shouldn't need to assume these.):
|
||||
RepositoryCopy/Project DirI/run_static_analyzer.log
|
||||
|
||||
Assumptions (TODO: shouldn't need to assume these.):
|
||||
The script is being run from the Repository Directory.
|
||||
The compiler for scan-build and scan-build are in the 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:
|
||||
zaks:TI zaks$ export CCC_ANALYZER_LOG=1
|
||||
zaks:TI zaks$ export CCC_ANALYZER_VERBOSE=1
|
||||
|
||||
|
||||
The list of checkers tested are hardcoded in the Checkers variable.
|
||||
For testing additional checkers, use the SA_ADDITIONAL_CHECKERS environment
|
||||
variable. It should contain a comma separated list.
|
||||
|
@ -120,16 +120,16 @@ class flushfile(object):
|
|||
sys.stdout = flushfile(sys.stdout)
|
||||
|
||||
def getProjectMapPath():
|
||||
ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
|
||||
ProjectMapPath = os.path.join(os.path.abspath(os.curdir),
|
||||
ProjectMapFile)
|
||||
if not os.path.exists(ProjectMapPath):
|
||||
print "Error: Cannot find the Project Map file " + ProjectMapPath +\
|
||||
"\nRunning script for the wrong directory?"
|
||||
sys.exit(-1)
|
||||
return ProjectMapPath
|
||||
sys.exit(-1)
|
||||
return ProjectMapPath
|
||||
|
||||
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) :
|
||||
if IsReferenceBuild == True :
|
||||
|
@ -156,13 +156,13 @@ ProjectMapFile = "projectMap.csv"
|
|||
# Names of the project specific scripts.
|
||||
# The script that needs to be executed before the build can start.
|
||||
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"
|
||||
|
||||
# The log file name.
|
||||
LogFolderName = "Logs"
|
||||
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.
|
||||
NumOfFailuresInSummary = 10
|
||||
FailuresSummaryFileName = "failures.txt"
|
||||
|
@ -189,21 +189,21 @@ def runCleanupScript(Dir, PBuildLogFile):
|
|||
ScriptPath = os.path.join(Dir, CleanupScript)
|
||||
if os.path.exists(ScriptPath):
|
||||
try:
|
||||
if Verbose == 1:
|
||||
if Verbose == 1:
|
||||
print " Executing: %s" % (ScriptPath,)
|
||||
check_call("chmod +x %s" % ScriptPath, cwd = Dir,
|
||||
check_call("chmod +x %s" % ScriptPath, cwd = Dir,
|
||||
stderr=PBuildLogFile,
|
||||
stdout=PBuildLogFile,
|
||||
shell=True)
|
||||
stdout=PBuildLogFile,
|
||||
shell=True)
|
||||
check_call(ScriptPath, cwd = Dir, stderr=PBuildLogFile,
|
||||
stdout=PBuildLogFile,
|
||||
stdout=PBuildLogFile,
|
||||
shell=True)
|
||||
except:
|
||||
print "Error: The pre-processing step failed. See ", \
|
||||
PBuildLogFile.name, " for details."
|
||||
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.
|
||||
def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
|
||||
BuildScriptPath = os.path.join(Dir, BuildScript)
|
||||
|
@ -212,9 +212,9 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
|
|||
sys.exit(-1)
|
||||
SBOptions = "--use-analyzer " + Clang + " "
|
||||
SBOptions += "-plist-html -o " + SBOutputDir + " "
|
||||
SBOptions += "-enable-checker " + Checkers + " "
|
||||
SBOptions += "-enable-checker " + Checkers + " "
|
||||
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.
|
||||
SBOptions += "--override-compiler "
|
||||
try:
|
||||
|
@ -231,10 +231,10 @@ def runScanBuild(Dir, SBOutputDir, PBuildLogFile):
|
|||
"-j" not in Command:
|
||||
Command += " -j%d" % Jobs
|
||||
SBCommand = SBPrefix + Command
|
||||
if Verbose == 1:
|
||||
if Verbose == 1:
|
||||
print " Executing: %s" % (SBCommand,)
|
||||
check_call(SBCommand, cwd = Dir, stderr=PBuildLogFile,
|
||||
stdout=PBuildLogFile,
|
||||
stdout=PBuildLogFile,
|
||||
shell=True)
|
||||
except:
|
||||
print "Error: scan-build failed. See ",PBuildLogFile.name,\
|
||||
|
@ -249,97 +249,97 @@ def hasNoExtension(FileName):
|
|||
|
||||
def isValidSingleInputFile(FileName):
|
||||
(Root, Ext) = os.path.splitext(FileName)
|
||||
if ((Ext == ".i") | (Ext == ".ii") |
|
||||
(Ext == ".c") | (Ext == ".cpp") |
|
||||
if ((Ext == ".i") | (Ext == ".ii") |
|
||||
(Ext == ".c") | (Ext == ".cpp") |
|
||||
(Ext == ".m") | (Ext == "")) :
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# Run analysis on a set of preprocessed files.
|
||||
def runAnalyzePreprocessed(Dir, SBOutputDir, Mode):
|
||||
if os.path.exists(os.path.join(Dir, BuildScript)):
|
||||
print "Error: The preprocessed files project should not contain %s" % \
|
||||
BuildScript
|
||||
raise Exception()
|
||||
raise Exception()
|
||||
|
||||
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) :
|
||||
CmdPrefix += "-std=c++11 "
|
||||
|
||||
CmdPrefix += "-std=c++11 "
|
||||
|
||||
PlistPath = os.path.join(Dir, SBOutputDir, "date")
|
||||
FailPath = os.path.join(PlistPath, "failures");
|
||||
os.makedirs(FailPath);
|
||||
|
||||
|
||||
for FullFileName in glob.glob(Dir + "/*"):
|
||||
FileName = os.path.basename(FullFileName)
|
||||
Failed = False
|
||||
|
||||
|
||||
# Only run the analyzes on supported files.
|
||||
if (hasNoExtension(FileName)):
|
||||
continue
|
||||
if (isValidSingleInputFile(FileName) == False):
|
||||
print "Error: Invalid single input file %s." % (FullFileName,)
|
||||
raise Exception()
|
||||
|
||||
|
||||
# Build and call the analyzer command.
|
||||
OutputOption = "-o " + os.path.join(PlistPath, FileName) + ".plist "
|
||||
Command = CmdPrefix + OutputOption + FileName
|
||||
LogFile = open(os.path.join(FailPath, FileName + ".stderr.txt"), "w+b")
|
||||
try:
|
||||
if Verbose == 1:
|
||||
if Verbose == 1:
|
||||
print " Executing: %s" % (Command,)
|
||||
check_call(Command, cwd = Dir, stderr=LogFile,
|
||||
stdout=LogFile,
|
||||
stdout=LogFile,
|
||||
shell=True)
|
||||
except CalledProcessError, e:
|
||||
print "Error: Analyzes of %s failed. See %s for details." \
|
||||
"Error code %d." % \
|
||||
(FullFileName, LogFile.name, e.returncode)
|
||||
Failed = True
|
||||
Failed = True
|
||||
finally:
|
||||
LogFile.close()
|
||||
|
||||
LogFile.close()
|
||||
|
||||
# If command did not fail, erase the log file.
|
||||
if Failed == False:
|
||||
os.remove(LogFile.name);
|
||||
|
||||
def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
|
||||
TBegin = time.time()
|
||||
TBegin = time.time()
|
||||
|
||||
BuildLogPath = os.path.join(SBOutputDir, LogFolderName, BuildLogName)
|
||||
print "Log file: %s" % (BuildLogPath,)
|
||||
print "Log file: %s" % (BuildLogPath,)
|
||||
print "Output directory: %s" %(SBOutputDir, )
|
||||
|
||||
|
||||
# Clean up the log file.
|
||||
if (os.path.exists(BuildLogPath)) :
|
||||
RmCommand = "rm " + BuildLogPath
|
||||
if Verbose == 1:
|
||||
print " Executing: %s" % (RmCommand,)
|
||||
check_call(RmCommand, shell=True)
|
||||
|
||||
|
||||
# Clean up scan build results.
|
||||
if (os.path.exists(SBOutputDir)) :
|
||||
RmCommand = "rm -r " + SBOutputDir
|
||||
if Verbose == 1:
|
||||
if Verbose == 1:
|
||||
print " Executing: %s" % (RmCommand,)
|
||||
check_call(RmCommand, shell=True)
|
||||
assert(not os.path.exists(SBOutputDir))
|
||||
os.makedirs(os.path.join(SBOutputDir, LogFolderName))
|
||||
|
||||
|
||||
# Open the log file.
|
||||
PBuildLogFile = open(BuildLogPath, "wb+")
|
||||
|
||||
|
||||
# Build and analyze the project.
|
||||
try:
|
||||
runCleanupScript(Dir, PBuildLogFile)
|
||||
|
||||
|
||||
if (ProjectBuildMode == 1):
|
||||
runScanBuild(Dir, SBOutputDir, PBuildLogFile)
|
||||
else:
|
||||
runAnalyzePreprocessed(Dir, SBOutputDir, ProjectBuildMode)
|
||||
|
||||
|
||||
if IsReferenceBuild :
|
||||
runCleanupScript(Dir, PBuildLogFile)
|
||||
|
||||
|
@ -354,28 +354,28 @@ def buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild):
|
|||
else SourceFile for SourceFile in Data['files']]
|
||||
Data['files'] = Paths
|
||||
plistlib.writePlist(Data, Plist)
|
||||
|
||||
|
||||
finally:
|
||||
PBuildLogFile.close()
|
||||
|
||||
|
||||
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).
|
||||
# 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):
|
||||
for F in glob.glob(SBOutputDir + "/*/*.plist"):
|
||||
P = os.path.join(SBOutputDir, F)
|
||||
|
||||
|
||||
Data = plistlib.readPlist(P)
|
||||
# Delete empty reports.
|
||||
if not Data['files']:
|
||||
os.remove(P)
|
||||
continue
|
||||
|
||||
# Given the scan-build output directory, checks if the build failed
|
||||
# (by searching for the failures directories). If there are failures, it
|
||||
# creates a summary file in the output directory.
|
||||
# Given the scan-build output directory, checks if the build failed
|
||||
# (by searching for the failures directories). If there are failures, it
|
||||
# creates a summary file in the output directory.
|
||||
def checkBuild(SBOutputDir):
|
||||
# Check if there are failures.
|
||||
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" %\
|
||||
len(Plists)
|
||||
return;
|
||||
|
||||
|
||||
# Create summary file to display when the build fails.
|
||||
SummaryPath = os.path.join(SBOutputDir, LogFolderName, FailuresSummaryFileName)
|
||||
if (Verbose > 0):
|
||||
print " Creating the failures summary file %s" % (SummaryPath,)
|
||||
|
||||
|
||||
SummaryLog = open(SummaryPath, "w+")
|
||||
try:
|
||||
SummaryLog.write("Total of %d failures discovered.\n" % (TotalFailed,))
|
||||
if TotalFailed > NumOfFailuresInSummary:
|
||||
SummaryLog.write("See the first %d below.\n"
|
||||
SummaryLog.write("See the first %d below.\n"
|
||||
% (NumOfFailuresInSummary,))
|
||||
# TODO: Add a line "See the results folder for more."
|
||||
|
||||
|
||||
FailuresCopied = NumOfFailuresInSummary
|
||||
Idx = 0
|
||||
for FailLogPathI in Failures:
|
||||
if Idx >= NumOfFailuresInSummary:
|
||||
break;
|
||||
Idx += 1
|
||||
Idx += 1
|
||||
SummaryLog.write("\n-- Error #%d -----------\n" % (Idx,));
|
||||
FailLogI = open(FailLogPathI, "r");
|
||||
try:
|
||||
try:
|
||||
shutil.copyfileobj(FailLogI, SummaryLog);
|
||||
finally:
|
||||
FailLogI.close()
|
||||
finally:
|
||||
SummaryLog.close()
|
||||
|
||||
|
||||
print "Error: analysis failed. See ", SummaryPath
|
||||
sys.exit(-1)
|
||||
sys.exit(-1)
|
||||
|
||||
# Auxiliary object to discard stdout.
|
||||
class Discarder(object):
|
||||
|
@ -428,44 +428,44 @@ class Discarder(object):
|
|||
# 0 - success if there are no crashes or analyzer failure.
|
||||
# 1 - success if there are no difference in the number of reported bugs.
|
||||
# 2 - success if all the bug reports are identical.
|
||||
def runCmpResults(Dir, Strictness = 0):
|
||||
TBegin = time.time()
|
||||
def runCmpResults(Dir, Strictness = 0):
|
||||
TBegin = time.time()
|
||||
|
||||
RefDir = os.path.join(Dir, SBOutputDirReferencePrefix + SBOutputDirName)
|
||||
NewDir = os.path.join(Dir, SBOutputDirName)
|
||||
|
||||
|
||||
# We have to go one level down the directory tree.
|
||||
RefList = glob.glob(RefDir + "/*")
|
||||
RefList = glob.glob(RefDir + "/*")
|
||||
NewList = glob.glob(NewDir + "/*")
|
||||
|
||||
|
||||
# Log folders are also located in the results dir, so ignore them.
|
||||
RefLogDir = os.path.join(RefDir, LogFolderName)
|
||||
if RefLogDir in RefList:
|
||||
RefList.remove(RefLogDir)
|
||||
NewList.remove(os.path.join(NewDir, LogFolderName))
|
||||
|
||||
|
||||
if len(RefList) == 0 or len(NewList) == 0:
|
||||
return False
|
||||
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).
|
||||
if (len(RefList) > 1):
|
||||
# Assume that the corresponding folders have the same names.
|
||||
RefList.sort()
|
||||
NewList.sort()
|
||||
|
||||
|
||||
# Iterate and find the differences.
|
||||
NumDiffs = 0
|
||||
PairList = zip(RefList, NewList)
|
||||
for P in PairList:
|
||||
RefDir = P[0]
|
||||
PairList = zip(RefList, NewList)
|
||||
for P in PairList:
|
||||
RefDir = P[0]
|
||||
NewDir = P[1]
|
||||
|
||||
assert(RefDir != NewDir)
|
||||
if Verbose == 1:
|
||||
|
||||
assert(RefDir != NewDir)
|
||||
if Verbose == 1:
|
||||
print " Comparing Results: %s %s" % (RefDir, NewDir)
|
||||
|
||||
|
||||
DiffsPath = os.path.join(NewDir, DiffsSummaryFileName)
|
||||
Opts = CmpRuns.CmpOptions(DiffsPath, "", Dir)
|
||||
# Discard everything coming out of stdout (CmpRun produces a lot of them).
|
||||
|
@ -480,70 +480,70 @@ def runCmpResults(Dir, Strictness = 0):
|
|||
(NumDiffs, DiffsPath,)
|
||||
if Strictness >= 2 and NumDiffs > 0:
|
||||
print "Error: Diffs found in strict mode (2)."
|
||||
sys.exit(-1)
|
||||
sys.exit(-1)
|
||||
elif Strictness >= 1 and ReportsInRef != ReportsInNew:
|
||||
print "Error: The number of results are different in strict mode (1)."
|
||||
sys.exit(-1)
|
||||
|
||||
print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
|
||||
sys.exit(-1)
|
||||
|
||||
print "Diagnostic comparison complete (time: %.2f)." % (time.time()-TBegin)
|
||||
return (NumDiffs > 0)
|
||||
|
||||
|
||||
def updateSVN(Mode, ProjectsMap):
|
||||
try:
|
||||
ProjectsMap.seek(0)
|
||||
ProjectsMap.seek(0)
|
||||
for I in csv.reader(ProjectsMap):
|
||||
ProjName = I[0]
|
||||
ProjName = I[0]
|
||||
Path = os.path.join(ProjName, getSBOutputDirName(True))
|
||||
|
||||
|
||||
if Mode == "delete":
|
||||
Command = "svn delete %s" % (Path,)
|
||||
else:
|
||||
Command = "svn add %s" % (Path,)
|
||||
|
||||
if Verbose == 1:
|
||||
if Verbose == 1:
|
||||
print " Executing: %s" % (Command,)
|
||||
check_call(Command, shell=True)
|
||||
|
||||
check_call(Command, shell=True)
|
||||
|
||||
if Mode == "delete":
|
||||
CommitCommand = "svn commit -m \"[analyzer tests] Remove " \
|
||||
"reference results.\""
|
||||
"reference results.\""
|
||||
else:
|
||||
CommitCommand = "svn commit -m \"[analyzer tests] Add new " \
|
||||
"reference results.\""
|
||||
if Verbose == 1:
|
||||
if Verbose == 1:
|
||||
print " Executing: %s" % (CommitCommand,)
|
||||
check_call(CommitCommand, shell=True)
|
||||
check_call(CommitCommand, shell=True)
|
||||
except:
|
||||
print "Error: SVN update failed."
|
||||
sys.exit(-1)
|
||||
|
||||
|
||||
def testProject(ID, ProjectBuildMode, IsReferenceBuild=False, Dir=None, Strictness = 0):
|
||||
print " \n\n--- Building project %s" % (ID,)
|
||||
|
||||
TBegin = time.time()
|
||||
TBegin = time.time()
|
||||
|
||||
if Dir is None :
|
||||
Dir = getProjectDir(ID)
|
||||
if Verbose == 1:
|
||||
Dir = getProjectDir(ID)
|
||||
if Verbose == 1:
|
||||
print " Build directory: %s." % (Dir,)
|
||||
|
||||
|
||||
# Set the build results directory.
|
||||
RelOutputDir = getSBOutputDirName(IsReferenceBuild)
|
||||
SBOutputDir = os.path.join(Dir, RelOutputDir)
|
||||
|
||||
|
||||
buildProject(Dir, SBOutputDir, ProjectBuildMode, IsReferenceBuild)
|
||||
|
||||
checkBuild(SBOutputDir)
|
||||
|
||||
|
||||
if IsReferenceBuild == False:
|
||||
runCmpResults(Dir, Strictness)
|
||||
|
||||
|
||||
print "Completed tests for project %s (time: %.2f)." % \
|
||||
(ID, (time.time()-TBegin))
|
||||
|
||||
|
||||
def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
|
||||
PMapFile = open(getProjectMapPath(), "rb")
|
||||
try:
|
||||
try:
|
||||
# Validate the input.
|
||||
for I in csv.reader(PMapFile):
|
||||
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"))):
|
||||
print "Error: Second entry in the ProjectMapFile should be 0" \
|
||||
" (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.
|
||||
if UpdateSVN == True:
|
||||
assert(IsReferenceBuild == True);
|
||||
updateSVN("delete", PMapFile);
|
||||
|
||||
|
||||
# Test the projects.
|
||||
PMapFile.seek(0)
|
||||
PMapFile.seek(0)
|
||||
for I in csv.reader(PMapFile):
|
||||
testProject(I[0], int(I[1]), IsReferenceBuild, None, Strictness)
|
||||
|
||||
|
@ -571,10 +571,10 @@ def testAll(IsReferenceBuild = False, UpdateSVN = False, Strictness = 0):
|
|||
|
||||
except:
|
||||
print "Error occurred. Premature termination."
|
||||
raise
|
||||
raise
|
||||
finally:
|
||||
PMapFile.close()
|
||||
|
||||
PMapFile.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Parse command line arguments.
|
||||
Parser = argparse.ArgumentParser(description='Test the Clang Static Analyzer.')
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"""
|
||||
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).
|
||||
|
||||
"""
|
||||
|
@ -69,7 +69,7 @@ if __name__ == '__main__':
|
|||
if ((") Total" in line) and (Mode == 1)) :
|
||||
s = line.split()
|
||||
TotalTime = TotalTime + float(s[6])
|
||||
|
||||
|
||||
print "TU Count %d" % (Count)
|
||||
print "Time %f" % (Time)
|
||||
print "Warnings %d" % (Warnings)
|
||||
|
@ -81,4 +81,3 @@ if __name__ == '__main__':
|
|||
print "MaxTime %f" % (MaxTime)
|
||||
print "TotalTime %f" % (TotalTime)
|
||||
print "Max CFG Size %d" % (MaxCFGSize)
|
||||
|
|
@ -18,7 +18,7 @@ import sys
|
|||
def Error(message):
|
||||
print >> sys.stderr, 'ubiviz: ' + message
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def StreamData(filename):
|
||||
file = open(filename)
|
||||
for ln in file:
|
||||
|
@ -55,20 +55,19 @@ def Display(G, data):
|
|||
|
||||
def main(args):
|
||||
if len(args) == 0:
|
||||
Error('no input files')
|
||||
Error('no input files')
|
||||
|
||||
server = xmlrpclib.Server('http://127.0.0.1:20738/RPC2')
|
||||
G = server.ubigraph
|
||||
|
||||
|
||||
for arg in args:
|
||||
G.clear()
|
||||
for x in StreamData(arg):
|
||||
Display(G,x)
|
||||
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[1:])
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue