You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
3.13.0 REPL crashes on double ctrl+z in line overflow #126332
Python 3.13.0 (tags/v3.13.0:60403a5, Oct 7 2024, 09:38:07) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\11111111111111111111^ZTraceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\__main__.py", line 6, in <module>
__pyrepl_interactive_console()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\main.py", line 59, in interactive_console
run_multiline_interactive_console(console)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\simple_interact.py", line 151, in run_multiline_interactive_console
statement = multiline_input(more_lines, ps1, ps2)
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\readline.py", line 389, in multiline_input
return reader.readline()
~~~~~~~~~~~~~~~^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\reader.py", line 801, in readline
self.handle1()
~~~~~~~~~~~~^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\reader.py", line 784, in handle1
self.do_cmd(cmd)
~~~~~~~~~~~^^^^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\reader.py", line 714, in do_cmd
self.refresh()
~~~~~~~~~~~~^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\reader.py", line 692, in refresh
self.console.refresh(self.screen, self.cxy)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\windows_console.py", line 191, in refresh
self.__write_changed_line(y, oldline, newline, px)
~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\windows_console.py", line 238, in __write_changed_line
and oldline[x_pos] == newline[x_pos]
~~~~~~~^^^^^^^
IndexError: string index out of range
I'm not sure what the intended behaviour is with overflowed lines in the command history, but it does strike me as odd too.
Python 3.13.0 (tags/v3.13.0:60403a5, Oct 7 2024, 09:38:07) [MSC v.1941 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\11111111111111111111^ZTraceback (most recent call last):
File "<frozen runpy>", line 198, in _run_module_as_main
File "<frozen runpy>", line 88, in _run_code
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\__main__.py", line 6, in <module>
__pyrepl_interactive_console()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\main.py", line 59, in interactive_console
run_multiline_interactive_console(console)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\simple_interact.py", line 151, in run_multiline_interactive_console
statement = multiline_input(more_lines, ps1, ps2)
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\readline.py", line 389, in multiline_input
return reader.readline()
~~~~~~~~~~~~~~~^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\reader.py", line 801, in readline
self.handle1()
~~~~~~~~~~~~^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\reader.py", line 784, in handle1
self.do_cmd(cmd)
~~~~~~~~~~~^^^^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\reader.py", line 714, in do_cmd
self.refresh()
~~~~~~~~~~~~^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\reader.py", line 692, in refresh
self.console.refresh(self.screen, self.cxy)
~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\windows_console.py", line 191, in refresh
self.__write_changed_line(y, oldline, newline, px)
~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
File "%LOCALAPPDATA%\Programs\Python\Python313\Lib\_pyrepl\windows_console.py", line 238, in __write_changed_line
and oldline[x_pos] == newline[x_pos]
~~~~~~~^^^^^^^
IndexError: string index out of range
I'm not sure what the intended behaviour is with overflowed lines in the command history, but it does strike me as odd too.
the expression is not the problem, how the REPL is handling overflowing lines is the problem, so it doesn't matter whether its a number literal or a identifier
I can confirm the issue in current main. In the __write_changed_line method there is a guard for the while loop using x_coord:
while (
x_coord < minlen
and oldline[x_pos] == newline[x_pos]
and newline[x_pos] != "\x1b"
):
x_coord += wlen(newline[x_pos])
x_pos += 1
The wlen method has some special casing for ctrl-z, but that is not taken into account when the length of a string is 1:
def wlen(s: str) -> int:
if len(s) == 1:
return str_width(s)
length = sum(str_width(i) for i in s)
# remove lengths of any escape sequences
sequence = ANSI_ESCAPE_SEQUENCE.findall(s)
ctrl_z_cnt = s.count('\x1a')
return length - sum(len(i) for i in sequence) + ctrl_z_cnt
The following diff avoids the crash:
diff --git a/Lib/_pyrepl/utils.py b/Lib/_pyrepl/utils.py
index 0f36083b6ff..4651717bd7e 100644
--- a/Lib/_pyrepl/utils.py
+++ b/Lib/_pyrepl/utils.py
@@ -16,7 +16,7 @@ def str_width(c: str) -> int:
def wlen(s: str) -> int:
- if len(s) == 1:
+ if len(s) == 1 and s != '\x1a':
return str_width(s)
length = sum(str_width(i) for i in s)
# remove lengths of any escape sequences
@pablogsal@godlygeek The optimization in wlen for the single character case was added in #120253. Should the special casing for CTRL-Z be taken into account there?
Activity
base-13 commentedon Nov 2, 2024
I found even more weird things which happens when handing line overflows
2024-11-02.17-36-48.mov
JamesParrott commentedon Nov 2, 2024
Something similar happens with a numeric literal:
Double Ctrl+Z
I'm not sure what the intended behaviour is with overflowed lines in the command history, but it does strike me as odd too.
base-13 commentedon Nov 2, 2024
the expression is not the problem, how the REPL is handling overflowing lines is the problem, so it doesn't matter whether its a number literal or a identifier
eendebakpt commentedon Nov 2, 2024
I can confirm the issue in current main. In the
__write_changed_linemethod there is a guard for the while loop usingx_coord:The
wlenmethod has some special casing for ctrl-z, but that is not taken into account when the length of a string is 1:The following diff avoids the crash:
eendebakpt commentedon Nov 2, 2024
@pablogsal @godlygeek The optimization in
wlenfor the single character case was added in #120253. Should the special casing for CTRL-Z be taken into account there?pablogsal commentedon Jan 21, 2025
I think so. @eendebakpt do you mind creating a PR with the fix?
eendebakpt commentedon Jan 21, 2025
@pablogsal PR is already open: #126650
gh-126332: Fix pyrepl crash for double ctrl-z in line overflow (#126650)
pythongh-126332: Fix pyrepl crash for double ctrl-z in line overflow (p…
[3.13] gh-126332: Fix pyrepl crash for double ctrl-z in line overflow (…
gh-126332: Add tests for _pyrepl.utils (#129325)
pythongh-126332: Add tests for _pyrepl.utils (pythonGH-129325)
[3.13] gh-126332: Add tests for _pyrepl.utils (GH-129325) (#130414)