Bug in csh (history, "!a%100s"). Report and Fix.

Michael Greim greim at sbsvax.UUCP
Mon Jul 3 23:46:20 AEST 1989


In article <192 at dg.dg.com> in comp.bugs.sys5 rec at dg.dg.com (Robert Cousins)
reported a bug in csh.
Here is a description of it and a fix.

Absorb, apply and enjoy,
	-mg

Symptoms:

>I have found that there are several basic bugs in the Cshell history
>mechanism which can be quite problematic.  These were originally called
>to my attention by the work of a couple of researchers at the U of W in
>Madison.  Bug 1:
>
>	!a%999999999f
>
>which causes 999999999 spaces to be output to the screen.  (Fewer on
>16 bit machines.)  It seems that the error message in the history
>module goes through the first argument of a printf() call and can be
>interpreted as a format.  A second bug, which happens on fewer machines
>takes place with:
>
>	!a%f%f
>
>which can cause csh to dump core from a floating point error.  
[...]

Diagnosis:

	When printing an error message the csh function "error" passes
	its first argument to its printf. If this string contains a "%",
	printf tries to evaluate the following as a format accessing its
	argument list, which is empty quite probably. This will cause
	unpredictable behaviour, like core dumps, strange numbers, ...

Therapy:
	Apply the following context diff to your source of 43BSD csh.
	This fix works like this:
	- in error only a string ending in "@" is passed as format string
		to printf.
	- only internal error messages needing arguments need format specifiers,
		so I add a trailing "@" to any such message
	- any string not ending with "@" is passed to printf with "%s" as first
		parameter.

*** sh.dol.c.old	Mon Jul  3 15:18:22 1989
--- sh.dol.c	Mon Jul  3 15:12:39 1989
***************
*** 159,165
  			if (c == c1)
  				break;
  			if (c == '\n' || c == DEOF)
! 				error("Unmatched %c", c1);
  			if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
  				--wp, ++i;
  			if (--i <= 0)

--- 159,165 -----
  			if (c == c1)
  				break;
  			if (c == '\n' || c == DEOF)
! 				error("Unmatched %c@", c1);		/* mg 3-jul-89 */
  			if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
  				--wp, ++i;
  			if (--i <= 0)
*** sh.err.c.old	Mon Jul  3 15:18:36 1989
--- sh.err.c	Mon Jul  3 15:16:10 1989
***************
*** 34,39
  {
  	register char **v;
  	register char *ep;
  
  	/*
  	 * Must flush before we print as we wish output before the error

--- 34,40 -----
  {
  	register char **v;
  	register char *ep;
+ 	register int i;		/* mg 3-jul-89 */
  
  	/*
  	 * Must flush before we print as we wish output before the error
***************
*** 53,58
  	/*
  	 * A zero arguments causes no printing, else print
  	 * an error diagnostic here.
  	 */
  	if (s)
  		printf(s, arg), printf(".\n");

--- 54,65 -----
  	/*
  	 * A zero arguments causes no printing, else print
  	 * an error diagnostic here.
+ 	 * mg 3-jul-89 : If error is called with s containing a part of
+ 	 * the users input, and if this contains a "%", printf tries to evaluate
+ 	 * this as a format reference. Try : "!a%100s".
+ 	 * I fixed this: internal error messages which should be processed as
+ 	 * format strings, will end in "@", all else is NOT interpreted as a
+ 	 * format string.
  	 */
  	if (s) {
  		i = strlen (s) - 1;
***************
*** 54,61
  	 * A zero arguments causes no printing, else print
  	 * an error diagnostic here.
  	 */
! 	if (s)
! 		printf(s, arg), printf(".\n");
  
  	didfds = 0;		/* Forget about 0,1,2 */
  	if ((ep = err) && errspl) {

--- 61,74 -----
  	 * format strings, will end in "@", all else is NOT interpreted as a
  	 * format string.
  	 */
! 	if (s) {
! 		i = strlen (s) - 1;
! 		if (s[i] == '@') {
! 			s[i] = '\0';
! 			printf(s, arg), printf(".\n");
! 		} else
! 			printf("%s\n", s);
! 	}
  
  	didfds = 0;		/* Forget about 0,1,2 */
  	if ((ep = err) && errspl) {
*** sh.func.c.old	Mon Jul  3 15:18:55 1989
--- sh.func.c	Mon Jul  3 15:12:55 1989
***************
*** 1004,1010
  	while (*cp && *cp == *str)
  		cp++, str++;
  	if (*cp)
! 		error("Bad scaling; did you mean ``%s''?", str0);
  }
  
  plim(lp, hard)

--- 1004,1010 -----
  	while (*cp && *cp == *str)
  		cp++, str++;
  	if (*cp)
! 		error("Bad scaling; did you mean ``%s''?@", str0); /* mg 3-jul-89 */
  }
  
  plim(lp, hard)
*** sh.glob.c.old	Mon Jul  3 15:19:06 1989
--- sh.glob.c	Mon Jul  3 15:13:10 1989
***************
*** 139,145
  			if (gpathp != gpath + 1) {
  				*gpathp = 0;
  				if (gethdir(gpath + 1))
! 					error("Unknown user: %s", gpath + 1);
  				(void) strcpy(gpath, gpath + 1);
  			} else
  				(void) strcpy(gpath, value("home"));

--- 139,145 -----
  			if (gpathp != gpath + 1) {
  				*gpathp = 0;
  				if (gethdir(gpath + 1))
! 					error("Unknown user: %s@", gpath + 1); /* mg 3-jul-89 */
  				(void) strcpy(gpath, gpath + 1);
  			} else
  				(void) strcpy(gpath, value("home"));
*** sh.sem.c.old	Mon Jul  3 15:19:21 1989
--- sh.sem.c	Mon Jul  3 15:13:22 1989
***************
*** 401,405
  		return;
  	if ((stb.st_mode & S_IFMT) == S_IFCHR)
  		return;
! 	error("%s: File exists", cp);
  }

--- 401,405 -----
  		return;
  	if ((stb.st_mode & S_IFMT) == S_IFCHR)
  		return;
! 	error("%s: File exists@", cp);	/* mg 3-jul-89 */
  }
-- 
Michael Greim    Email : greim at sbsvax.informatik.uni-saarland.dbp.de
                 or    : ...!uunet!unido!sbsvax!greim
# include <disclaimers/std.h>



More information about the Comp.sources.bugs mailing list