Hey all,

First of all, cool findings! I've been working on the CodeQL query and have a 
revised version that I think improves accuracy and might offer some performance 
gains (though I haven't done rigorous benchmarking). The key change is the use 
of `StackVariableReachability` and making sure that there's a path where `var` 
is not reassigned before taking a `goto _;`. Ran it on an older database, found 
some of the same bugs with no false-positives so far.


This is the revised query.
```
import cpp 
import semmle.code.cpp.controlflow.StackVariableReachability


// A call that can return 0
class CallReturningOK extends FunctionCall {
    CallReturningOK() {
     exists(ReturnStmt ret | this.getTarget() = ret.getEnclosingFunction() and 
ret.getExpr().getValue().toInt() = 0)
    }
  
  }

class GotoWrongRetvalConfiguration extends StackVariableReachability {
    GotoWrongRetvalConfiguration() { this = "GotoWrongRetvalConfiguration" }

    // Source is an assigment of an "OK" return value to an access of v
    // To not get FP's we get a false successor
    override predicate isSource(ControlFlowNode node, StackVariable v) {
        exists(AssignExpr ae, IfStmt ifst | ae.getRValue() instanceof 
CallReturningOK 
        and v.getAnAccess() = ae.getLValue() and  
ifst.getCondition().getAChild() = ae  and
        ifst.getCondition().getAFalseSuccessor() = node)
        
    }

    // Our intermediate sink is a `goto _` statement, but it should have a 
successor that's a return of `v`
    override predicate isSink(ControlFlowNode node, StackVariable v) {
        exists(ReturnStmt ret | ret.getExpr() = v.getAnAccess() and
        node instanceof GotoStmt and node.getASuccessor+() = ret.getExpr())
    }

    // We don't want `v` to be reassigned
    override predicate  isBarrier(ControlFlowNode node, StackVariable v) {
        exists(AssignExpr ae | ae.getLValue() = node and v.getAnAccess() = node)
    }
}

from ControlFlowNode source, ControlFlowNode sink, GotoWrongRetvalConfiguration 
conf, Variable v, Expr retval
where
// We want a call that can `return 0` to reach a goto that has a ret of `v` 
sucessor
conf.reaches(source, v, sink)
and 
// We don't want `v` to be reassigned after the goto
not conf.isBarrier(sink.getASuccessor+(), v)
// this goes from our intermediate sink to retval
and sink.getASuccessor+() = retval
// Just making sure that it's returning v
and exists(ReturnStmt ret | ret.getExpr() = retval and retval = v.getAnAccess())
select retval.getEnclosingFunction(), source, sink, retval
```


Hope that's helpful, please reach out if you have any questions :)

Cheers,

Jordy Zomer

Reply via email to