[gnu.gcc.bug] Unknown problem; may be Sun rindex, GCC, SunOS, or GNU Make

hrp@boring.cray.com (Hal Peterson) (09/23/89)

I am getting intermittent failures in GNU Make 3.55+, compiled with
GCC 1.35, running on a Sun-3/280 under SunOS 3.5.  I am building the
documentation for TeXPS 2.19 (available by anonymous FTP from
june.cs.washington.edu) and make usually dumps core with a SIGSEGV.
It doesn't always happen, even though I have run make with identical
starting conditions every time.  When it does happen, it doesn't
always happen in the same place in the Make code.  The places where
the SIGSEGV happens have been executed many times before the crash,
without apparent error.  Here is the most recent crash, one which I
have seen several times:

     $ gdb make core
    GDB 3.2, Copyright (C) 1988 Free Software Foundation, Inc.
    There is ABSOLUTELY NO WARRANTY for GDB; type "info warranty" for details.
    GDB is free software and you are welcome to distribute copies of it
     under certain conditions; type "info copying" to see the conditions.
    Reading symbol data from /usr.MC68020/raptor1/contrib/src/TeXPS/TeXPS/doc/make..
    .done.
    Core file is from "make".
    Program terminated with signal 11, Segmentation fault.
    Type "help" for a list of commands.
    (gdb) bt
    #0  0x1b458 in kill ()
    #1  0x37ec in fatal_error_signal (...) (...)
    #2  0x185bc in _sigtramp ()
    #3  0x4ae0 in file_impossible_p (...) (...)
    #4  0xc350 in pattern_search (...) (...)
    #5  0xbd52 in try_implicit_rule (...) (...)
    #6  0xa3da in update_file_1 (...) (...)
    #7  0x9e98 in update_file (...) (...)
    #8  0xaa00 in check_dep (...) (...)
    #9  0xa526 in update_file_1 (...) (...)
    #10 0x9e98 in update_file (...) (...)
    #11 0xaa00 in check_dep (...) (...)
    #12 0xa526 in update_file_1 (...) (...)
    #13 0x9e98 in update_file (...) (...)
    #14 0x9d68 in update_goal_chain (...) (...)
    #15 0x6f12 in main (...) (...)
    (gdb) fr 3
    Reading in symbols for dir.c...done.
    #3  0x4ae0 in file_impossible_p (filename=(char *) 0x52b5c "SliTeX/SCCS/s.root.t
    ex") (dir.c line 295)
    295           dir = find_directory (dirname);
    (gdb) p dir
    Reading in symbols for commands.c...done.
    $1 = (struct directory *) 0x22778
    (gdb) list
    290       else
    291         {
    292           char *dirname = (char *) alloca (dirend - filename + 1);
    293           bcopy (p, dirname, dirend - p);
    294           dirname[dirend - p] = '\0';
    295           dir = find_directory (dirname);
    296           p = dirend + 1;
    297         }
    298
    299       if (dir->files == 0)
    (gdb) p dirend
    $4 = (char *) 0x17 <Address 0x17 out of bounds>
    (gdb) p filename
    $5 = (char *) 0x5e918 "SliTeX/SCCS"
    (gdb) p rindex(filename, '/')
    Cannot invoke functions if the inferior is not running.
    (gdb) p dirname
    $6 = (char *) 0x4dd90 ""
    (gdb) p p
    $10 = (char *) 0x5e923 ""

Notice the wildly incorrect value for dirend, which is the result of
rindex(filename, '/').  The SIGSEGV happens on line 294, since bcopy
is smart enough not to attempt a negative copy.  I'm not sure what the
alloca does, but it may be nasty.  I get more or less the same results
if I'm using Sun alloca, __builtin_alloca, or the C alloca from Emacs
18.54, so I don't think alloca is the problem as I did in an earlier
version of this bug report.

Here is the preprocessed source for dir.c, from which I have removed
blank lines but nothing else.  More information is available on
request; I have no idea what to look for.

--
Hal Peterson			Domain:  hrp@cray.com
Cray Research			Old style:  hrp%cray.com@uc.msc.umn.edu
1440 Northland Dr.		UUCP:  uunet!cray!hrp
Mendota Hts, MN  55120  USA	Telephone:  +1 612 681 3145

