Skip to content

Commit ed4b64b

Browse files
authored
Merge pull request #10265 from yoff/python/port-UnguardedNextInGenerator
Approved by tausbn
2 parents 36f8b05 + 0cfb491 commit ed4b64b

File tree

4 files changed

+17
-6
lines changed

4 files changed

+17
-6
lines changed

python/ql/src/Exceptions/UnguardedNextInGenerator.ql

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,22 @@
1111
*/
1212

1313
import python
14+
private import semmle.python.ApiGraphs
1415

15-
FunctionValue iter() { result = Value::named("iter") }
16+
API::Node iter() { result = API::builtin("iter") }
1617

17-
BuiltinFunctionValue next() { result = Value::named("next") }
18+
API::Node next() { result = API::builtin("next") }
19+
20+
API::Node stopIteration() { result = API::builtin("StopIteration") }
1821

1922
predicate call_to_iter(CallNode call, EssaVariable sequence) {
20-
sequence.getAUse() = iter().getArgumentForCall(call, 0)
23+
call = iter().getACall().asCfgNode() and
24+
call.getArg(0) = sequence.getAUse()
2125
}
2226

2327
predicate call_to_next(CallNode call, ControlFlowNode iter) {
24-
iter = next().getArgumentForCall(call, 0)
28+
call = next().getACall().asCfgNode() and
29+
call.getArg(0) = iter
2530
}
2631

2732
predicate call_to_next_has_default(CallNode call) {
@@ -47,7 +52,7 @@ predicate iter_not_exhausted(EssaVariable iterator) {
4752
predicate stop_iteration_handled(CallNode call) {
4853
exists(Try t |
4954
t.containsInScope(call.getNode()) and
50-
t.getAHandler().getType().pointsTo(ClassValue::stopIteration())
55+
t.getAHandler().getType() = stopIteration().getAValueReachableFromSource().asExpr()
5156
)
5257
}
5358

@@ -61,5 +66,11 @@ where
6166
) and
6267
call.getNode().getScope().(Function).isGenerator() and
6368
not exists(Comp comp | comp.contains(call.getNode())) and
64-
not stop_iteration_handled(call)
69+
not stop_iteration_handled(call) and
70+
// PEP 479 removes this concern from 3.7 onwards
71+
// see: https://peps.python.org/pep-0479/
72+
//
73+
// However, we do not know the minor version of the analyzed code (only of the extractor),
74+
// so we only alert on Python 2.
75+
major_version() = 2
6576
select call, "Call to next() in a generator"

0 commit comments

Comments
 (0)