[cfe-dev] Suggested starter bug on clang analyzer codebase

Artem Dergachev via cfe-dev cfe-dev at lists.llvm.org
Tue Apr 18 08:00:38 PDT 2017


Before anything, please note that `State' is your local variable; 
assigning to `State' doesn't immediately affect analysis in any way. In 
order to make your changes to the program state take effect, you'd need 
to put the changed state back into the `CheckerContext' by calling its 
`addTransition' method, like other checker callbacks do.

Otherwise, your code looks reasonable to me. If everything is 
implemented correctly, i believe that your code would already suppress 
the double-destroy warning on this branch.

On 4/18/17 5:53 PM, Malhar Thakkar wrote:
> Test-case:
>
> pthread_mutex_lock(&mtx1);
> pthread_mutex_unlock(&mtx1);
> int retval = pthread_mutex_destroy(&mtx1);
> if(retval != 0){
> pthread_mutex_destroy(&mtx1); (1)
> }
> else
> printf("Already destroyed\n");
>
>
> Regarding my previous query about reverting the LockState, how would I 
> ensure that the LockState at (1) is Unlocked and not Destroyed?
>
> Following is the code for checkDeadSymbols()
> void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper,
>                    CheckerContext &C) const {
>   ProgramStateRef State = C.getState();
>   ConstraintManager &CMgr = State->getConstraintManager();
>
>   RetValConstraintTy TrackedSymbols = State->get<RetValConstraint>();
>   for (RetValConstraintTy::iterator I = TrackedSymbols.begin(),
>      E = TrackedSymbols.end(); I != E; ++I) {
>     SymbolRef Sym = I->second;
>     const MemRegion* lockR = I->first;
>     bool IsSymDead = SymReaper.isDead(Sym);
>     const LockState* LState = State->get<LockMap>(lockR);
>     // Remove the dead symbol from the return value symbols map.
>     if (IsSymDead){
>       ConditionTruthVal retZero = CMgr.isNull(State, Sym);
> if(retZero.isConstrainedFalse()){
>         // Update LockMap
>         State = State->remove<LockMap>(lockR); // I know this is 
> incorrect but even after removing this entry                      from 
> the map, (1) raises a warning saying, "This lock has already been 
> destroyed".
>       }
>       State = State->remove<RetValConstraint>(lockR);
>     }
>   }
> }
>
> Thank you.
>
>
> Regards,
> Malhar
>
>
>>
> On Mon, Apr 17, 2017 at 8:34 PM, Devin Coughlin <dcoughlin at apple.com 
> <mailto:dcoughlin at apple.com>> wrote:
>
>
>>     On Apr 17, 2017, at 4:55 AM, Malhar Thakkar <cs13b1031 at iith.ac.in
>>     <mailto:cs13b1031 at iith.ac.in>> wrote:
>>
>>     Consider the following test-case:
>>
>>     int retval = pthread_mutex_destroy(&mtx1);
>>     if(retval == 0){
>>     pthread_mutex_lock(&mtx1);
>>     }
>>
>>
>>     REGISTER_MAP_WITH_PROGRAMSTATE(RetValConstraint, const MemRegion
>>     *, SymbolRef)
>>
>>     I have added the following snippet for checkDeadSymbols:
>>     void PthreadLockChecker::checkDeadSymbols(SymbolReaper &SymReaper,
>>      CheckerContext &C) const {
>>       // std::cout<<"Checking dead symbols\n";
>>     ProgramStateRef State = C.getState();
>>     ConstraintManager &CMgr = State->getConstraintManager();
>>
>>     RetValConstraintTy TrackedSymbols = State->get<RetValConstraint>();
>>       // int counter = 0;
>>       for (RetValConstraintTy::iterator I = TrackedSymbols.begin(),
>>                            E = TrackedSymbols.end(); I != E; ++I) {
>>     // counter++;
>>     // std::cout << "Counter: "<<counter<<std::endl;
>>     SymbolRef Sym = I->second;
>>     const MemRegion* lockR = I->first;
>>     bool IsSymDead = SymReaper.isDead(Sym);
>>
>>     // Remove the dead symbol from the return value symbols map.
>>     if (IsSymDead){
>>     ConditionTruthVal retZero = CMgr.isNull(State, Sym);
>>     if(retZero.isConstrainedFalse()){
>>       std::cout<<"False\n";
>>       // Update LockMap
>>     }
>>     else if(retZero.isConstrainedTrue()){
>>       std::cout<<"True\n";
>>     }
>>     State = State->remove<RetValConstraint>(lockR);
>>     std::cout<<"Removed\n";
>>         }
>>       }
>>     }
>>
>>     Now, after the execution of PthreadLockChecker::DestroyLock(),
>>     checkDeadSymbols() is executed twice before
>>     PthreadLockChecker::AcquireLock() is executed.
>>
>>     When checkDeadSymbols is first executed, there is just one symbol
>>     in RetValConstraint(trivial). But, this symbol is constrained
>>     /not /to be NULL. Then, the symbol is removed. During the
>>     execution of checkDeadSymbols for the second time, there is again
>>     one symbol in RetValConstraint(I don't understand this. Shouldn't
>>     this symbol have been destroyed during the previous execution?).
>>     Nevertheless, this time, this symbol is constrained to be NULL.
>
>     The static analyzer performs a path-sensitive exploration of the
>     program. This means that when it sees a branch it will explore
>     both both sides of the branch independently (unless it can tell
>     that one side is infeasible). In this case it means the analyzer
>     will explore the path when retval is 0 and when it is not. If you
>     haven’t read it yet, the “Debugging” section the the checker
>     development manual describes some tricks for how to visualize the
>     analyzer’s exploration.
>     <https://clang-analyzer.llvm.org/checker_dev_manual.html#commands
>     <https://clang-analyzer.llvm.org/checker_dev_manual.html#commands>>.
>     I find the debug.ViewExplodedGraph checker particularly helpful.
>
>>     Also, I have one more query. After fixing the above mentioned
>>     issue, how do I update LockMap in the sense that I'll need to
>>     revert the change made to it if the symbol is constrained not to
>>     be NULL. Apart from keeping track of the previous LockState, is
>>     there any other way to do it?
>
>     Since the analyzer keeps its representation of the program state
>     per-path and explores paths independently, you shouldn’t need to
>     do any reverting to undo the effects of simulating other paths to
>     reaching a particular program point.
>
>     Devin
>
>




More information about the cfe-dev mailing list