[`pylint`] Fix `unreachable` infinite loop (`PLW0101`) (#15278)

<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

## Summary

Fix infinite loop issue reported here #15248.
The issue was caused by the break inside the if block, which caused the
flow to exit in an unforeseen way. This caused other issues, eventually
leading to an infinite loop.

Resolves #15248. Resolves #15336.

## Test Plan

Added failing code to fixture.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
Co-authored-by: dylwil3 <dylwil3@gmail.com>
This commit is contained in:
Auguste Lalande 2025-01-08 10:45:04 -05:00 committed by GitHub
parent 7284d68157
commit 450d4e0e0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 156 additions and 0 deletions

View File

@ -116,3 +116,15 @@ def func():
finally:
raise Exception("other")
# previously caused infinite loop
# found by fuzzer
def func():
for i in():
try:
try:
while r:
if t:break
finally:()
return
except:l

View File

@ -145,3 +145,12 @@ def bokeh2(self, host: str = DEFAULT_HOST, port: int = DEFAULT_PORT) -> None:
port += 1
self.thread = threading.Thread(target=self._run_web_server)
def func():
while T:
try:
while():
if 3:
break
finally:
return

View File

@ -708,3 +708,76 @@ flowchart TD
block1 --> return
block0 --> return
```
## Function 13
### Source
```python
def func():
for i in():
try:
try:
while r:
if t:break
finally:()
return
except:l
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Loop continue"]]
block2["return\n"]
block3["()\n"]
block4[["Loop continue"]]
block5["break\n"]
block6["if t:break\n"]
block7["while r:
if t:break\n"]
block8[["Exception raised"]]
block9["try:
while r:
if t:break
finally:()\n"]
block10[["Exception raised"]]
block11["l\n"]
block12["try:
try:
while r:
if t:break
finally:()
return
except:l\n"]
block13["for i in():
try:
try:
while r:
if t:break
finally:()
return
except:l\n"]
start --> block13
block13 -- "()" --> block12
block13 -- "else" --> block0
block12 -- "Exception raised" --> block11
block12 -- "else" --> block9
block11 --> block1
block10 --> return
block9 -- "Exception raised" --> block8
block9 -- "else" --> block7
block8 --> block3
block7 -- "r" --> block6
block7 -- "else" --> block3
block6 -- "t" --> block5
block6 -- "else" --> block4
block5 --> block3
block4 --> block7
block3 --> block2
block2 --> return
block1 --> block13
block0 --> return
```

View File

@ -777,3 +777,63 @@ flowchart TD
block1 --> block7
block0 --> return
```
## Function 23
### Source
```python
def func():
while T:
try:
while():
if 3:
break
finally:
return
```
### Control Flow Graph
```mermaid
flowchart TD
start(("Start"))
return(("End"))
block0[["`*(empty)*`"]]
block1[["Loop continue"]]
block2["return\n"]
block3[["Loop continue"]]
block4["break\n"]
block5["if 3:
break\n"]
block6["while():
if 3:
break\n"]
block7[["Exception raised"]]
block8["try:
while():
if 3:
break
finally:
return\n"]
block9["while T:
try:
while():
if 3:
break
finally:
return\n"]
start --> block9
block9 -- "T" --> block8
block9 -- "else" --> block0
block8 -- "Exception raised" --> block7
block8 -- "else" --> block6
block7 --> block2
block6 -- "()" --> block5
block6 -- "else" --> block2
block5 -- "3" --> block4
block5 -- "else" --> block3
block4 --> block2
block3 --> block6
block2 --> return
block1 --> block9
block0 --> return
```

View File

@ -462,6 +462,7 @@ fn post_process_loop(
Some(Stmt::Continue(_)) => {
block.next = NextBlock::Always(loop_start);
}
Some(Stmt::Return(_)) => return,
_ => {}
};
idx = next;
@ -603,6 +604,7 @@ fn post_process_try(
NextBlock::Always(next) => {
next_index = *next;
match block.stmts.last() {
Some(Stmt::Break(_)) => return,
Some(Stmt::Continue(_)) => return,
Some(Stmt::Raise(_)) => {
// re-route to except if not already re-routed