[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