[net.bugs.4bsd] Bug in curses package

per@chalmers.UUCP (05/17/84)

Subject:
	Curses package sometimes dump core.
Index:
	usr.lib/libcurses 4.2BSD

Description:
	Screen oriented programs that worked on terminals like vt100,
	caused 'segmentation fault' when run on facit 4440. (Swedish
	terminal, 72 lines by 80 columns). 

	The problem was caused by a loop like:
	    while (*cp++ == *dp++)
		;
	(Now I start guessing)
	The reason this hasn't been detected before is that the curses
	package does a lot of calloc()/free().
	The amount of space used by 'curscr' and 'stdscr', allocated
	by initscr(), is less than what is used during other
	initialiations. The result is that "above" 'curscr' and
	'stdscr' there is memory that no longer is initialized to 0.
	But this is only true if 'stdscr' and 'curscr' are small
	enough. That isn't the case when the screen is 72x80.

Repeat-By:
	/* start of test.c */
	#include <curses.h>

	#define	FMT	"libcurses test, line %d"

	main(argc, argv)
	{
	    register i;

	    /* simulate 72x80 screen (facit 4440) */
	    LINES = 72;
	    COLS = 80;

	    initscr();

	    for (i = 0; i < 15; i++)
		mvprintw(i, 5, FMT, i+1);

	    move(20,1);
	    refresh();
	    endwin();
	}
	/* end of test.c */

	compile with:
		cc test.c -lcurses -ltermcap
	run by:
		a.out
Fix:

	Diff listing (edited) follows. Line numbers are not correct
	due to other minor changes.

	*** refresh.c.old	Wed May 16 23:48:53 1984
	--- refresh.c.new	Sat May 12 00:17:46 1984
	***************
	*** 235,243
				lx = wx + win->_begx;
			}
			else if (wx < lch)
	! 			while (*nsp == *csp) {
	  				nsp++;
	  				if (!curwin)
						csp++;
					++wx;
				}

	--- 240,248 -----
				lx = wx + win->_begx;
			}
			else if (wx < lch)
	! 			while (*nsp == *csp && wx < lch) {
					nsp++;
					if (!curwin)
						csp++;
					++wx;
				}

	    Per Westerlund
	    Dept of Comp Sci
	    Chalmers U of Tech
	    S-412 96 Gothenburg
	    SWEDEN

laman@sdcsvax.UUCP (Mike Laman) (05/22/84)

Yes, that is a bug.  I posted the very same fix a good number of months ago.
On systems that it doesn't dump core, it does MUCH more looking than is needed!
The problem is that it is supposed to walk down JUST the ONE line; instead
it walks down the entire window.  Think about it and you will see A LOT of
time can be wasted.

Since this fix is being posted I thought I would repost the set of fixes I
put over a good while ago.  My apologies to those that have seen these before.

Beginning of previous bug fix list message posted earlier...

Some one asked for bug fixes to 4.1 curses.  All the following should be
relevent.  I am posting this synopsis to answer his request and since
San Diego was cut off for about a month, others may find it interesting
(otherwise I would have just replied to him).  I apologize to those in the
San Diego area who has seen parts of this for the fourth time.  Strange
though, the request is from the San Diego area....

I have included two messages that I sent out on bug fixes.  They are at the
end.  Several other fixes are as follows:

1. Add touchwin(win); to the end of winsertln().
2. If your loop in wgetstr() has a semicolon on the end which blocks off the
   pointer incrmentation as implied by the indentation style, reomve that
   semi colon:

   while(some ugly god awful expression);
	++str;			        ^
				        |
				        |
				    Dumb huh
