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.
This commit is contained in:
nick black
2020-01-07 18:41:04 -05:00
parent 31ee76e8ee
commit 302bcca99a
3 changed files with 24 additions and 4 deletions

View File

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

View File

@@ -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();

View File

@@ -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 << " ";
}
}
}