olson@fortune.UUCP (Dave Olson) (12/07/84)
There is a severe bug in the V7 exece() in sys1.c, IF it has been modified to use bdwrite(), without adding the code at the end of this article (or equivalent code). (It is ok in S5 and 4.1BSD, and possibly others). The problem definitely occurs if you have modified it to use bdwrite(); if it is stock and uses bawrite(), the problem might still occur, but probably will not (and the fix below will not help). The problem occurs when getxfile() fails. (This most frequently happens with shell scripts on our system.) In this case, the accumulated argument list and environment remain in the buffer cache (due to the bdwrite(bp) ). Unfortunately, the swap space that was allocated is freed. Since bp is 0'ed just before the call to getxfile(), you won't even release the latest buffer used. Typically, exece() ends up getting the same swap blocks on each call (or the write actually occurs and the buffer is released). In this case, there is no problem. However, if the system becomes loaded enough that the swap space is reallocated to another process (and the process swaps) BEFORE the write completes, the swapped process will be partially overwritten. If the portion overwritten happens to be the upage, disastrous things can happen. (If the overwrite is in the text, data, or stack segment of a process, bizzare behaviour may occur IF the overwritten info is referenced by the process after it is swapped in.) If you are running on a 68000 machine, you will typically get a double bus error in resume(). You therefore get a 'silent hang' where the CPU simply shuts down. I'm not sure what would happen on other machines. With the modification to use bdwrite(), instead of bawrite() in order to reduce disk i/o, the problem is much more severe, as the chance of the write completing after the swap space is reallocated is much greater. The fix is relatively simple: Change the lines: if (getxfile(ip, nc) || u.u_error) goto bad; To: if(getxfile(ip, nc) || u.u_error) { for(c = 0; c < nc; c += BSIZE) { bp = (incore(swapdev, dbtofsb(bno+swplo)+(c>>BSHIFT))) ? bread(swapdev,dbtofsb(bno+swplo)+(c>>BSHIFT)) : 0; if(bp) { /* if the buffer has not yet been written */ bp->b_flags |= B_AGE; /* throw it away */ bp->b_flags &= ~B_DELWRI; /* cancel the I/O */ brelse(bp); bp = 0; /* prevent brelse() at bad: */ } } goto bad; } Dave Olson at Fortune Systems. UUCP: {ihnp4,ucbvax!dual}!fortune!olson