========================================================================
# 1 "dir.c"
# 1 "make.h"
# 1 "/usr/include/signal.h"
# 64 "/usr/include/signal.h"
int	(*signal())();
struct	sigvec {
	int	(*sv_handler)();	 
	int	sv_mask;		 
	int	sv_flags;		 
};
struct	sigstack {
	char	*ss_sp;			 
	int	ss_onstack;		 
};
struct	sigcontext {
	int	sc_onstack;		 
	int	sc_mask;		 
	int	sc_sp;			 
	int	sc_pc;			 
	int	sc_ps;			 
};
# 18 "make.h"
# 1 "/usr/include/stdio.h"
extern	struct	_iobuf {
	int	_cnt;
	unsigned char *_ptr;
	unsigned char *_base;
	int	_bufsiz;
	short	_flag;
	char	_file;		 
} _iob[];
extern struct _iobuf 	*fopen();
extern struct _iobuf 	*fdopen();
extern struct _iobuf 	*freopen();
extern struct _iobuf 	*popen();
extern struct _iobuf 	*tmpfile();
extern long	ftell();
extern char	*fgets();
extern char	*gets();
extern char	*ctermid();
extern char	*cuserid();
extern char	*tempnam();
extern char	*tmpnam();
# 19 "make.h"
# 1 "/usr/include/sys/param.h"
# 1 "/usr/include/machine/param.h"
# 90 "/usr/include/machine/param.h"
# 12 "/usr/include/sys/param.h"
# 1 "/usr/include/signal.h"
# 157 "/usr/include/signal.h"
# 62 "/usr/include/sys/param.h"
# 1 "/usr/include/sys/types.h"
# 1 "/usr/include/sys/sysmacros.h"
# 10 "/usr/include/sys/types.h"
typedef	unsigned char	u_char;
typedef	unsigned short	u_short;
typedef	unsigned int	u_int;
typedef	unsigned long	u_long;
typedef	unsigned short	ushort;		 
typedef	unsigned int	uint;		 
typedef	struct	_physadr { short r[1]; } *physadr;
typedef	struct	label_t	{
	int	val[13];
} label_t;
typedef	struct	_quad { long val[2]; } quad;
typedef	long	daddr_t;
typedef	char *	caddr_t;
typedef	u_long	ino_t;
typedef	long	swblk_t;
typedef	int	size_t;
typedef	long	time_t;
typedef	short	dev_t;
typedef	int	off_t;
typedef long	key_t;
typedef	struct	fd_set { int fds_bits[1]; } fd_set;
# 114 "/usr/include/sys/param.h"
# 25 "make.h"
# 1 "/usr/include/sys/stat.h"
struct	stat
{
	dev_t	st_dev;
	ino_t	st_ino;
	unsigned short st_mode;
	short	st_nlink;
	short	st_uid;
	short	st_gid;
	dev_t	st_rdev;
	off_t	st_size;
	time_t	st_atime;
	int	st_spare1;
	time_t	st_mtime;
	int	st_spare2;
	time_t	st_ctime;
	int	st_spare3;
	long	st_blksize;
	long	st_blocks;
	long	st_spare4[2];
};
# 30 "make.h"
# 42 "make.h"
# 1 "/usr/include/strings.h"
char	*strcat();
char	*strncat();
int	strcmp();
int	strncmp();
char	*strcpy();
char	*strncpy();
int	strlen();
char	*index();
char	*rindex();
# 43 "make.h"
extern int bcmp ();
extern void bzero (), bcopy ();
extern void die ();
extern void fatal (), error ();
extern void pfatal_with_name (), perror_with_name ();
extern char *savestring (), *concat ();
extern char *xmalloc (), *xrealloc ();
extern char *find_next_token (), *next_token (), *end_of_token ();
extern void collapse_continuations (), collapse_line ();
extern char *sindex (), *lindex ();
extern int alpha_compare ();
extern void print_spaces ();
extern struct dep *copy_dep_chain ();
extern char *find_percent ();
extern int ar_name ();
extern int ar_touch ();
extern time_t ar_member_date ();
extern void dir_load ();
extern int dir_file_exists_p (), file_exists_p (), file_impossible_p ();
extern void file_impossible ();
extern char *dir_name ();
extern void set_default_suffixes (), install_default_implicit_rules ();
extern void convert_to_pattern (), count_implicit_rule_limits ();
extern void create_pattern_rule ();
extern void build_vpath_lists (), construct_vpath_list ();
extern int vpath_search ();
extern void construct_include_path ();
extern int update_goal_chain ();
extern int notice_finished_file ();
extern int glob_pattern_p ();
extern char **glob_filename ();
extern void free ();
extern void abort ();
extern int unlink (), stat (), execvp ();
extern void qsort ();
extern int atoi ();
extern char *getwd ();
extern char *reading_filename;
extern unsigned int *reading_lineno_ptr;
extern int just_print_flag, silent_flag, ignore_errors_flag, keep_going_flag;
extern int debug_flag, print_data_base_flag, question_flag, touch_flag;
extern int env_overrides, no_builtin_rules_flag, print_version_flag;
extern int print_directory_flag;
extern unsigned int job_slots;
extern double max_load_average;
extern char *program;
extern unsigned int makelevel;
# 18 "dir.c"
# 1 "/usr/include/sys/dir.h"
struct	direct {
	u_long	d_fileno;		 
	u_short	d_reclen;		 
	u_short	d_namlen;		 
	char	d_name[255  + 1];	 
};
typedef struct _dirdesc {
	int	dd_fd;
	long	dd_loc;
	long	dd_size;
	long	dd_bbase;
	long	dd_entno;
	long	dd_bsize;
	char	*dd_buf;
} DIR;
extern	DIR *opendir();
extern	struct direct *readdir();
extern	long telldir();
extern	void seekdir();
extern	void closedir();
# 29 "dir.c"
struct directory
  {
    struct directory *next;
    char *name;			 
    struct dirfile **files;	 
    DIR *dirstream;		 
  };
