Subject: lib/17352: libcurses core dumps if screen wider than 1024 columns
To: None <gnats-bugs@gnats.netbsd.org>
From: None <dsl@l8s.co.uk>
List: netbsd-bugs
Date: 06/21/2002 10:52:10
>Number: 17352
>Category: lib
>Synopsis: libcurses core dumps if screen wider than 1024 columns
>Confidential: no
>Severity: serious
>Priority: low
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Jun 21 02:53:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator: David Laight
>Release: NetBSD 1.5ZC (also current 21/6/02)
>Organization:
no
>Environment:
System: NetBSD snowdrop 1.5ZC NetBSD 1.5ZC (GENERIC) #10: Thu May 16 12:50:04 BST 2002 dsl@snowdrop:/oldroot/usr/bsd-current/src/sys/arch/i386/compile/GENERIC i386
Architecture: i386
Machine: i386
>Description:
There are a few buffers on size 1024 in libcurses that cause
grief on very wide terminals.
Additionaly the cursor positioning routing (in libterm)
won't generate lines/columns > 999.
I've also fixed bugs that stop libcurses compiling if DEBUG
is defined.
>How-To-Repeat:
Run a 'vi' that has had the 500 column limit removed on a
very wide terminal (eg xterm with font 'unreadable').
>Fix:
Apply the following patches:
(The fix in scanw.c stops the buffer overwrite.
OTOH I'm not at all sure what this code is playing at!)
Index: color.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/color.c,v
retrieving revision 1.17
diff -u -r1.17 color.c
--- color.c 2002/01/02 10:38:27 1.17
+++ color.c 2002/06/21 09:34:26
@@ -318,8 +318,8 @@
pair = PAIR_NUMBER((u_int32_t)attr);
#ifdef DEBUG
__CTRACE("__set_color: %d, %d, %d\n", pair,
- _cursesi_screen->pairs[pair].fore,
- _cursesi_screen->pairs[pair].back);
+ _cursesi_screen->colour_pairs[pair].fore,
+ _cursesi_screen->colour_pairs[pair].back);
#endif
switch (_cursesi_screen->color_type) {
/* Set ANSI forground and background colours */
Index: cr_put.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/cr_put.c,v
retrieving revision 1.20
diff -u -r1.20 cr_put.c
--- cr_put.c 2000/12/19 21:34:24 1.20
+++ cr_put.c 2002/06/21 09:34:38
@@ -97,7 +97,7 @@
int in_refresh;
{
int c, l;
- char cgp[1024];
+ char cgp[64]; /* 64 bytes is plenty for terminfo 'move cursor' */
if (destcol >= COLS) {
destline += destcol / COLS;
@@ -166,9 +166,7 @@
}
if (destline < outline && !(__CA || __tc_up))
destline = outline;
- if (__CA) {
- t_goto(NULL, __tc_cm, destcol, destline, cgp, 1023);
-
+ if (__CA && !t_goto(NULL, __tc_cm, destcol, destline, cgp, sizeof cgp - 1)) {
/*
* Need this condition due to inconsistent behavior
* of backspace on the last column.
Index: ctrace.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/ctrace.c,v
retrieving revision 1.12
diff -u -r1.12 ctrace.c
--- ctrace.c 2002/05/26 17:01:38 1.12
+++ ctrace.c 2002/06/21 09:34:48
@@ -45,6 +45,7 @@
#ifdef DEBUG
#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
@@ -65,10 +66,18 @@
static int seencr = 1;
va_list ap;
- if (tracefp == NULL)
- tracefp = fopen(TFILE, "w");
- if (tracefp == NULL)
+ if (tracefp == (void *)~0)
+ return;
+
+ if (tracefp == NULL) {
+ char *tf = getenv( "CURSES_TRACE_FILE" );
+ if (!tf || strcmp( tf, "<none>"))
+ tracefp = fopen( tf ? tf : TFILE, "w");
+ }
+ if (tracefp == NULL) {
+ tracefp = (void *)~0;
return;
+ }
gettimeofday(&tv, NULL);
if (seencr) {
gettimeofday(&tv, NULL);
Index: cur_hash.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/cur_hash.c,v
retrieving revision 1.9
diff -u -r1.9 cur_hash.c
--- cur_hash.c 2000/04/15 13:17:03 1.9
+++ cur_hash.c 2002/06/21 09:35:02
@@ -50,12 +50,14 @@
/*
* __hash() is "hashpjw" from the Dragon Book, Aho, Sethi & Ullman, p.436.
*/
+
u_int
-__hash(char *s, int len)
+__hash_more(const void *v_s, size_t len, u_int h)
{
- u_int h, g, i;
+ u_int g;
+ size_t i;
+ const char *s = v_s;
- h = 0;
i = 0;
while (i < len) {
h = (h << 4) + s[i];
Index: curses_private.h
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/curses_private.h,v
retrieving revision 1.20
diff -u -r1.20 curses_private.h
--- curses_private.h 2002/01/02 10:38:27 1.20
+++ curses_private.h 2002/06/21 09:35:25
@@ -231,7 +231,7 @@
unsigned int len;
int meta_state;
char pad_char;
- char ttytype[1024];
+ char ttytype[128]; /* terminal name - filled by __longname */
int endwin;
};
@@ -255,7 +255,8 @@
int _cursesi_setterm(char *type, SCREEN *screen);
int _cursesi_wnoutrefresh(SCREEN *screen, WINDOW *win);
int __delay(void);
-unsigned int __hash(char *s, int len);
+unsigned int __hash_more(const void *s, size_t len, unsigned int hash_in);
+#define __hash(s,len) __hash_more(s,len,0u)
void __id_subwins(WINDOW *orig);
void __init_getch(SCREEN *screen);
void __init_acs(SCREEN *screen);
Index: refresh.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/refresh.c,v
retrieving revision 1.45
diff -u -r1.45 refresh.c
--- refresh.c 2002/01/02 10:38:28 1.45
+++ refresh.c 2002/06/21 09:35:39
@@ -240,8 +240,7 @@
for (wy = 0; wy < win->maxy; wy++) {
wlp = win->lines[wy];
if (wlp->flags & __ISDIRTY)
- wlp->hash = __hash((char *)(void *)wlp->line,
- (int) (win->maxx * __LDATASIZE));
+ wlp->hash = __hash(wlp->line, win->maxx * __LDATASIZE);
}
if ((win->flags & __CLEAROK) || (curscr->flags & __CLEAROK) ||
@@ -721,9 +720,11 @@
__LINE *clp, *tmp1, *tmp2;
int bsize, curs, curw, starts, startw, i, j;
int n, target, cur_period, bot, top, sc_region;
- __LDATA buf[1024];
+ static __LDATA buf[128]; /* only ever spaces */
u_int blank_hash;
attr_t bcolor;
+ static u_int last_hash;
+ static size_t last_hash_len;
#ifdef __GNUC__
curs = curw = starts = startw = 0; /* XXX gcc -Wuninitialized */
@@ -865,15 +866,26 @@
}
#endif
+ /* Initialise buf to a block of space chars... */
+ if (!buf[0].ch)
+ for (i = 0; i < 128; i++) {
+ buf[i].ch = ' ';
+ buf[i].bch = ' ';
+ buf[i].attr = 0;
+ buf[i].battr = 0;
+ }
+
/* So we don't have to call __hash() each time */
- for (i = 0; i < __virtscr->maxx; i++) {
- buf[i].ch = ' ';
- buf[i].bch = ' ';
- buf[i].attr = 0;
- buf[i].battr = 0;
- }
- blank_hash = __hash((char *)(void *)buf,
- (int) (__virtscr->maxx * __LDATASIZE));
+ if (__virtscr->maxx != last_hash_len) {
+ blank_hash = 0;
+ for (i = __virtscr->maxx; i > 128; i-= 128 )
+ blank_hash = __hash_more( buf, sizeof buf, blank_hash );
+ blank_hash = __hash_more( buf, i * sizeof buf[0], blank_hash );
+ /* cache result in static data - screen width doesn't change often! */
+ last_hash_len = __virtscr->maxx;
+ last_hash = blank_hash;
+ } else
+ blank_hash = last_hash;
/*
* Perform the rotation to maintain the consistency of curscr.
@@ -930,10 +942,13 @@
} else
if ((n > 0 && target >= top && target < top + n) ||
(n < 0 && target <= bot && target > bot + n)) {
- if (clp->hash != blank_hash || memcmp(clp->line,
- buf, (size_t) __virtscr->maxx * __LDATASIZE) !=0) {
- (void)memcpy(clp->line, buf,
- (size_t) __virtscr->maxx * __LDATASIZE);
+ if (clp->hash != blank_hash
+ || memcmp(clp->line, clp->line + 1,
+ (__virtscr->maxx - 1) * __LDATASIZE)
+ || memcmp( clp->line, buf, __LDATASIZE) ) {
+ for (i = __virtscr->maxx; i > 128; i-= 128 )
+ memcpy( clp->line + i - 128, buf, sizeof buf );
+ memcpy( clp->line , buf, i * sizeof buf[0] );
#ifdef DEBUG
__CTRACE("-- blanked out: dirty\n");
#endif
Index: scanw.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/scanw.c,v
retrieving revision 1.16
diff -u -r1.16 scanw.c
--- scanw.c 2002/05/26 17:01:38 1.16
+++ scanw.c 2002/06/21 09:35:49
@@ -122,6 +122,6 @@
char buf[1024];
- return (wgetstr(win, buf) == OK ?
+ return (wgetnstr(win, buf, sizeof buf) == OK ?
vsscanf(buf, fmt, ap) : ERR);
}
Index: setterm.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/setterm.c,v
retrieving revision 1.31
diff -u -r1.31 setterm.c
--- setterm.c 2002/01/02 10:38:29 1.31
+++ setterm.c 2002/06/21 09:36:02
@@ -123,9 +123,7 @@
int
_cursesi_setterm(char *type, SCREEN *screen)
{
- static char cm_buff[1024], tc[1024], *tcptr;
int unknown;
- size_t limit;
struct winsize win;
char *p;
@@ -187,11 +185,14 @@
* Test for cursor motion capability.
*
*/
- if (t_goto(NULL, screen->tc_cm, 0, 0, cm_buff, 1023) < 0) {
- screen->CA = 0;
- screen->tc_cm = 0;
- } else
- screen->CA = 1;
+ {
+ char cm_buff[64];
+ if (t_goto(NULL, screen->tc_cm, 0, 0, cm_buff, sizeof cm_buff - 1) < 0) {
+ screen->CA = 0;
+ screen->tc_cm = 0;
+ } else
+ screen->CA = 1;
+ }
/*
* set the pad char, only take the first char of the pc capability
@@ -199,14 +200,19 @@
*/
screen->pad_char = screen->tc_pc ? screen->tc_pc[0] : 0;
+ /* Get full name of terminal */
if (unknown) {
strcpy(screen->ttytype, "dumb");
} else {
- tcptr = tc;
- limit = 1023;
- if (t_getterm(screen->cursesi_genbuf, &tcptr, &limit) < 0)
+ char *tcptr;
+ size_t limit = 0;
+ if (t_getterm(screen->cursesi_genbuf, 0, &limit))
+ return ERR;
+ tcptr = malloc( limit + 1 );
+ if (!tcptr || t_getterm(screen->cursesi_genbuf, &tcptr, 0) < 0)
return ERR;
- __longname(tc, screen->ttytype);
+ __longname(tcptr, screen->ttytype);
+ free( tcptr );
}
/* If no scrolling commands, no quick change. */
@@ -351,7 +357,7 @@
*(tmp + 1) = *(namp + 1);
*vp++ = t_getnum(screen->cursesi_genbuf, tmp);
#ifdef DEBUG
- __CTRACE("%2.2s = %d\n", namp, *vp[-1]);
+ __CTRACE("%2.2s = %d\n", namp, vp[-1]);
#endif
namp += 2;
screen->int_count++;
@@ -367,7 +373,7 @@
*(tmp + 1) = *(namp + 1);
*sp++ = t_agetstr(screen->cursesi_genbuf, tmp);
#ifdef DEBUG
- __CTRACE("%2.2s = %s", namp, *sp[-1] == NULL ? "NULL\n" : "\"");
+ __CTRACE("%2.2s = %s", namp, sp[-1] == NULL ? "NULL\n" : "\"");
if (sp[-1] != NULL) {
for (cp = sp[-1]; *cp; cp++)
__CTRACE("%s", unctrl(*cp));
Index: tscroll.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libcurses/tscroll.c,v
retrieving revision 1.10
diff -u -r1.10 tscroll.c
--- tscroll.c 2002/05/26 17:01:38 1.10
+++ tscroll.c 2002/06/21 09:36:16
@@ -44,6 +44,7 @@
#endif
#endif /* not lint */
+#include <string.h>
#include "curses.h"
#include "curses_private.h"
Index: ../libterm/tgoto.c
===================================================================
RCS file: /cvsroot/basesrc/lib/libterm/tgoto.c,v
retrieving revision 1.19
diff -u -r1.19 tgoto.c
--- tgoto.c 2001/01/09 07:18:50 1.19
+++ tgoto.c 2002/06/21 09:36:44
@@ -114,6 +114,9 @@
int c;
int oncol = 0;
int which = destline;
+ char *buf_lim = buffer + limit;
+ char dig_buf[ 3 * sizeof which ];
+ int k;
/* CM is checked below */
_DIAGASSERT(buffer != NULL);
@@ -128,70 +131,72 @@
if (cp == 0) {
errno = EINVAL;
-toohard:
return -1;
}
added[0] = '\0';
while ((c = *cp++) != '\0') {
- if (c != '%') {
-copy:
+ if (c != '%' || (c = *cp++) == '%') {
*dp++ = c;
- if (dp >= &buffer[limit])
- {
+ if (dp >= buf_lim) {
errno = E2BIG;
- goto toohard;
+ return -1;
}
continue;
}
- switch (c = *cp++) {
+
+ switch (c) {
#ifdef CM_N
case 'n':
destcol ^= 0140;
destline ^= 0140;
- goto setwhich;
+ /* flip oncol here so it doesn't actually change */
+ oncol = 1 - oncol;
+ break;
#endif
case 'd':
- if (which < 10)
- goto one;
- if (which < 100)
- goto two;
- /* FALLTHROUGH */
+ /* Generate digits into temp buffer in reverse order */
+ k = 0;
+ do
+ dig_buf[ k++ ] = which % 10 | '0';
+ while ((which /= 10));
+ if (dp + k >= buf_lim) {
+ errno = E2BIG;
+ return -1;
+ }
+ /* then unwind into callers buffer */
+ do
+ *dp++ = dig_buf[ --k ];
+ while (k);
+ break;
case '3':
if (which >= 1000) {
errno = E2BIG;
- goto toohard;
+ return -1;
}
*dp++ = (which / 100) | '0';
- if (dp >= &buffer[limit]) {
+ if (dp >= buf_lim) {
errno = E2BIG;
- goto toohard;
+ return -1;
}
which %= 100;
/* FALLTHROUGH */
case '2':
-two:
*dp++ = which / 10 | '0';
- if (dp >= &buffer[limit]) {
+ if (dp >= buf_lim) {
errno = E2BIG;
- goto toohard;
+ return -1;
}
-one:
*dp++ = which % 10 | '0';
- if (dp >= &buffer[limit]) {
+ if (dp >= buf_lim) {
errno = E2BIG;
- goto toohard;
+ return -1;
}
+ break;
-swap:
- oncol = 1 - oncol;
-setwhich:
- which = oncol ? destcol : destline;
- continue;
-
#ifdef CM_GT
case '>':
if (which > *cp++)
@@ -237,7 +242,7 @@
if (strlen(added) + strlen(add) >= sizeof(added))
{
errno = E2BIG;
- goto toohard;
+ return -1;
}
(void)strcat(added, add);
@@ -246,16 +251,16 @@
}
}
*dp++ = which;
- if (dp >= &buffer[limit])
+ if (dp >= buf_lim)
{
errno = E2BIG;
- goto toohard;
+ return -1;
}
- goto swap;
+ break;
case 'r':
- oncol = 1;
- goto setwhich;
+ oncol = 0;
+ break;
case 'i':
destcol++;
@@ -263,9 +268,6 @@
which++;
continue;
- case '%':
- goto copy;
-
#ifdef CM_B
case 'B':
which = (which/10 << 4) + which%10;
@@ -280,13 +282,18 @@
default:
errno = EINVAL;
- goto toohard;
+ return -1;
}
+
+ /* flip to other number... */
+ oncol = 1 - oncol;
+ which = oncol ? destcol : destline;
}
- if (dp + strlen(added) >= &buffer[limit])
+
+ if (dp + strlen(added) >= buf_lim)
{
errno = E2BIG;
- goto toohard;
+ return -1;
}
(void)strcpy(dp, added);
>Release-Note:
>Audit-Trail:
>Unformatted: