*BSD News Article 64967


Return to BSD News archive

Newsgroups: comp.bugs.2bsd
Path: euryale.cc.adfa.oz.au!newshost.anu.edu.au!harbinger.cc.monash.edu.au!news.rmit.EDU.AU!news.unimelb.EDU.AU!munnari.OZ.AU!news.ecn.uoknor.edu!news.cis.okstate.edu!newsfeed.ksu.ksu.edu!news.mid.net!sbctri.tri.sbc.com!newspump.wustl.edu!news.ecn.bgu.edu!vixen.cso.uiuc.edu!newsfeed.internetmci.com!salliemae!europa.chnt.gtegsc.com!wlbr!moe!sms
From: sms@moe.2bsd.com (Steven M. Schultz)
Subject: tcsh dumps core when traversing symlinks (#313)
Organization: 2BSD, Simi Valley CA USA
Message-ID: <DpDMqq.5uG@moe.2bsd.com>
Date: Fri, 5 Apr 1996 06:44:50 GMT
Lines: 481

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 <unistd.h>
! #include <sys/types.h>
! #include <sys/uio.h>
! 
  #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
  ============