static struct directory *directories[23 ];
static unsigned int open_directories = 0;
struct dirfile
  {
    struct dirfile *next;
    char *name;			 
    char impossible;		 
  };

static struct directory *
find_directory (name)
     register char *name;
{
  register unsigned int hash = 0;
  register char *p;
  register struct directory *dir;
  for (p = name; *p != '\0'; ++p)
    {
      hash += *p;
      hash = (hash << 7) + (hash >> 20);
    }
  hash %= 23 ;
  for (dir = directories[hash]; dir != 0; dir = dir->next)
    if (((dir->name) == ( name) || (*(dir->name) == *( name) && (*(dir->name) == '\0' || !strcmp ((dir->name) + 1, ( name) + 1)))) )
      break;
  if (dir == 0)
    {
      struct stat st;
      dir = (struct directory *) xmalloc (sizeof (struct directory));
      dir->next = directories[hash];
      directories[hash] = dir;
      dir->name = savestring (name, p - name);
      dir->dirstream = opendir (name);
      if (dir->dirstream == 0)
	dir->files = 0;
      else
	{
	  dir->files = (struct dirfile **)
	    xmalloc (sizeof (struct dirfile) * 1007 );
	  bzero ((char *) dir->files,
		 sizeof (struct dirfile) * 1007 );
	  ++open_directories;
	  if (open_directories == 10 )
	    (void) dir_file_exists_p (dir->name, "");
	}
    }
  return dir;
}

int
dir_file_exists_p (dirname, filename)
     register char *dirname;
     register char *filename;
{
  register unsigned int hash;
  register char *p;
  register struct directory *dir;
  register struct dirfile *df;
  register struct direct *d;
  dir = find_directory (dirname);
  if (dir->files == 0)
    return 0;
  if (*filename == '\0')
    return 1;
  hash = 0;
  for (p = filename; *p != '\0'; ++p)
    {
      hash += *p;
      hash = (hash <<  7) + (hash >> 20);
    }
  hash %= 1007 ;
  for (df = dir->files[hash]; df != 0; df = df->next)
    if (((df->name) == ( filename) || (*(df->name) == *( filename) && (*(df->name) == '\0' || !strcmp ((df->name) + 1, ( filename) + 1)))) )
      return !df->impossible;
  if (dir->dirstream == 0)
    return 0;
  while ((d = readdir (dir->dirstream)) != 0)
    {
      register unsigned int newhash = 0;
      register unsigned int i;
      for (i = 0; i < ((d)->d_namlen) ; ++i)
	{
	  newhash += d->d_name[i];
	  newhash = (newhash << 7) + (newhash >> 20);
	}
      newhash %= 1007 ;
      df = (struct dirfile *) xmalloc (sizeof (struct dirfile));
      df->next = dir->files[newhash];
      dir->files[newhash] = df;
      df->name = savestring (d->d_name, ((d)->d_namlen) );
      df->impossible = 0;
      if (newhash == hash && ((d->d_name) == ( filename) || (*(d->d_name) == *( filename) && (*(d->d_name) == '\0' || !strcmp ((d->d_name) + 1, ( filename) + 1)))) )
	return 1;
    }
  if (d == 0)
    {
      --open_directories;
      closedir (dir->dirstream);
      dir->dirstream = 0;
    }
  return 0;
}

