Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3.13.0 REPL crashes on double ctrl+z in line overflow #126332

Open
base-13 opened this issue Nov 2, 2024 · 5 comments
Open

3.13.0 REPL crashes on double ctrl+z in line overflow #126332

base-13 opened this issue Nov 2, 2024 · 5 comments
Labels
3.13 bugs and security fixes 3.14 new features, bugs and security fixes OS-windows topic-repl Related to the interactive shell type-bug An unexpected behavior, bug, or error

Comments

@base-13
Copy link

base-13 commented Nov 2, 2024

Bug report

Bug description:

The new REPL in 3.13.0 crashes on pressing ctrl+Z twice at the end of a overflowing line, refer to the attachment

2024-11-02.17-22-35.mov

CPython versions tested on:

3.13

Operating systems tested on:

Windows

Linked PRs

@base-13 base-13 added the type-bug An unexpected behavior, bug, or error label Nov 2, 2024
@picnixz picnixz added OS-windows topic-repl Related to the interactive shell 3.13 bugs and security fixes 3.14 new features, bugs and security fixes labels Nov 2, 2024
@base-13
Copy link
Author

base-13 commented Nov 2, 2024

I found even more weird things which happens when handing line overflows

2024-11-02.17-36-48.mov

@JamesParrott
Copy link

Something similar happens with a numeric literal:

Double Ctrl+Z

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.

@base-13
Copy link
Author

base-13 commented Nov 2, 2024

Something similar happens with a numeric literal:

Double Ctrl+Z

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

@eendebakpt
Copy link
Contributor

eendebakpt commented Nov 2, 2024

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

@eendebakpt
Copy link
Contributor

@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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3.13 bugs and security fixes 3.14 new features, bugs and security fixes OS-windows topic-repl Related to the interactive shell type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

4 participants