clang checker is not called back on goto statements

Hi everyone,

I have just got started with clang development. My first project would extract the return value from each path. I can get the return value quite easily, but have some problem with path representation. For example, given the following very simple function,

1: int jump(int x){
2: int result = x;

4: if (x < 5) {
result = -1;
6: goto out;
}

9: result = 0;

out:
12: return result;
}

I would like to return two paths and their corresponding return values. I use line numbers to represent each path.

Path Return value


L6, L12 -1
L12 0

The problem I am having now is that I am not able to get line numbers of goto statements, although my checker writes callback functions for goto statements. My code is as follows. I have tried to add callback functions for PreStmt on both GotoStmt and IndirectGotoStmt and also PostStmt on them, but never got line numbers for goto statements. I can get line numbers for return statements with the following code.

Does anybody have any idea about why this happens?

Thank you for your help.
Sheng

namespace {
class CheckReturnValue : public Checker< check::PreStmt,
check::PreStmt,
check::PostStmt> {

public:
void checkPreStmt(const ReturnStmt *DS, CheckerContext &C) const;
void checkPreStmt(const IndirectGotoStmt *DS, CheckerContext &C) const;
void checkPostStmt(const GotoStmt *DS, CheckerContext &C) const;
private:
static bool isNegative(CheckerContext &C, const Expr *E);
};
} // end anonymous namespace

void CheckReturnValue::checkPostStmt(const GotoStmt *DS, CheckerContext &C) const{

llvm :: outs() << “Goto statement\t”;
DS → getLocStart().print(llvm::outs(),C.getSourceManager()) ;

}

void CheckReturnValue::checkPreStmt(const IndirectGotoStmt *DS, CheckerContext &C) const {
llvm :: outs() << “Indirect goto statement\t”;
DS → getLocStart().print(llvm::outs(),C.getSourceManager()) ;

}

void CheckReturnValue::checkPreStmt(const ReturnStmt DS, CheckerContext &C) const {
const Expr
retExp = DS → getRetValue() ;
retExp → printPretty(llvm::outs(), NULL, PrintingPolicy(LangOptions())) ;

llvm :: outs() << “\tLocation\t”;
DS → getLocStart().print(llvm::outs(),C.getSourceManager()) ;

}

Hello,

In the analyzer (which is a very specific part of clang you're digging into, quite isolated from the rest of the clang, just in case) we only provide checkPreStmt/checkPostStmt callbacks for statements that are also CFGElements within CFGBlocks, i.e. statements that are executed sequentially and don't change control flow. Goto is different because it jumps between two blocks. We also provide the checkBranchCondition callback to check CFGTerminators (last statements in the block, which determine which block is executed next) - i'm not sure if it's called on goto statements (though they are terminators).

In any case, i've never seen anybody need to handle goto statements in a special manner; most of the time you don't care how exactly the control flows, you only care what actions are performed along the path.

Note that the analyzer displays path diagnostics. In your particular project, if you simply throw a warning (CheckerContext::emitReport()) on the ReturnStmt, you'd automatically get a pretty path explanation printed out as console text (-analyzer-output=text), fancy HTML with syntax highlighting (-analyzer-output=html) or machine-readable plist xml for use in IDEs (-analyzer-output=plist).

I also doubt it'd be helpful to try to draw the path through debug prints from the callbacks, because callbacks aren't called sequentially as the program executes, but instead they may jump randomly from one execution branch to another. You need to add information to the program state if you want to track what happens along the current path.