mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Python: Handle loop constructs outside of loops
Observed on some test files in Nuitka/Nuitka, having `break` and `continue` outside of loops in Python is (to Python) a syntax error, but our parser happily accepted this broken syntax. This then caused issues further downstream in the control-flow construction, as it broke some invariants. To fix this we now skip the code that would previously fail when the invariants are broken. Co-authored-by: yoff <yoff@github.com>
This commit is contained in:
@@ -909,14 +909,22 @@ class FlowPass(Pass):
|
||||
def _walk_break(self, node, predecessors):
|
||||
#A break statement counts as an exit to the enclosing loop statement
|
||||
predecessors = self.add_successor(predecessors, node)
|
||||
self.scope.breaking_stack.add(predecessors)
|
||||
# In well formed code, there should always be an element in the breaking stack, but because
|
||||
# our parser accepts code where `break` appears outside of a loop, we must check for this
|
||||
# case.
|
||||
if self.scope.breaking_stack:
|
||||
self.scope.breaking_stack.add(predecessors)
|
||||
#Provide no predecessors to following statement
|
||||
return EMPTY
|
||||
|
||||
def _walk_continue(self, node, predecessors):
|
||||
#A continue statement counts as an exit to the following orelse
|
||||
predecessors = self.add_successor(predecessors, node)
|
||||
self.scope.continuing_stack.add(predecessors)
|
||||
# In well formed code, there should always be an element in the continuing stack, but
|
||||
# because our parser accepts code where `continue` appears outside of a loop, we must check
|
||||
# for this case.
|
||||
if self.scope.continuing_stack:
|
||||
self.scope.continuing_stack.add(predecessors)
|
||||
#Provide no predecessors to following statement
|
||||
return EMPTY
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: fix
|
||||
---
|
||||
|
||||
- Using the `break` and `continue` keywords outside of a loop, which is a syntax error but is accepted by our parser, would cause the control-flow construction to fail. This is now no longer the case.
|
||||
10
python/ql/test/extractor-tests/syntax_error/without_loop.py
Normal file
10
python/ql/test/extractor-tests/syntax_error/without_loop.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# The following constructs are syntax errors in Python, as they are not inside a loop.
|
||||
# However, our parser does not consider this code to be syntactically incorrect.
|
||||
# Thus, this test is really observing that allowing these constructs does not break any other parts
|
||||
# of the extractor.
|
||||
|
||||
if True:
|
||||
break
|
||||
|
||||
if True:
|
||||
continue
|
||||
Reference in New Issue
Block a user