Teach IdempotentOperationsChecker about paths aborted because ExprEngine didn't know how to handle a specific Expr type.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@128761 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ted Kremenek 2011-04-02 02:56:23 +00:00
Родитель 66750fa464
Коммит 422ab7a49a
6 изменённых файлов: 67 добавлений и 17 удалений

Просмотреть файл

@ -48,6 +48,10 @@ class CoreEngine {
public:
typedef std::vector<std::pair<BlockEdge, const ExplodedNode*> >
BlocksExhausted;
typedef std::vector<std::pair<const CFGBlock*, const ExplodedNode*> >
BlocksAborted;
private:
SubEngine& SubEng;
@ -68,6 +72,10 @@ private:
/// The locations where we stopped doing work because we visited a location
/// too many times.
BlocksExhausted blocksExhausted;
/// The locations where we stopped because the engine aborted analysis,
/// usually because it could not reason about something.
BlocksAborted blocksAborted;
void generateNode(const ProgramPoint& Loc, const GRState* State,
ExplodedNode* Pred);
@ -122,17 +130,32 @@ public:
ExplodedNodeSet &Dst);
// Functions for external checking of whether we have unfinished work
bool wasBlockAborted() const { return !blocksExhausted.empty(); }
bool hasWorkRemaining() const { return wasBlockAborted() || WList->hasWork(); }
bool wasBlockAborted() const { return !blocksAborted.empty(); }
bool wasBlocksExhausted() const { return !blocksExhausted.empty(); }
bool hasWorkRemaining() const { return wasBlocksExhausted() ||
WList->hasWork() ||
wasBlockAborted(); }
/// Inform the CoreEngine that a basic block was aborted because
/// it could not be completely analyzed.
void addAbortedBlock(const ExplodedNode *node, const CFGBlock *block) {
blocksAborted.push_back(std::make_pair(block, node));
}
WorkList *getWorkList() const { return WList; }
BlocksExhausted::const_iterator blocks_aborted_begin() const {
BlocksExhausted::const_iterator blocks_exhausted_begin() const {
return blocksExhausted.begin();
}
BlocksExhausted::const_iterator blocks_aborted_end() const {
BlocksExhausted::const_iterator blocks_exhausted_end() const {
return blocksExhausted.end();
}
BlocksAborted::const_iterator blocks_aborted_begin() const {
return blocksAborted.begin();
}
BlocksAborted::const_iterator blocks_aborted_end() const {
return blocksAborted.end();
}
};
class StmtNodeBuilder {

Просмотреть файл

@ -213,11 +213,9 @@ public:
const SymbolManager& getSymbolManager() const { return SymMgr; }
// Functions for external checking of whether we have unfinished work
bool wasBlockAborted() const { return Engine.wasBlockAborted(); }
bool wasBlocksExhausted() const { return Engine.wasBlocksExhausted(); }
bool hasEmptyWorkList() const { return !Engine.getWorkList()->hasWork(); }
bool hasWorkRemaining() const {
return wasBlockAborted() || Engine.getWorkList()->hasWork();
}
bool hasWorkRemaining() const { return Engine.hasWorkRemaining(); }
const CoreEngine &getCoreEngine() const { return Engine; }

Просмотреть файл

@ -88,8 +88,8 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
}
output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: "
<< unreachable << " | Aborted Block: "
<< (Eng.wasBlockAborted() ? "yes" : "no")
<< unreachable << " | Exhausted Block: "
<< (Eng.wasBlocksExhausted() ? "yes" : "no")
<< " | Empty WorkList: "
<< (Eng.hasEmptyWorkList() ? "yes" : "no");
@ -97,10 +97,10 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
D->getLocation());
// Emit warning for each block we bailed out on
typedef CoreEngine::BlocksExhausted::const_iterator AbortedIterator;
typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
const CoreEngine &CE = Eng.getCoreEngine();
for (AbortedIterator I = CE.blocks_aborted_begin(),
E = CE.blocks_aborted_end(); I != E; ++I) {
for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
E = CE.blocks_exhausted_end(); I != E; ++I) {
const BlockEdge &BE = I->first;
const CFGBlock *Exit = BE.getDst();
const CFGElement &CE = Exit->front();

Просмотреть файл

@ -534,9 +534,9 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
CFGReverseBlockReachabilityAnalysis *CRA = AC->getCFGReachablityAnalysis();
// Test for reachability from any aborted blocks to this block
typedef CoreEngine::BlocksExhausted::const_iterator AbortedIterator;
for (AbortedIterator I = CE.blocks_aborted_begin(),
E = CE.blocks_aborted_end(); I != E; ++I) {
typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator;
for (ExhaustedIterator I = CE.blocks_exhausted_begin(),
E = CE.blocks_exhausted_end(); I != E; ++I) {
const BlockEdge &BE = I->first;
// The destination block on the BlockEdge is the first block that was not
@ -550,6 +550,15 @@ IdempotentOperationChecker::pathWasCompletelyAnalyzed(AnalysisContext *AC,
if (destBlock == CB || CRA->isReachable(destBlock, CB))
return false;
}
// Test for reachability from blocks we just gave up on.
typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
for (AbortedIterator I = CE.blocks_aborted_begin(),
E = CE.blocks_aborted_end(); I != E; ++I) {
const CFGBlock *destBlock = I->first;
if (destBlock == CB || CRA->isReachable(destBlock, CB))
return false;
}
// For the items still on the worklist, see if they are in blocks that
// can eventually reach 'CB'.

Просмотреть файл

@ -444,7 +444,8 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
{
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
Builder->BuildSinks = true;
MakeNode(Dst, S, Pred, GetState(Pred));
const ExplodedNode *node = MakeNode(Dst, S, Pred, GetState(Pred));
Engine.addAbortedBlock(node, Builder->getBlock());
break;
}

Просмотреть файл

@ -13,3 +13,22 @@ void false1() {
test(five * a); // expected-warning {{The right operand to '*' is always 0}}
b = 4;
}
// Test not flagging idempotent operations because we aborted the analysis
// of a path because of an unsupported construct.
struct RDar9219143_Foo {
~RDar9219143_Foo();
operator bool() const;
};
RDar9219143_Foo foo();
unsigned RDar9219143_bar();
void RDar9219143_test() {
unsigned i, e;
for (i = 0, e = RDar9219143_bar(); i != e; ++i)
if (foo())
break;
if (i == e) // no-warning
return;
}