ab@unido.UUCP (05/30/85)
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 ??? :-) ) Andreas -- Andreas Bormann ab@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)) { printf("Cannot open kmem\n"); exit(1); } nlist(NAMELIST, avenrun); if(avenrun[0].n_type == 0) { printf("Cannot find avenrun\n"); exit(1); } lseek(kmem, (long) avenrun[0].n_value, 0); read(kmem, (char *) avg, 3 * sizeof (double)); printf("Load average: %f %f %f\n", avg[0], avg[1], avg[2]); exit(0); }
chris@umcp-cs.UUCP (Chris Torek) (06/20/85)
The last element of a struct nlist array as handed to nlist() should be {0} (i.e., a null pointer in the name field), not {""} (which is a null string in the name field, which will make nlist() do crazy things). -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland
henry@utzoo.UUCP (Henry Spencer) (06/24/85)
> The last element of a struct nlist array as handed to nlist() should > be {0} (i.e., a null pointer in the name field), not {""} (which > is a null string in the name field, which will make nlist() do > crazy things). We have here a problem that dates back to the vague and obscure wording of the V7 nlist(3) manual page. V7 really *does* want an empty string for that initializer, because the array element is "char[8]", not "char *". Later Unixes and non-Unixes have done things differently; some of them may not have realized this, because the manual page is so vague. Fortuitously, "{0}" is legal and correct under either interpretation, and hence should be preferred. -- Henry Spencer @ U of Toronto Zoology {allegra,ihnp4,linus,decvax}!utzoo!henry
ab@unido.UUCP (06/26/85)
> 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@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); }