basic analyzer checker programstate problem

hi

another fairly basic question that i am having trouble with: i am trying to set some state in an analyzer checker in checkBranchCondition and then retrieve it in checkPreCall. the state is being set ok, but for some reason is never readable in successive checkPreCall callbacks, the state map always returns NULL. i thought that the ProgramState data map was supposed to propagate down the graph, is this not how it works? i can see the node that is added to the graph, so why can i not get the state that is set?

here is the code i am using, i followed some of the other checkers pretty closely, am i doing something stupid here?

void UnavailableMethodChecker::checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const
{
VersionTuple V = getAvailabilityForStmt(Condition, Ctx);
ProgramStateRef State = Ctx.getState();
SymbolRef Sym = State->getSVal(Condition, Ctx.getLocationContext()).getAsSymbol();
State = State->set(Sym, AvailabilityState(V));
Ctx.addTransition(State);
}

void UnavailableMethodChecker::checkPreCall(const CallEvent &Call, CheckerContext &Ctx) const
{

ProgramStateRef State = Ctx.getState();
AvailabilityMapTy M = State->get();
// M is always NULL here

for (AvailabilityMapTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
AvailabilityState A = I->second;
if (A.Version >= CallVersion) {
return;
}
}


}

thanks for the help.

Your understanding is correct, the map should be propagated.
Are you sure that checkBranchCondition and checkPreCall are both called? Furthermore, are you sure one is called after the other along the same path? (You might find the ExplodedGraph viewing (p ViewGraph(0)) helpful for debugging this: http://clang-analyzer.llvm.org/checker_dev_manual.html#commands.)

Also, if checking for the availability is done through a simple API call returning a bool (ex: ‘is_available’), the following approach might work. Register for checkPostCall on that API and store the returned symbol. Later, when the deprecated API is used, check if the symbol (return value from the is_available call) evaluates to true. (This would be similar to how we check if fopen succeeded in the talk.)

Cheers,
Anna.

hey anna

i am sure that both the callbacks are called, i am stepping through them in lldb, and i have checked the graph to get the order, but i cannot work out why state cannot be propagated from checkBranchCondition callbacks. for the trivial test code below:

int main(int argc, char *argv[])
{
UILabel *l = [[UILabel alloc] init];

if ([l respondsToSelector:@selector(adjustsLetterSpacingToFitWidth)]) {
l.adjustsLetterSpacingToFitWidth = YES;
} else {
l.adjustsLetterSpacingToFitWidth = NO;
}
[l release];

return 0;
}

if i add state before the IfStmt, say in a checkPostCall callback, i can read this state from any point further down the graph. if i add state in the checkBranchCondition callback however, it is visible for the duration of the callback, but is then being removed somewhere, and the only state visible after the branch is state set outside the IfStmt. i tried adding a breakpoint in the StateTrait::Remove method, but it did not seem to get called.

any suggestions?

Looks like you’ve hit a bug in the analyzer ExprEngine!

Should be fixed by r170232. Let me know if that’s not the case.

Cheers,
Anna.

yeah, thats fixed it, ta.