Subject: tcsh dumps core when traversing symlinks (#313) Index: new/tcsh/sh.dir.c,alloc11.c,... 2.11BSD Description: tcsh dumps core with no error message when traversing symlinks. Repeat-By: /u is a symlink to where the home directories reside. In my case a "ln -s /userfiles /u" had been done earlier. Then: cd / cd u cd sms1 pwd *BOOM* - core dump with no diagnostic message Another way, suggested a year ago (yes, it's taken that long for this to bubble to the top of the TODO list): mkdir tmp cd cd /u/sms1 cd tmp *BOOM* Fix: There were two problems, the second being triggered by the first. The first problem was a corruption of the malloc arena due to a string copy overrunning a malloc'd buffer (when the allocation was done room was not reserved for the terminating NULL). The second problem was that 'botch()' called 'printf' in an attempt to report the first error. Printf() calls malloc - but the malloc arena was corrupt, so the botch() routine gets called to report the error. See a pattern here? Eventually the stack underflows and the kernel mercifully terminates the program with a core dump. In the process of fixing the above the base segment grew above 48kb. To avoid having to rearrange the overlays a couple other .c files were modified to include additional "register" declarations. This reduced the code size to less than it was before the bugs were fixed! The overlay arrangement should be revisited some day. It is definitely sub optimal - the simplest command causing many overlay switches. It's a tribute to the efficiency of the kernel overlay switching that the interactive response of tcsh is not noticeably affected. Cut where indicated, saving to a file (/tmp/313). Then: patch -p0 < /tmp/313 cd /usr/src/new/tcsh make make install make clean this takes about 50 minutes. This and previous updates are available via anonymous FTP to either FTP.IIPO.GTEGSC.COM and MOE.2BSD.COM in the directory /pub/2.11BSD. ==========================cut here========================= *** /usr/src/new/tcsh/sh.dir.c.old Wed Aug 21 10:47:20 1991 --- /usr/src/new/tcsh/sh.dir.c Thu Apr 4 21:11:17 1996 *************** *** 1,4 **** - /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.dir.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ /* * sh.dir.c: Directory manipulation functions */ --- 1,3 ---- *************** *** 37,43 **** #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() ! { return "$Id: sh.dir.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } #endif --- 36,42 ---- #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() ! { return "$Id: sh.dir.c,v 3.0.1 1996/04/04 21:49:28 sms Exp $"; } #endif *************** *** 160,166 **** Char ***v; char *str; { ! Char **n = *v, *s; dirflag = 0; for (n++; *n != NOSTR && (*n)[0] == '-'; n++) --- 159,165 ---- Char ***v; char *str; { ! register Char **n = *v, *s; dirflag = 0; for (n++; *n != NOSTR && (*n)[0] == '-'; n++) *************** *** 248,254 **** void dtilde() { ! struct directory *d = dcwd; do { if (d == &dhead) --- 247,253 ---- void dtilde() { ! register struct directory *d = dcwd; do { if (d == &dhead) *************** *** 266,272 **** */ Char * dnormalize(cp) ! Char *cp; { #define UC (unsigned char) --- 265,271 ---- */ Char * dnormalize(cp) ! register Char *cp; { #define UC (unsigned char) *************** *** 279,285 **** #ifdef S_IFLNK if (adrof(STRig__symlinks)) { int dotdot = 0; ! Char *dp, *cwd; #ifdef apollo bool slashslash; #endif --- 278,284 ---- #ifdef S_IFLNK if (adrof(STRig__symlinks)) { int dotdot = 0; ! register Char *dp, *cwd; #ifdef apollo bool slashslash; #endif *************** *** 974,980 **** */ p2 = cp + Strlen(p2); sp = newcp = (Char *) xmalloc((size_t) ! ((cc + Strlen(p2)) * sizeof(Char))); while (*p1) *sp++ = *p1++; while (*p2) --- 973,979 ---- */ p2 = cp + Strlen(p2); sp = newcp = (Char *) xmalloc((size_t) ! ((cc + Strlen(p2) + 1) * sizeof(Char))); while (*p1) *sp++ = *p1++; while (*p2) *************** *** 1031,1037 **** Char *s; int cnt; { ! struct directory *dp; dp = dcwd; if (cnt < 0) { /* < 0 ==> last dir requested. */ --- 1030,1036 ---- Char *s; int cnt; { ! register struct directory *dp; dp = dcwd; if (cnt < 0) { /* < 0 ==> last dir requested. */ *************** *** 1061,1067 **** */ void dextract(dp) ! struct directory *dp; { if (dp == dcwd) return; --- 1060,1066 ---- */ void dextract(dp) ! register struct directory *dp; { if (dp == dcwd) return; *** /usr/src/new/tcsh/alloc11.c.old Mon Aug 19 07:41:13 1991 --- /usr/src/new/tcsh/alloc11.c Thu Apr 4 20:48:49 1996 *************** *** 1,16 **** #if !defined(lint) && !defined(NOSCCS) ! static char *sccsid = "@(#)alloc.c 4.1 10/9/80"; #endif #include "config.h" ! /* #include "sh.local.h" */ #define debug #ifdef debug #define ASSERT(p) if(!(p))botch("p");else botch(s) char *s; { ! printf("assertion botched: %s\n",s); abort(); } #else --- 1,38 ---- #if !defined(lint) && !defined(NOSCCS) ! static char *sccsid = "@(#)alloc.c 4.1.1 1996/4/4"; #endif #include "config.h" ! #include ! #include ! #include ! #define debug #ifdef debug #define ASSERT(p) if(!(p))botch("p");else + + /* + * Can't use 'printf' below because that can call malloc(). If the malloc + * arena is corrupt the result is a recursive loop which underflows the stack + * and obfuscates the initial problem. + */ botch(s) char *s; { ! struct iovec iov[3]; ! register struct iovec *v = iov; ! char *ab = "assertion botched: "; ! ! v->iov_base = ab; ! v->iov_len = strlen(ab); ! v++; ! v->iov_base = s; ! v->iov_len = strlen(s); ! v++; ! v->iov_base = "\n"; ! v->iov_len = 1; ! ! writev(STDOUT_FILENO, iov, 3); abort(); } #else *************** *** 47,53 **** #define WORD sizeof(union store) #define BLOCK 1024 /* a multiple of WORD*/ #define BUSY 1 ! #define NULL 0 #define testbusy(p) ((INT)(p)&BUSY) #define setbusy(p) (union store *)((INT)(p)|BUSY) #define clearbusy(p) (union store *)((INT)(p)&~BUSY) --- 69,75 ---- #define WORD sizeof(union store) #define BLOCK 1024 /* a multiple of WORD*/ #define BUSY 1 ! #define testbusy(p) ((INT)(p)&BUSY) #define setbusy(p) (union store *)((INT)(p)|BUSY) #define clearbusy(p) (union store *)((INT)(p)&~BUSY) *************** *** 220,224 **** free += i; } } ! printf("%d used, %d free, %u end\n", used, free, clearbusy(alloct)); } --- 242,246 ---- free += i; } } ! printf("%u used, %u free, %u end\n", used, free, clearbusy(alloct)); } *** /usr/src/new/tcsh/ed.defns.c.old Tue Aug 20 20:57:42 1991 --- /usr/src/new/tcsh/ed.defns.c Thu Apr 4 21:10:08 1996 *************** *** 1,4 **** - /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/ed.defns.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ /* * ed.defns.c: Editor function definitions and initialization */ --- 1,3 ---- *************** *** 37,43 **** #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() ! { return "$Id: ed.defns.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } #endif #include "sh.h" --- 36,42 ---- #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() ! { return "$Id: ed.defns.c,v 3.0.1 1996/04/04 21:49:28 sms Exp $"; } #endif #include "sh.h" *************** *** 1482,1488 **** { Char buf[3]; register int i; ! KEYCMD *map; map = CcKeyMap; for (i = 0; i <= 0377 && CcKeyMap[i] != F_METANEXT; i++); --- 1481,1487 ---- { Char buf[3]; register int i; ! register KEYCMD *map; map = CcKeyMap; for (i = 0; i <= 0377 && CcKeyMap[i] != F_METANEXT; i++); *** /usr/src/new/tcsh/sh.hist.c.old Tue Aug 20 12:13:00 1991 --- /usr/src/new/tcsh/sh.hist.c Thu Apr 4 21:31:23 1996 *************** *** 1,4 **** - /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.hist.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ /* * sh.hist.c: Shell history expansions and substitutions */ --- 1,3 ---- *************** *** 37,43 **** #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() ! { return "$Id: sh.hist.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } #endif #include "sh.h" --- 36,42 ---- #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() ! { return "$Id: sh.hist.c,v 3.0.1 1996/04/04 21:49:28 sms Exp $"; } #endif #include "sh.h" *************** *** 171,178 **** static void dohist1(hp, np, rflg, hflg, tflg) ! struct Hist *hp; ! int *np, rflg, hflg, tflg; { bool print = (*np) > 0; --- 170,178 ---- static void dohist1(hp, np, rflg, hflg, tflg) ! register struct Hist *hp; ! register int *np; ! int rflg, hflg, tflg; { bool print = (*np) > 0; *************** *** 195,201 **** register struct Hist *hp; int hflg, tflg; { ! struct tm *t; char ampm = 'a'; if (hflg == 0) { --- 195,201 ---- register struct Hist *hp; int hflg, tflg; { ! register struct tm *t; char ampm = 'a'; if (hflg == 0) { *** /usr/src/new/tcsh/tc.alloc.c.old Tue Aug 20 12:13:08 1991 --- /usr/src/new/tcsh/tc.alloc.c Thu Apr 4 21:08:28 1996 *************** *** 1,4 **** - /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/tc.alloc.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ /* * tc.alloc.c (Caltech) 2/21/82 * Chris Kingsley, kingsley@cit-20. --- 1,3 ---- *************** *** 45,51 **** #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() ! { return "$Id: tc.alloc.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } #endif --- 44,50 ---- #include "config.h" #if !defined(lint) && !defined(pdp11) static char *rcsid() ! { return "$Id: tc.alloc.c,v 3.0.1 1996/04/04 21:49:28 sms Exp $"; } #endif *************** *** 496,502 **** memalign_t Realloc(p, n) ptr_t p; ! size_t n; { ptr_t ptr; --- 495,501 ---- memalign_t Realloc(p, n) ptr_t p; ! register size_t n; { ptr_t ptr; *************** *** 510,518 **** memalign_t Calloc(s, n) ! size_t s, n; { ! char *sptr; ptr_t ptr; n *= s; --- 509,517 ---- memalign_t Calloc(s, n) ! register size_t s, n; { ! register char *sptr; ptr_t ptr; n *= s; *** /VERSION.old Sat Mar 30 20:46:46 1996 --- /VERSION Thu Apr 4 21:52:18 1996 *************** *** 1,4 **** ! Current Patch Level: 312 2.11 BSD ============ --- 1,4 ---- ! Current Patch Level: 313 2.11 BSD ============