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

curses segfault resizing window #80105

Closed
JosiahUlfers mannequin opened this issue Feb 7, 2019 · 9 comments
Closed

curses segfault resizing window #80105

JosiahUlfers mannequin opened this issue Feb 7, 2019 · 9 comments
Labels
extension-modules C modules in the Modules dir type-crash A hard crash of the interpreter, possibly with a core dump

Comments

@JosiahUlfers
Copy link
Mannequin

JosiahUlfers mannequin commented Feb 7, 2019

BPO 35924
Nosy @Yhg1s, @abadger, @lisroach
PRs
  • bpo-35924: Document a workaround for a curses bug #13209
  • Files
  • cursesfault.py
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2019-05-18.02:38:00.339>
    created_at = <Date 2019-02-07.00:02:21.351>
    labels = ['extension-modules', 'type-crash']
    title = 'curses segfault resizing window'
    updated_at = <Date 2019-05-18.02:38:00.338>
    user = 'https://bugs.python.org/JosiahUlfers'

    bugs.python.org fields:

    activity = <Date 2019-05-18.02:38:00.338>
    actor = 'Josiah Ulfers'
    assignee = 'none'
    closed = True
    closed_date = <Date 2019-05-18.02:38:00.339>
    closer = 'Josiah Ulfers'
    components = ['Extension Modules']
    creation = <Date 2019-02-07.00:02:21.351>
    creator = 'Josiah Ulfers'
    dependencies = []
    files = ['48108']
    hgrepos = []
    issue_num = 35924
    keywords = ['patch']
    message_count = 9.0
    messages = ['334991', '337718', '341802', '341893', '341925', '342266', '342776', '342786', '342787']
    nosy_count = 4.0
    nosy_names = ['twouters', 'a.badger', 'lisroach', 'Josiah Ulfers']
    pr_nums = ['13209']
    priority = 'normal'
    resolution = None
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = 'crash'
    url = 'https://bugs.python.org/issue35924'
    versions = ['Python 2.7', 'Python 3.6']

    @JosiahUlfers
    Copy link
    Mannequin Author

    JosiahUlfers mannequin commented Feb 7, 2019

    To provoke a segmentation fault, run the attached, then grab the top or
    bottom edge of the window. Move it down or up until it overlaps the box.
    Might need to wiggle the edge a little, but it's reliably reproducible.

    Expected error, which is what happens when dragging the left or right edge
    instead of the top or bottom:

        Traceback (most recent call last):
          File "cursesfault.py", line 12, in <module>
            curses.wrapper(main)
          File "/usr/lib64/python3.6/curses/__init__.py", line 94, in wrapper
            return func(stdscr, *args, **kwds)
          File "cursesfault.py", line 9, in main
            w.addstr(0, 0, box)
        _curses.error: addwstr() returned ERR

    Actual error message varies a little. It's either:

    *** Error in `python3': corrupted size vs. prev_size: 0x000055b3055ba820 ***
        Aborted (core dumped)
    

    Or:

    *** Error in `python3': double free or corruption (!prev): 0x000055b61e1ffbb0 ***
        Aborted (core dumped)
    

    Or:

    *** Error in `python': malloc(): memory corruption: 0x0000564907a5a4f0 ***
        Aborted (core dumped)
    

    Possibly relates to bpo-15581

    ---

    Python 2.7.14 and 3.6.5
    OpenSUSE 15.0
    KDE Plasma 5.12.6

    uname -a
    Linux ... 4.12.14-lp150.12.45-default #1 SMP Mon Jan 14 20:29:59 UTC 2019 (7a62739) x86_64 x86_64 x86_64 GNU/Linux

    @JosiahUlfers JosiahUlfers mannequin added extension-modules C modules in the Modules dir type-crash A hard crash of the interpreter, possibly with a core dump labels Feb 7, 2019
    @lisroach
    Copy link
    Contributor

    I am able to confirm the repro, I haven't been able to find the root cause of it yet though. Trying to dig into it.

    @abadger
    Copy link
    Mannequin

    abadger mannequin commented May 7, 2019

    I'm still debugging this but it may be an off-by-one error in ncurses, wresize.c. I've found that if I modify the following section in ncurses, our problem goes away:

        /*
           * Dispose of unwanted memory.
           */
          if (!(win->_flags & _SUBWIN)) { 
              if (ToCols == size_x) { 
                  for (row = ToLines + 1; row <= size_y; row++) { 
                       free(win->_line[row].text);
                  } 
              } else { 
                  for (row = 0; row <= size_y; row++) { 
                       free(win->_line[row].text);
                  } 
              }
          } 
      
          free(win->_line);
          win->_line = new_lines;
    
    Replacing:
                  for (row = ToLines + 1; row <= size_y; row++) { 
    with:
                  for (row = ToLines + 2; row <= size_y; row++) { 

    fixes this error. ToLines is a parameter passed in to wresize. wresize will reuse ToLines number of rows from the old structure in the new structure. Due to that, I think that the chances are good that it is ncurses which is at fault here. I will try to rewrite the test case into a C program and then submit a bug report to ncurses upstream. I'm not sure that there's a way we can work around this until that's fixed.

    @abadger
    Copy link
    Mannequin

    abadger mannequin commented May 8, 2019

    I've diagnosed this a bit further and have a workaround for you. It appears that using addstr() with a string with embedded newlines is a piece of the problem. If I modify your example program so that we add each line as a separate string instead of adding them as a single string with embedded newlines, we get the ncurses ERR on resize instead of a segfault:

    import curses
    
    def main(stdscr):
        y, x = curses.LINES//3, curses.COLS//3  # size is arbitrary
        box = '\n'.join('+'*x for _ in range(y))
        w = stdscr.subwin(y, x+1, y, x) 
        while True: 
            new_box = box[:]
            w.clear()
            for offset, line in enumerate(box.splitlines()):
                w.addstr(offset, 0, line) 
            w.getch()  # not required, just avoids a hot loop
    
    curses.wrapper(main)

    I don't see anything in the curses specification that forbids embedded newlines in the string to addstr(), though, so I am still thinking that this is a bug in ncurses.

    @abadger
    Copy link
    Mannequin

    abadger mannequin commented May 8, 2019

    My upstream (ncurses) bug report: http://lists.gnu.org/archive/html/bug-ncurses/2019-05/msg00010.html

    @abadger
    Copy link
    Mannequin

    abadger mannequin commented May 12, 2019

    Hi Josiah, I've tested my sample program and it looks like the segmentation fault is fixed with ncurses-6.1-20190511: http://lists.gnu.org/archive/html/bug-ncurses/2019-05/msg00013.html

    Are you able to give that a try and see whether it resolves the issue for you as well?

    For the Core devs; Assuming this is fixed in a newer ncurses, how would you like to proceed with this bug? I have a documentation PR to tell people about the bug in ncurses and the workaround: #13209 I can update that to mention the version of ncurses that this is fixed in if you want that. Other than that, I'm not sure what more we can do.

    @lisroach
    Copy link
    Contributor

    Thank you for all the work you did on this Toshio! I think we are good to close this issue.

    @JosiahUlfers
    Copy link
    Mannequin Author

    JosiahUlfers mannequin commented May 18, 2019

    Yes, thanks Toshio and Lisa and sorry for the slow response. I just now built a Python 3.7.3 against ncurses-6.1-20190511 and can confirm it resolved the issue.

    1 similar comment
    @JosiahUlfers
    Copy link
    Mannequin Author

    JosiahUlfers mannequin commented May 18, 2019

    Yes, thanks Toshio and Lisa and sorry for the slow response. I just now built a Python 3.7.3 against ncurses-6.1-20190511 and can confirm it resolved the issue.

    @JosiahUlfers JosiahUlfers mannequin closed this as completed May 18, 2019
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    extension-modules C modules in the Modules dir type-crash A hard crash of the interpreter, possibly with a core dump
    Projects
    None yet
    Development

    No branches or pull requests

    1 participant