3. If your first loop in wdeleteln() looks like:

				:
				:
				:
	for (y = win->_cury; y < win->_maxy - 2; y++) {
				:
				:
				:

   This doesn't get the last line of the given window.  Change it to the
   following:

				:
				:
				:
	for (y = win->_cury; y < win->_maxy - 1; y++) {
				:
				:
				:

Here are the other two fixes which I have previously posted on the network.

There is a bug in wdeleteln().  This bug is in the curses library distributed
over net.sources, and in the 4.2 BSD distribution (that sdcsvax received
at least).

Even though the last line of the window gets cleared internally, its "refresh"
image may not.  The fix is simple.  Add the following two lines to the end
of the wdeleteln() routine.

	win->_firstch[win->_maxy-1] = 0;
	win->_lastch[win->_maxy-1] = win->_maxx - 1;

Now wrefresh() will look at the entire line.

I have enclosed a little program that will show you if you have the bug.  Just
compile it with you curses library (termlib too) and run it.

#include	<curses.h>

main() {
	register i;

	initscr();
	mvaddstr(0, 20, "This program will delete line #5 after");
	mvaddstr(1, 20, "writing the line number for each line.");
	for(i = 0; i < LINES; ++i)
		mvprintw(i, 0, "Line #%d", i);
	refresh();
	addstr("     You have the bug if the BOTTOM line is not COMPLETELY blank!");
	move(5, 0);
	deleteln();
	move(LINES - 3, 0);
	refresh();
	endwin();
}

And the other:

    The following bug is in the curses library distributed over net.sources,
and in the 4.2 BSD distribution (that sdcsvax received at least).

    The bug is in makech() (in refresh.c).  makech() gets called to give
output for the given LINE (hint hint).  It is interesting that this bug
managed to get out.  Here is the offending code (the simple fix follows).

			:
			:
			:
		else if (wx < lch)
			while (*nsp == *csp) {
				nsp++;
				if (!curwin)
					csp++;
				++wx;
			}
		else
			:
			:
			:

I wrote a program that added '*' to (0, 0) on stdscr then a refresh().
wx ended up with a value of over 3000!  That loop walked down the line
and the next, ... (all the way down the window!).  The following code
is the fix.  Notice that the ++wx looks just perfect.  It really makes one
think "they" thought of it, but merely forgot to add the test.

			:
			:
			:
		else if (wx < lch)
			while (*nsp == *csp && wx <= lch) {
				nsp++;
				if (!curwin)
					csp++;
				++wx;
			}
		else
			:
			:
			:

--- End of previous message


			Mike Laman
			UUCP: {ucbvax,philabs,sdccsu3,sdcsla}!sdcsvax!laman

lorien@dartvax.UUCP (Lorien Y. Pratt) (05/23/84)

When I saw Mike Laman's bug fix for lack of scrolling in Curses,
I thought it was just the thing to help us avoid an anticipated need to
hack our C program to get around curses so that scrolling worked at a
decent rate.  Problem is, the bug fixes he proposes *don't work* at our
(4.2bsd) installation.  As it's not documented in the curses manual,
perhaps I simply don't know how to get the screen to scroll.

All I want to do is to display pages of data to users without clearing
the screen between pages but rather to begin scrolling in a new page
when they press some character indicating they want to go on.

Here's the program I wrote to test if introducing Laymen's bug
fix worked (only #1 on his list was not already fixed).  *Tell me* how
to modify Curses so that it uses the built-in scrolling facilities of
my terminal instead of redrawing it all.

/* Start of curtest.c */
#include<curses.h>
#include <stdio.h>

main()
{
char temp[256];
char t;
int i;

initscr();
scrollok( stdscr, TRUE );

for(i=0;i<24;i++)
{
  sprintf( temp, "This        is        the        line   numbered   %d", i );
  mvaddstr( i, 0, temp );
  refresh();
}
t = getch();
for(i=24;i<50;i++)
{
  scroll( stdscr );
  sprintf( temp, "Line %d", i );
  mvaddstr( 23, 0, temp );
  refresh();
}
endwin();
}
/* End of curtest.c */

Compile by:
  cc curtest.c -lcurses -ltermlib
Run by:
  a.out

laman@sdcsvax.UUCP (05/25/84)

curses(foiled, again);

I tried sending this message out once, but I got a message from "inews"
about being locked out.  So I'll again.

In reply to "lorien"'s (sorry, but no personal name was given) problem
of windows not scrolling properly, I tried his/her program that was included
in his reply message.  It worked fine on "sdcsvax"!  It did NOT erase the
screen after the initial screen erasure.  It scrolled the lines perfectly.
That is what I understood from his following paragraph (and his code) that
"lorien" wants.

"...  All I want to do is to display pages of data to users without clearing
the screen between pages but rather to begin scrolling in a new page
when they press some character indicating they want to go on. ..."

I am really puzzled why "sdscvax"'s library works fine and yours doesn't.

If the problem that you are having is ONLY with it clearing the screen
after a scroll has been done, I would suggest checking your clear flag in
your WINDOW structure to see if it is somehow getting turned on.
I would also check the second (by what I see) "if" in wrefresh() to see if this
is the code that is causing the (incorrect) clearing of your screen between
refreshes.

How does the program work on other 4.2 BSD systems?  Anyone else try his/her
program?

			Mike Laman
			UUCP: {ucbvax,philabs,sdccsu3,sdcsla}!sdcsvax!laman

P.S.  I should also mention that there seems to be a bug in scrolling windows
      that are smaller than the "standard screen".  I saw this in the
      System V.2 terminfo/curses sources and plan to look into it when time
      allows.  I seem to remember bumping into a problem like that once when
      I was tinkering around with a program of mine.