what is going on here ???

ab at unido.UUCP ab at unido.UUCP
Thu Jun 27 04:29:00 AEST 1985


> If you are running 4.2, look at the following short program and
> guess what it will do. Then compile and run it and find out
> what it really does. 
> 
> Try to explain its behavior!! (- Is it a bug in 4.2 ??? :-) )

Here is the solution to the previously posted 'puzzle':

It is a nice method to terminate all running shells which share
the controlling terminal. -- And it is an example of unexpected
side-effects, caused by a relatively small and hidden bug.

The bug was produced by a typo in the statement which opens /dev/kmem.
Notice the wrong positions of the parentheses:

>       if((kmem = open ("/dev/kmem", 0) < 0)) {

kmem stays 0 and the lseek on kmem is actually done on stdin !!!

The lseek takes the read/write-pointer of the terminal-channel to
an unaccessible position and all following reads or writes of any
process from/to the terminal will fail. This will cause all shells
to terminate! (See also the source below.)

Andreas Bormann                 ab at unido.UUCP
University of Dortmund          N 51 29' 05"   E 07 24' 42"
West Germany

--- CUT HERE ---------- CUT HERE ---------- CUT HERE ---------- CUT HERE ----
#include <nlist.h>

#define NAMELIST "/vmunix"

struct nlist    avenrun[] = {
      { "_avenrun" },
      { "" }
};

main()
{
	register int    kmem;
	double  avg[3];

	if((kmem = open ("/dev/kmem", 0) < 0)) { /* HERE's THE BUG !!! */
/*
 * If the open-call succeeds, it will return a positive filedescriptor
 * and kmem will be 0 because the positive descriptor isn't less than 0.
 *
 * This is the corrected statement:
 *  
 *      if((kmem = open ("/dev/kmem", 0)) < 0) {
 */
		printf("Cannot open kmem\n");    
		exit(1);
	}
	nlist(NAMELIST, avenrun);
	if(avenrun[0].n_type == 0) {
		printf("Cannot find avenrun\n");
		exit(1);
	}
/*
 * Remember: kmem == 0 !!
 * avenrun[0].n_value is something like -2147230472,
 * so the lseek will seek the read/write-pointer ON THE STDIN to
 * an unaccessible position.
 */
	lseek(kmem, (long) avenrun[0].n_value, 0);
/*
 * All successive reads by all processes which share the terminal
 * will now return an error (-1) and the parent shells will terminate!!!
 */
	read(kmem, (char *) avg, 3 * sizeof (double));
	printf("Load average: %f %f %f\n", avg[0], avg[1], avg[2]);
	exit(0);
}



More information about the Comp.unix mailing list