[cfe-dev] [RFC][StaticAnalyzer] Fix false negative
Daniel Marjamäki via cfe-dev
cfe-dev at lists.llvm.org
Thu Nov 12 23:17:22 PST 2015
Hello!
I am investigating a false negative for this code:
void f(unsigned long a) {
char s[10];
if (a >= 20)
s[a] = 'a'; // <- array index out of bounds
}
This is how I run Clang:
$ clang -cc1 -analyze -analyzer-checker=alpha 1.c
When I set a breakpoint in ArrayBoundChecker::checkLocation() and look at ProgramState, it looks incomplete. here is the dump output:
Store (direct and default bindings), 0x0 :
Expressions:
(0x75af750,0x75569b0) s[a] : &element{s,reg_$0<a>,char}
(0x75af750,0x75569f0) 'a' : 97 S8b
(0x75af750,0x75a40c0) s[a] = 'a' : 97 S8b
Ranges are empty.
Before ArrayBoundChecker::checkLocation() is executed, dead symbols are removed from the ProgramState.
An ugly hack to fix the FN is to comment out the code in RangeConstraintManager::removeDeadBindings. Then the ProgramState dump output will become:
Store (direct and default bindings), 0x0 :
Expressions:
(0x75ae780,0x75559d0) s[a] : &element{s,reg_$0<a>,char}
(0x75ae780,0x7555a10) 'a' : 97 S8b
(0x75ae780,0x75a30f0) s[a] = 'a' : 97 S8b
Ranges of symbol values:
reg_$0<a> : { [20, 18446744073709551615] }
With that ProgramState the bug is found by ArrayBoundChecker.
Now I would like to fix this FN properly. I am thinking about modifying below ExprEngine::ProcessStmt(). Existing code:
void ExprEngine::ProcessStmt(const CFGStmt S,
ExplodedNode *Pred) {
// Reclaim any unnecessary nodes in the ExplodedGraph.
G.reclaimRecentlyAllocatedNodes();
const Stmt *currStmt = S.getStmt();
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
currStmt->getLocStart(),
"Error evaluating statement");
// Remove dead bindings and symbols.
ExplodedNodeSet CleanedStates;
if (shouldRemoveDeadBindings(AMgr, S, Pred, Pred->getLocationContext())){
removeDead(Pred, CleanedStates, currStmt, Pred->getLocationContext());
} else
CleanedStates.Add(Pred);
// Visit the statement.
ExplodedNodeSet Dst;
for (ExplodedNodeSet::iterator I = CleanedStates.begin(),
E = CleanedStates.end(); I != E; ++I) {
ExplodedNodeSet DstI;
// Visit the statement.
Visit(currStmt, *I, DstI);
Dst.insert(DstI);
}
// Enqueue the new nodes onto the work list.
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
The reg_$0<a> symbol should be removed after the statement has been visited. I am thinking about:
* Call the RangeConstraintManager::removeDeadBindings after the for loop. The CleanedStates must still be populated properly before the for loop.
* Change so symbols used in currStmt are not seen as dead.
Do you have any comments?
Best regards,
Daniel Marjamäki
..................................................................................................................
Daniel Marjamäki Senior Engineer
Evidente ES East AB Warfvinges väg 34 SE-112 51 Stockholm Sweden
Mobile: +46 (0)709 12 42 62
E-mail: Daniel.Marjamaki at evidente.se
www.evidente.se
More information about the cfe-dev
mailing list