int
file_exists_p (name)
     register char *name;
{
  char *dirend;
  char *dirname;
  if (ar_name (name))
    return ar_member_date (name) != (time_t) -1;
  dirend = rindex (name, '/');
  if (dirend == 0)
    return dir_file_exists_p (".", name);
  dirname = (char *) alloca (dirend - name + 1);
  bcopy (name, dirname, dirend - name);
  dirname[dirend - name] = '\0';
  return dir_file_exists_p (dirname, dirend + 1);
}

void
file_impossible (filename)
     register char *filename;
{
  char *dirend;
  register char *p = filename;
  register unsigned int hash;
  register struct directory *dir;
  register struct dirfile *new;
  dirend = rindex (p, '/');
  if (dirend == 0)
    dir = find_directory (".");
  else
    {
      char *dirname = (char *) alloca (dirend - p + 1);
      bcopy (p, dirname, dirend - p);
      dirname[dirend - p] = '\0';
      dir = find_directory (dirname);
      filename = p = dirend + 1;
    }
  hash = 0;
  while (*p != '\0')
    {
      hash += *p++;
      hash = (hash << 7) + (hash >> 20);
    }
  hash %= 1007 ;
  if (dir->files == 0)
    {
      dir->files = (struct dirfile **)
	xmalloc (sizeof (struct dirfile) * 1007 );
      bzero ((char *) dir->files, sizeof (struct dirfile) * 1007 );
    }
  new = (struct dirfile *) xmalloc (sizeof (struct dirfile));
  new->next = dir->files[hash];
  dir->files[hash] = new;
  new->name = savestring (filename, strlen (filename));
  new->impossible = 1;
}

int
file_impossible_p (filename)
     char *filename;
{
  char *dirend;
  register char *p = filename;
  register unsigned int hash;
  register struct directory *dir;
  register struct dirfile *next;
  dirend = rindex (filename, '/');
  if (dirend == 0)
    dir = find_directory (".");
  else
    {
      char *dirname = (char *) alloca (dirend - filename + 1);
      bcopy (p, dirname, dirend - p);
      dirname[dirend - p] = '\0';
      dir = find_directory (dirname);
      p = dirend + 1;
    }
  if (dir->files == 0)
    return 0;
  hash = 0;
  while (*p != '\0')
    {
      hash += *p++;
      hash = (hash << 7) + (hash >> 20);
    }
  hash %= 1007 ;
  for (next = dir->files[hash]; next != 0; next = next->next)
    if (((filename) == ( next->name) || (*(filename) == *( next->name) && (*(filename) == '\0' || !strcmp ((filename) + 1, ( next->name) + 1)))) )
      return next->impossible;
  return 0;
}

char *
dir_name (dir)
     char *dir;
{
  return find_directory (dir)->name;
}

void
print_dir_data_base ()
{
  register unsigned int i, dirs, files, impossible;
  register struct directory *dir;
  puts ("\n# Directories\n");
  dirs = files = impossible = 0;
  for (i = 0; i < 23 ; ++i)
    for (dir = directories[i]; dir != 0; dir = dir->next)
      {
	++dirs;
	if (dir->files == 0)
	  printf ("# %s: could not be opened.\n", dir->name);
	else
	  {
	    register unsigned int f = 0, im = 0;
	    register unsigned int j;
	    register struct dirfile *df;
	    for (j = 0; j < 1007 ; ++j)
	      for (df = dir->files[j]; df != 0; df = df->next)
		if (df->impossible)
		  ++im;
		else
		  ++f;
	    printf ("# %s: ", dir->name);
	    if (f == 0)
	      fputs ("No", (&_iob[1]) );
	    else
	      printf ("%u", f);
	    fputs (" files, ", (&_iob[1]) );
	    if (im == 0)
	      fputs ("no", (&_iob[1]) );
	    else
	      printf ("%u", im);
	    fputs (" impossibilities", (&_iob[1]) );
	    if (dir->dirstream == 0)
	      puts (".");
	    else
	      puts (" so far.");
	    files += f;
	    impossible += im;
	  }
      }
  fputs ("\n# ", (&_iob[1]) );
  if (files == 0)
    fputs ("No", (&_iob[1]) );
  else
    printf ("%u", files);
  fputs (" files, ", (&_iob[1]) );
  if (impossible == 0)
    fputs ("no", (&_iob[1]) );
  else
    printf ("%u", impossible);
  printf (" impossibilities in %u directories.\n", dirs);
}