Files
codeql/python/ql/src/Variables/LoopVariableCapture.ql

48 lines
1.5 KiB
Plaintext

/**
* @name Loop variable capture
* @description Capture of a loop variable is not the same as capturing the value of a loop variable, and may be erroneous.
* @kind problem
* @tags correctness
* @problem.severity error
* @sub-severity low
* @precision high
* @id py/loop-variable-capture
*/
import python
// Gets the scope of the iteration variable of the looping scope
Scope iteration_variable_scope(AstNode loop) {
result = loop.(For).getScope()
or
result = loop.(Comp).getFunction()
}
predicate capturing_looping_construct(CallableExpr capturing, AstNode loop, Variable var) {
var.getScope() = iteration_variable_scope(loop) and
var.getAnAccess().getScope() = capturing.getInnerScope() and
capturing.getParentNode+() = loop and
(
loop.(For).getTarget() = var.getAnAccess()
or
var = loop.(Comp).getAnIterationVariable()
)
}
predicate escaping_capturing_looping_construct(CallableExpr capturing, AstNode loop, Variable var) {
capturing_looping_construct(capturing, loop, var) and
// Escapes if used out side of for loop or is a lambda in a comprehension
(
loop instanceof For and
exists(Expr e | e.pointsTo(_, _, capturing) | not loop.contains(e))
or
loop.(Comp).getElt() = capturing
or
loop.(Comp).getElt().(Tuple).getAnElt() = capturing
)
}
from CallableExpr capturing, AstNode loop, Variable var
where escaping_capturing_looping_construct(capturing, loop, var)
select capturing, "Capture of loop variable $@.", loop, var.getId()