Skip to content

gh-154749: Reject a terminal-less screen in curses.set_term()#154750

Open
fedonman wants to merge 1 commit into
python:mainfrom
fedonman:fix-curses-set-term-prescr
Open

gh-154749: Reject a terminal-less screen in curses.set_term()#154750
fedonman wants to merge 1 commit into
python:mainfrom
fedonman:fix-curses-set-term-prescr

Conversation

@fedonman

@fedonman fedonman commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

curses.set_term() only checked that its argument is a screen that has not been
deleted, so it also accepted a screen from curses.new_prescr(). That screen has no
terminal attached, and once it was made current the next window refresh dereferenced
NULL inside curses and killed the interpreter:

import curses, os
fd = os.openpty()[1]
scr = curses.newterm('xterm', fd, fd)
curses.set_term(curses.new_prescr())
scr.stdscr.refresh()          # Segmentation fault, rc=139

set_term() now raises curses.error when the screen has no standard window, which is
exactly what a new_prescr() screen is. The documentation already described the argument
as a screen returned by newterm(), so this makes the code match, and the docs now
mention the exception.

Both functions are new in 3.16 (gh-90092, GH-151748), so no released version is affected.

The same reproducer after the change:

set_term(new_prescr()) -> error: the screen has no terminal
refresh after the rejected switch: ok
set_term(real screen) still works, prev is a screen: True
refresh on the new current screen: ok

Tests:

$ ./python -m test -u all -v test_curses -m 'test_set_term_prescr_screen'
test_set_term_prescr_screen (test.test_curses.ScreenTests.test_set_term_prescr_screen) ... ok
Ran 1 test in 0.107s
OK

$ ./python -m test -u all test_curses
Total tests: run=164 skipped=3
Result: SUCCESS

curses.set_term() accepted a screen returned by new_prescr(), which has no
terminal attached. Making such a screen current left curses without a
terminal, and the next window refresh dereferenced NULL and crashed the
interpreter.

set_term() now raises curses.error for a screen with no standard window,
which is exactly a new_prescr() screen. The documentation already said the
argument comes from newterm().
@read-the-docs-community

Copy link
Copy Markdown

Documentation build overview

📚 cpython-previews | 🛠️ Build #33767389 | 📁 Comparing b87e630 against main (5afbb60)

  🔍 Preview build  

2 files changed
± library/curses.html
± whatsnew/changelog.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant