From 302bcca99af58764c0e4311559397716360971a1 Mon Sep 17 00:00:00 2001 From: nick black Date: Tue, 7 Jan 2020 18:41:04 -0500 Subject: [PATCH] Curses: don't iterate through unbound COLORS #369 On DirectColor-capable terminals with the proper terminfo database in use, COLORS is 2^24. Since the color map is only 64k entries, this resulted in a segfault. I've introduced NC::colorCount(), which bounds it by the previously assumed maximum (and usable range) of 256. --- src/curses/window.cpp | 20 +++++++++++++++++--- src/curses/window.h | 4 ++++ src/screens/help.cpp | 4 +++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/curses/window.cpp b/src/curses/window.cpp index d9feebad..4193bf76 100644 --- a/src/curses/window.cpp +++ b/src/curses/window.cpp @@ -33,6 +33,10 @@ namespace { +// In a DirectColor setup, COLORS as returned by ncurses (via terminfo) can +// run as high as 2^24. We only work with up to 256. +int maxColor; + namespace rl { bool aborted; @@ -224,9 +228,9 @@ int Color::pairNumber() const else if (!isDefault()) { if (!currentBackground()) - result = (background() + 1) % COLORS; + result = (background() + 1) % colorCount(); result *= 256; - result += foreground() % COLORS; + result += foreground() % colorCount(); assert(result < int(color_pair_map.size())); @@ -385,6 +389,11 @@ void disable() } +int colorCount() +{ + return maxColor; +} + void initScreen(bool enable_colors, bool enable_mouse) { initscr(); @@ -392,13 +401,18 @@ void initScreen(bool enable_colors, bool enable_mouse) { start_color(); use_default_colors(); + maxColor = COLORS; + if (maxColor > 256) + { + maxColor = 256; + } color_pair_map.resize(256 * 256, 0); // Predefine pairs for colors with transparent background, all the other // ones will be dynamically registered in Color::pairNumber when they're // used. color_pair_counter = 1; - for (int fg = 0; fg < COLORS; ++fg, ++color_pair_counter) + for (int fg = 0; fg < colorCount(); ++fg, ++color_pair_counter) { init_pair(color_pair_counter, fg, -1); color_pair_map[fg] = color_pair_counter; diff --git a/src/curses/window.h b/src/curses/window.h index 220f84d3..97ed2e40 100644 --- a/src/curses/window.h +++ b/src/curses/window.h @@ -219,6 +219,10 @@ void disable(); /// @param enable_colors enables colors void initScreen(bool enable_colors, bool enable_mouse); +// Get the maximum supported color index (but only once initScreen() has been +// successfully called). This might be less than the advertised COLORS. +int colorCount(); + /// Pauses the screen (e.g. for running an external command) void pauseScreen(); diff --git a/src/screens/help.cpp b/src/screens/help.cpp index b1124b50..7cdca37d 100644 --- a/src/screens/help.cpp +++ b/src/screens/help.cpp @@ -424,8 +424,10 @@ void write_bindings(NC::Scrollpad &w) } section(w, "", "List of available colors"); - for (int i = 0; i < COLORS; ++i) + for (int i = 0; i < NC::colorCount(); ++i) + { w << NC::Color(i, NC::Color::transparent) << i+1 << NC::Color::End << " "; + } } }