From: guy@sun.uucp (Guy Harris) Newsgroups: net.unix-wizards,net.bugs.v7,net.bugs.4bsd,net.bugs.usg Subject: "sh" assumes you can restart faulting instructions Message-ID: <4082@sun.uucp> Date: Wed, 11-Jun-86 19:39:40 EDT Article-I.D.: sun.4082 Posted: Wed Jun 11 19:39:40 1986 Organization: Sun Microsystems, Inc. "sh" manages its data space by an unusual technique; it catches SIGSEGV and generally pretends it has an infinite data space. If it gets a SIGSEGV fault, it grows its data space to include the area it wanted to use, and returns from the SIGSEGV handler under the assumption that this will reexecute the faulting instruction. 'Tain't so on all machines. Here are a set of fixes to the S5R2 shell which seem to have cleared the problem up there. No guarantee that they are sufficient (I think they're all necessary, though). This version also doesn't catch SIGSEGV, so at least if they *aren't* sufficient you'll find out when the shell drops core.... They have been tested, including a test on a vanilla S5 machine; said machine permits you to return from SIGSEGV handlers and restart the faulting instruction (to the best of my knowledge), and was used for a quick performance test - namely, saying "echo `cat [ab]*.c`" in the shell's source directory. No performance difference between the unfixed and fixed versions was noticed. Also: a few "lint" fixes and similar cleanups a null pointer dereference fix to the "ulimit" command a fix to the "is this a restricted shell" problem - it now only thinks it's a restricted shell if its "simple name" was "rsh" or "-rsh", not if its simple name contained an "r" anywhere (after all, it's only a shell, not an oyster) a fix to the "not an identifier" problem - environment strings which aren't in the "proper" format are ignored, and don't cause the string to barf when starting up Some of these came from the version of the shell that comes with the BRL S5 package for 4.2BSD. diff -c /archbeluga/s5r2/usr/src/cmd/sh/args.c ./args.c *** /archbeluga/s5r2/usr/src/cmd/sh/args.c Wed Sep 7 10:34:00 1983 --- ./args.c Mon May 19 13:07:51 1986 *************** *** 9,15 **** #include "defs.h" static struct dolnod *copyargs(); ! static struct dolnod *freedolh(); extern struct dolnod *freeargs(); static struct dolnod *dolh; --- 9,15 ---- #include "defs.h" static struct dolnod *copyargs(); ! static void freedolh(); extern struct dolnod *freeargs(); static struct dolnod *dolh; *************** *** 180,186 **** } ! static struct dolnod * freedolh() { register char **argp; --- 180,186 ---- } ! static void freedolh() { register char **argp; *************** *** 307,310 **** } return(dolh); } - --- 307,309 ---- diff -c /archbeluga/s5r2/usr/src/cmd/sh/blok.c ./blok.c *** /archbeluga/s5r2/usr/src/cmd/sh/blok.c Wed Sep 7 10:34:00 1983 --- ./blok.c Mon May 19 13:07:51 1986 *************** *** 72,77 **** --- 72,79 ---- register char *rndstak; register struct blk *blokstak; + if (staktop >= brkend) + growstak(staktop); pushstak(0); rndstak = (char *)round(staktop, BYTESPERWORD); blokstak = (struct blk *)(stakbas) - 1; *************** *** 84,95 **** reqd &= ~(brkincr - 1); blokp = bloktop; bloktop = bloktop->word = (struct blk *)(Rcheat(bloktop) + reqd); bloktop->word = (struct blk *)(brkbegin + 1); { register char *stakadr = (char *)(bloktop + 2); if (stakbot != staktop) ! staktop = movstr(stakbot, stakadr); else staktop = stakadr; --- 86,102 ---- reqd &= ~(brkincr - 1); blokp = bloktop; bloktop = bloktop->word = (struct blk *)(Rcheat(bloktop) + reqd); + if ((char *)&bloktop->word > brkend) + { + if (setbrk((unsigned)((char *)(&bloktop->word) - brkend)) == (char *)-1) + error(nospace); + } bloktop->word = (struct blk *)(brkbegin + 1); { register char *stakadr = (char *)(bloktop + 2); if (stakbot != staktop) ! staktop = movstrstak(stakbot, stakadr); else staktop = stakadr; diff -c /archbeluga/s5r2/usr/src/cmd/sh/defs.h ./defs.h *** /archbeluga/s5r2/usr/src/cmd/sh/defs.h Sat Oct 15 16:40:07 1983 --- ./defs.h Mon May 19 13:07:53 1986 *************** *** 121,130 **** extern char **scan(); extern char *mactrim(); extern char *macro(); - extern char *execs(); - extern char *copyto(); extern int exname(); - extern char *staknam(); extern int printnam(); extern int printro(); extern int printexp(); --- 121,127 ---- diff -c /archbeluga/s5r2/usr/src/cmd/sh/expand.c ./expand.c *** /archbeluga/s5r2/usr/src/cmd/sh/expand.c Wed Sep 7 10:34:01 1983 --- ./expand.c Mon May 19 13:07:54 1986 *************** *** 335,340 **** --- 335,342 ---- s1 = as1; while (c = *s1++) { + if (s2 >= brkend) + growstak(s2); if ((c &= STRIP) == 0) { *s2++ = '/'; *************** *** 343,353 **** *s2++ = c; } s1 = as2; ! while (*s2 = *s1++) s2++; if (s1 = as3) { *s2++ = '/'; while (*s2++ = *++s1); } makearg(endstak(s2)); --- 345,368 ---- *s2++ = c; } s1 = as2; ! for (;;) ! { ! if (s2 >= brkend) ! growstak(s2); ! if ((*s2 = *s1++) == 0) ! break; s2++; + } if (s1 = as3) { + if (s2 >= brkend) + growstak(s2); *s2++ = '/'; + do + { + if (s2 >= brkend) + growstak(s2); + } while (*s2++ = *++s1); } makearg(endstak(s2)); *************** *** 359,363 **** args->argnxt = gchain; gchain = args; } - - --- 374,376 ---- diff -c /archbeluga/s5r2/usr/src/cmd/sh/fault.c ./fault.c *** /archbeluga/s5r2/usr/src/cmd/sh/fault.c Sat Oct 15 16:40:07 1983 --- ./fault.c Fri Jun 6 23:39:22 1986 *************** *** 35,41 **** 0, /* power fail */ }; ! int (*(sigval[]))() = { 0, done, --- 35,41 ---- 0, /* power fail */ }; ! int (*(sigval[MAXTRAP]))() = { 0, done, *************** *** 56,67 **** done, done, done, - done }; /* ======== fault handling routines ======== */ fault(sig) register int sig; { --- 56,67 ---- done, done, done, }; /* ======== fault handling routines ======== */ + int fault(sig) register int sig; { *************** *** 68,80 **** register int flag; signal(sig, fault); ! if (sig == SIGSEGV) { - if (setbrk(brkincr) == -1) - error(nospace); - } - else if (sig == SIGALRM) - { if (flags & waiting) done(); } --- 68,75 ---- register int flag; signal(sig, fault); ! if (sig == SIGALRM) { if (flags & waiting) done(); } *************** *** 99,105 **** setsig(SIGEMT); setsig(SIGFPE); setsig(SIGBUS); - signal(SIGSEGV, fault); setsig(SIGSYS); setsig(SIGPIPE); setsig(SIGALRM); --- 94,99 ---- *************** *** 109,144 **** } ignsig(n) { ! register int s, i; ! if ((i = n) == SIGSEGV) { ! clrsig(i); ! failed(badtrap, "cannot trap 11"); } - else if ((s = (signal(i, SIG_IGN) == SIG_IGN)) == 0) - { - trapflg[i] |= SIGMOD; - } return(s); } getsig(n) { ! register int i; ! ! if (trapflg[i = n] & SIGMOD || ignsig(i) == 0) ! signal(i, fault); } setsig(n) { ! register int i; ! ! if (ignsig(i = n) == 0) ! signal(i, sigval[i]); } oldsigs() --- 103,132 ---- } ignsig(n) + register int n; { ! register int s; ! if ((s = (signal(n, SIG_IGN) == SIG_IGN)) == 0) { ! trapflg[n] |= SIGMOD; } return(s); } getsig(n) + register int n; { ! if (trapflg[n] & SIGMOD || ignsig(n) == 0) ! signal(n, fault); } setsig(n) + register int n; { ! if (ignsig(n) == 0) ! signal(n, sigval[n]); } oldsigs() diff -c /archbeluga/s5r2/usr/src/cmd/sh/io.c ./io.c *** /archbeluga/s5r2/usr/src/cmd/sh/io.c Wed Sep 7 10:34:02 1983 --- ./io.c Mon May 19 13:07:55 1986 *************** *** 214,219 **** --- 214,221 ---- while (!eolchar(c)) { + if (clinep >= brkend) + growstak(clinep); *clinep++ = c; c = readc(); } *************** *** 227,237 **** --- 229,243 ---- while (!eolchar(c)) { + if (clinep >= brkend) + growstak(clinep); *clinep++ = c; c = nextc(*ends); } } + if (clinep >= brkend) + growstak(clinep); *clinep = 0; if (eof || eq(cline, ends)) { *************** *** 240,246 **** --- 246,256 ---- break; } else + { + if (clinep >= brkend) + growstak(clinep); *clinep++ = NL; + } if ((i = clinep - start) < CPYSIZ) cline = clinep; diff -c /archbeluga/s5r2/usr/src/cmd/sh/macro.c ./macro.c *** /archbeluga/s5r2/usr/src/cmd/sh/macro.c Sat Oct 15 16:40:08 1983 --- ./macro.c Mon May 19 13:07:56 1986 *************** *** 14,20 **** ! static char * copyto(endch) register char endch; { --- 14,20 ---- ! static void copyto(endch) register char endch; { *************** *** 21,27 **** --- 21,33 ---- register char c; while ((c = getch(endch)) != endch && c) + { + if (staktop >= brkend) + growstak(staktop); pushstak(c | quote); + } + if (staktop >= brkend) + growstak(staktop); zerostak(); if (c != endch) error(badsub); *************** *** 88,96 **** --- 94,106 ---- argp = (char *)relstak(); while (alphanum(c)) { + if (staktop >= brkend) + growstak(staktop); pushstak(c); c = readc(); } + if (staktop >= brkend) + growstak(staktop); zerostak(); n = lookup(absstak(argp)); setstak(argp); *************** *** 169,179 **** --- 179,197 ---- for (;;) { if (*v == 0 && quote) + { + if (staktop >= brkend) + growstak(staktop); pushstak(QUOTE); + } else { while (c = *v++) + { + if (staktop >= brkend) + growstak(staktop); pushstak(c | quote); + } } if (dolg == 0 || (++dolg > dolc)) *************** *** 181,186 **** --- 199,206 ---- else { v = dolv[dolg]; + if (staktop >= brkend) + growstak(staktop); pushstak(tmp); } } *************** *** 244,250 **** --- 264,274 ---- copyto(0); pop(); if (quoted && (stakbot == staktop)) + { + if (staktop >= brkend) + growstak(staktop); pushstak(QUOTE); + } /* * above is the fix for *'.c' bug */ *************** *** 265,271 **** --- 289,299 ---- usestak(); while ((d = readc()) != SQUOTE && d) + { + if (staktop >= brkend) + growstak(staktop); pushstak(d); + } { register char *argc; *************** *** 283,295 **** */ chkpipe(pv); initf(pv[INPIPE]); ! execute(t, 0, (int)(flags & errflg), 0, pv); close(pv[OTPIPE]); } tdystak(savptr); staktop = movstr(savptr, stakbot); while (d = readc()) pushstak(d | quote); await(0, 0); while (stakbot != staktop) { --- 311,327 ---- */ chkpipe(pv); initf(pv[INPIPE]); ! execute(t, 0, (int)(flags & errflg), (int *)0, pv); close(pv[OTPIPE]); } tdystak(savptr); staktop = movstr(savptr, stakbot); while (d = readc()) + { + if (staktop >= brkend) + growstak(staktop); pushstak(d | quote); + } await(0, 0); while (stakbot != staktop) { *************** *** 318,323 **** --- 350,357 ---- */ while (c = (getch(DQUOTE) & STRIP)) { + if (staktop >= brkend) + growstak(staktop); pushstak(c); if (--count == 0) { diff -c /archbeluga/s5r2/usr/src/cmd/sh/main.c ./main.c *** /archbeluga/s5r2/usr/src/cmd/sh/main.c Sat Oct 15 16:40:08 1983 --- ./main.c Mon May 19 13:07:56 1986 *************** *** 43,48 **** --- 43,49 ---- register int rflag = ttyflg; int rsflag = 1; /* local restricted flag */ struct namnod *n; + char *sim; stdsigs(); *************** *** 77,83 **** #ifndef RES ! if (c > 0 && any('r', simple(*v))) rflag = 0; #endif --- 78,85 ---- #ifndef RES ! /* smarter check for restricted shell, courtesy of BRL */ ! if (c > 0 && (eq(sim = simple(*v), "rsh") || eq(sim, "-rsh"))) rflag = 0; #endif *************** *** 137,152 **** dfault(&mchknod, MAILCHECK); mailchk = stoi(mchknod.namval); ! if ((beenhere++) == FALSE) /* ? profile */ { if (*(simple(cmdadr)) == '-') { /* system profile */ #ifndef RES - if ((input = pathopen(nullstr, sysprofile)) >= 0) exfile(rflag); /* file exists */ - #endif if ((input = pathopen(nullstr, profile)) >= 0) --- 139,153 ---- dfault(&mchknod, MAILCHECK); mailchk = stoi(mchknod.namval); ! if (beenhere == FALSE) /* ? profile */ { + beenhere = TRUE; if (*(simple(cmdadr)) == '-') { /* system profile */ #ifndef RES if ((input = pathopen(nullstr, sysprofile)) >= 0) exfile(rflag); /* file exists */ #endif if ((input = pathopen(nullstr, profile)) >= 0) *************** *** 287,293 **** flags &= ~waiting; ! execute(cmd(NL, MTFLG), 0, eflag); eof |= (flags & oneflg); } } --- 288,294 ---- flags &= ~waiting; ! execute(cmd(NL, MTFLG), 0, eflag, (int *)0, (int *)0); eof |= (flags & oneflg); } } diff -c /archbeluga/s5r2/usr/src/cmd/sh/name.c ./name.c *** /archbeluga/s5r2/usr/src/cmd/sh/name.c Wed Sep 7 10:34:04 1983 --- ./name.c Mon May 19 13:07:57 1986 *************** *** 158,164 **** return; } } ! failed(argi, notid); } replace(a, v) --- 158,165 ---- return; } } ! if (!(xp & N_ENVNAM)) ! failed(argi, notid); } replace(a, v) *************** *** 228,233 **** --- 229,235 ---- readvar(names) char **names; { + extern long lseek(); struct fileblk fb; register struct fileblk *f = &fb; register char c; *************** *** 250,255 **** --- 252,259 ---- { if ((*names && any(c, ifsnod.namval)) || eolchar(c)) { + if (staktop >= brkend) + growstak(staktop); zerostak(); assign(n, absstak(rel)); setstak(rel); *************** *** 270,275 **** --- 274,281 ---- } else { + if (staktop >= brkend) + growstak(staktop); pushstak(c); c = nextc(0); *************** *** 427,435 **** { register char *p; ! p = movstr(n->namid, staktop); ! p = movstr("=", p); ! p = movstr(n->namval, p); return(getstak(p + 1 - (char *)(stakbot))); } --- 433,441 ---- { register char *p; ! p = movstrstak(n->namid, staktop); ! p = movstrstak("=", p); ! p = movstrstak(n->namval, p); return(getstak(p + 1 - (char *)(stakbot))); } *************** *** 499,504 **** --- 505,511 ---- static char **argnam; + static pushnam(n) struct namnod *n; { diff -c /archbeluga/s5r2/usr/src/cmd/sh/service.c ./service.c *** /archbeluga/s5r2/usr/src/cmd/sh/service.c Sat Oct 15 16:40:08 1983 --- ./service.c Mon May 19 13:07:58 1986 *************** *** 24,29 **** --- 24,30 ---- struct ionod *iop; int save; { + extern long lseek(); register char *ion; register int iof, fd; int ioufd; *************** *** 147,161 **** register char *argp = locstak(); while (*scanp && *scanp != COLON) *argp++ = *scanp++; if (scanp != path) *argp++ = '/'; if (*scanp == COLON) scanp++; path = (*scanp ? scanp : 0); scanp = name; ! while ((*argp++ = *scanp++)) ! ; return(path); } --- 148,174 ---- register char *argp = locstak(); while (*scanp && *scanp != COLON) + { + if (argp >= brkend) + growstak(argp); *argp++ = *scanp++; + } if (scanp != path) + { + if (argp >= brkend) + growstak(argp); *argp++ = '/'; + } if (*scanp == COLON) scanp++; path = (*scanp ? scanp : 0); scanp = name; ! do ! { ! if (argp >= brkend) ! growstak(argp); ! } ! while (*argp++ = *scanp++); return(path); } *************** *** 176,181 **** --- 189,196 ---- static char *xecmsg; static char **xecenv; + + static char *execs(); int execa(at, pos) char *at[]; diff -c /archbeluga/s5r2/usr/src/cmd/sh/stak.c ./stak.c *** /archbeluga/s5r2/usr/src/cmd/sh/stak.c Wed Sep 7 10:34:05 1983 --- ./stak.c Mon May 19 13:07:59 1986 *************** *** 21,26 **** --- 21,28 ---- size = round(asize, BYTESPERWORD); oldstak = stakbot; staktop = stakbot += size; + if (staktop >= brkend) + growstak(staktop); return(oldstak); } *************** *** 41,46 **** --- 43,61 ---- return(stakbot); } + void + growstak(newtop) + char *newtop; + { + register unsigned incr; + + incr = newtop - brkend + 1; + if (brkincr > incr) + incr = brkincr; + if (setbrk(incr) == -1) + error(nospace); + } + char * savstak() { *************** *** 82,86 **** cpystak(x) char *x; { ! return(endstak(movstr(x, locstak()))); } --- 97,114 ---- cpystak(x) char *x; { ! return(endstak(movstrstak(x, locstak()))); ! } ! ! char * ! movstrstak(a, b) ! register char *a, *b; ! { ! do ! { ! if (b >= brkend) ! growstak(b); ! } ! while (*b++ = *a++); ! return(--b); } diff -c /archbeluga/s5r2/usr/src/cmd/sh/stak.h ./stak.h *** /archbeluga/s5r2/usr/src/cmd/sh/stak.h Wed Sep 7 10:34:05 1983 --- ./stak.h Mon May 19 13:07:59 1986 *************** *** 50,57 **** --- 50,65 ---- */ extern char *cpystak(); + /* Copy a string onto the stack, checking for stack overflow + * as the copy is done. Same calling sequence as "movstr". + */ + extern char *movstrstak(); + /* Allocate given ammount of stack space */ extern char *getstak(); + + /* Grow the data segment to include a given location */ + extern void growstak(); /* A chain of ptrs of stack blocks that * have become covered by heap allocation. diff -c /archbeluga/s5r2/usr/src/cmd/sh/word.c ./word.c *** /archbeluga/s5r2/usr/src/cmd/sh/word.c Wed Sep 7 10:34:06 1983 --- ./word.c Mon May 19 13:08:02 1986 *************** *** 44,60 **** --- 44,68 ---- { if (c == LITERAL) { + if (argp >= brkend) + growstak(argp); *argp++ = (DQUOTE); while ((c = readc()) && c != LITERAL) { + if (argp >= brkend) + growstak(argp); *argp++ = (c | QUOTE); if (c == NL) chkpr(); } + if (argp >= brkend) + growstak(argp); *argp++ = (DQUOTE); } else { + if (argp >= brkend) + growstak(argp); *argp++ = (c); if (c == '=') wdset |= alpha; *************** *** 63,70 **** if (qotchar(c)) { d = c; ! while ((*argp++ = (c = nextc(d))) && c != d) { if (c == NL) chkpr(); } --- 71,83 ---- if (qotchar(c)) { d = c; ! for (;;) { + if (argp >= brkend) + growstak(argp); + if ((*argp++ = (c = nextc(d))) == 0 + || c == d) + break; if (c == NL) chkpr(); } diff -c /archbeluga/s5r2/usr/src/cmd/sh/xec.c ./xec.c *** /archbeluga/s5r2/usr/src/cmd/sh/xec.c Sat Oct 15 16:40:08 1983 --- ./xec.c Mon May 19 13:08:02 1986 *************** *** 407,413 **** long ulimit(); int command = 2; ! if (*a1 == '-') { switch(*(a1+1)) { case 'f': --- 407,413 ---- long ulimit(); int command = 2; ! if (a1 && *a1 == '-') { switch(*(a1+1)) { case 'f': *************** *** 478,485 **** prc_buff(NL); } break; - #endif case SYSTST: exitval = test(argn, com); --- 478,485 ---- prc_buff(NL); } break; + #endif case SYSTST: exitval = test(argn, com); -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)