Skip to content

Commit d40d413

Browse files
committed
gh-156951: Do not truncate the color pair in curses.slk_color()
slk_color() cast its color pair to a short before calling ncurses, while the pair converter accepts pairs up to INT_MAX on a build with extended color support. Pairs of 32768 and above were rejected although the rest of the module accepts them, and a pair whose low 16 bits named a valid pair was silently applied in place of the one that was asked for. Call extended_slk_color() under the module's existing _NCURSES_EXTENDED_COLOR_FUNCS guard, as slk_attr_set() and window.color_set() already do, and keep the legacy call for builds without it.
1 parent 1a2e3a0 commit d40d413

2 files changed

Lines changed: 29 additions & 3 deletions

File tree

Lib/test/test_curses.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3479,10 +3479,10 @@ class SLKTests(NewtermTestBase):
34793479
# slk_init() must run before newterm()/initscr(), so each test sets up its
34803480
# own screen rather than reusing the one TestCurses builds in setUp().
34813481

3482-
def make_slk_screen(self, fmt=0):
3482+
def make_slk_screen(self, fmt=0, term='xterm'):
34833483
s = self.make_pty()
34843484
curses.slk_init(fmt)
3485-
return curses.newterm('xterm', s, s)
3485+
return curses.newterm(term, s, s)
34863486

34873487
def test_init_reserves_a_line(self):
34883488
# Every layout takes the bottom line for the labels; the index-line
@@ -3565,6 +3565,26 @@ def test_color(self):
35653565
curses.slk_attr_set(curses.A_BOLD, 0)
35663566
curses.slk_color(0)
35673567

3568+
def test_color_wide_pair(self):
3569+
# Drive a terminal with enough color pairs to reach past a short,
3570+
# rather than relying on whatever $TERM happens to be.
3571+
try:
3572+
self.make_slk_screen(term='xterm-256color')
3573+
except curses.error:
3574+
self.skipTest('no xterm-256color terminfo entry')
3575+
if not curses.has_colors():
3576+
self.skipTest('requires colors support')
3577+
curses.start_color()
3578+
if not (curses.has_extended_color_support()
3579+
and curses.COLOR_PAIRS > SHORT_MAX + 1):
3580+
self.skipTest('requires extended color support')
3581+
# A pair that does not fit in a short is still a valid pair here.
3582+
curses.slk_color(SHORT_MAX + 1)
3583+
# The low 16 bits of this are pair 5, but the pair itself is out of
3584+
# range, so it must raise instead of selecting pair 5.
3585+
self.assertRaises(curses.error, curses.slk_color,
3586+
curses.COLOR_PAIRS * 2 + 5)
3587+
35683588

35693589
@unittest.skipUnless(hasattr(curses, 'newterm'), 'requires curses.newterm()')
35703590
@unittest.skipIf(BROKEN_NEWTERM, 'ncurses < 6.5 mishandles repeated newterm()')

Modules/_cursesmodule.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8863,7 +8863,13 @@ _curses_slk_color_impl(PyObject *module, int pair)
88638863
/*[clinic end generated code: output=ffe4de805f9c65f5 input=b1e691a9cc6177ee]*/
88648864
{
88658865
PyCursesStatefulInitialised(module);
8866-
return curses_check_err(module, slk_color((short)pair), "slk_color", NULL);
8866+
int rtn;
8867+
#if _NCURSES_EXTENDED_COLOR_FUNCS
8868+
rtn = extended_slk_color(pair);
8869+
#else
8870+
rtn = slk_color((short)pair);
8871+
#endif
8872+
return curses_check_err(module, rtn, "slk_color", NULL);
88678873
}
88688874
#endif /* HAVE_CURSES_SLK_COLOR */
88698875

0 commit comments

Comments
 (0)