preprocessor/556: cpplib uses freed file descriptors

Neil Booth NeilB@earthling.net
Wed Sep 20 23:39:00 GMT 2000


This bootstraps and no new regressions.  OK to commit?

Neil.

	* cppfiles.c (lookup_include_file): Rename to open_file.
	Always create a splay tree value, even on syscall failures.
	Negative entries indicated by fd == -2.
	Re-open files closed in the meantime.
	(_cpp_fake_include): Create a negative splay tree entry.
	(find_include_file, cpp_read_file): Update for function name
	change.
	* gcc.gd/cpp/mi4.c: Testcase.

Index: cppfiles.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cppfiles.c,v
retrieving revision 1.81
diff -c -p -r1.81 cppfiles.c
*** cppfiles.c	2000/09/19 17:28:46	1.81
--- cppfiles.c	2000/09/20 22:24:11
*************** static struct file_name_list *actual_dir
*** 73,80 ****
  static struct include_file *find_include_file
  				PARAMS ((cpp_reader *, const char *,
  					 struct file_name_list *));
! static struct include_file *lookup_include_file
! 				PARAMS ((cpp_reader *, const char *));
  static int read_include_file	PARAMS ((cpp_reader *, struct include_file *));
  static int stack_include_file	PARAMS ((cpp_reader *, struct include_file *));
  static void purge_cache 	PARAMS ((struct include_file *));
--- 73,79 ----
  static struct include_file *find_include_file
  				PARAMS ((cpp_reader *, const char *,
  					 struct file_name_list *));
! static struct include_file *open_file PARAMS ((cpp_reader *, const char *));
  static int read_include_file	PARAMS ((cpp_reader *, struct include_file *));
  static int stack_include_file	PARAMS ((cpp_reader *, struct include_file *));
  static void purge_cache 	PARAMS ((struct include_file *));
*************** destroy_include_file_node (v)
*** 98,104 ****
    if (f)
      {
        purge_cache (f);
!       free (f);
      }
  }
  
--- 97,103 ----
    if (f)
      {
        purge_cache (f);
!       free (f);  /* The tree is registered with free to free f->name.  */
      }
  }
  
*************** _cpp_cleanup_includes (pfile)
*** 120,142 ****
  }
  
  /* Given a file name, look it up in the cache; if there is no entry,
!    create one.  Returns 0 if the file doesn't exist or is
!    inaccessible, otherwise the cache entry.  */
  
  static struct include_file *
! lookup_include_file (pfile, filename)
       cpp_reader *pfile;
       const char *filename;
! {     
    splay_tree_node nd;
!   struct include_file *file = 0;
!   int fd;
!   struct stat st;
  
    nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) filename);
  
    if (nd)
!     return (struct include_file *)nd->value;
  
    /* We used to open files in nonblocking mode, but that caused more
       problems than it solved.  Do take care not to acquire a
--- 119,162 ----
  }
  
  /* Given a file name, look it up in the cache; if there is no entry,
!    create one (regardless of success in opening the file).  If the
!    file doesn't exist or is inaccessible, this entry is flagged so we
!    don't attempt to open it again in the future.  If the file isn't
!    open, open it.
  
+    Returns an include_file structure with an open file descriptor on
+    success, or NULL on failure.  */
+ 
  static struct include_file *
! open_file (pfile, filename)
       cpp_reader *pfile;
       const char *filename;
! {
    splay_tree_node nd;
!   struct include_file *file;
  
    nd = splay_tree_lookup (pfile->all_include_files, (splay_tree_key) filename);
  
    if (nd)
!     {
!       file = (struct include_file *) nd->value;
! 
!       /* Don't retry opening if we failed previously.  */
!       if (file->fd == -2)
! 	return 0;
! 
!       /* -1 indicates a file we've opened previously, and since closed.  */
!       if (file->fd != -1)
! 	return file;
!     }
!   else
!     {
!       file = xcnew (struct include_file);
!       file->name = xstrdup (filename);
!       splay_tree_insert (pfile->all_include_files,
! 			 (splay_tree_key) file->name,
! 			 (splay_tree_value) file);
!     }
  
    /* We used to open files in nonblocking mode, but that caused more
       problems than it solved.  Do take care not to acquire a
*************** lookup_include_file (pfile, filename)
*** 153,189 ****
       Special case: the empty string is translated to stdin.  */
  
    if (filename[0] == '\0')
!     fd = 0;
    else
!     fd = open (filename, O_RDONLY|O_NOCTTY|O_BINARY, 0666);
!   if (fd == -1)
!     goto fail;
  
!   if (fstat (fd, &st) < 0)
!     goto fail;
!   
!   file = xcnew (struct include_file);
!   file->name = xstrdup (filename);
!   file->st = st;
!   file->fd = fd;
! 
!   /* If the file is plain and zero length, mark it never-reread now.  */
!   if (S_ISREG (st.st_mode) && st.st_size == 0)
!     file->cmacro = NEVER_REREAD;
! 
!   splay_tree_insert (pfile->all_include_files,
! 		     (splay_tree_key) file->name, (splay_tree_value) file);
!   return file;
  
!  fail:
  
    /* Don't issue an error message if the file doesn't exist.  */
    if (errno != ENOENT && errno != ENOTDIR)
      cpp_error_from_errno (pfile, filename);
  
-   /* Create a negative node for this path.  */
-   splay_tree_insert (pfile->all_include_files,
- 		     (splay_tree_key) xstrdup (filename), 0);
    return 0;
  }
  
--- 173,198 ----
       Special case: the empty string is translated to stdin.  */
  
    if (filename[0] == '\0')
!     file->fd = 0;
    else
!     file->fd = open (filename, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
  
!   if (file->fd != -1 && fstat (file->fd, &file->st) == 0)
!     {
!       /* Mark a regular, zero-length file never-reread now.  */
!       if (S_ISREG (file->st.st_mode) && file->st.st_size == 0)
! 	file->cmacro = NEVER_REREAD;
  
!       return file;
!     }
  
    /* Don't issue an error message if the file doesn't exist.  */
    if (errno != ENOENT && errno != ENOTDIR)
      cpp_error_from_errno (pfile, filename);
+ 
+   /* Create a negative node for this path, and return null.  */
+   file->fd = -2;
  
    return 0;
  }
  
*************** find_include_file (pfile, fname, search_
*** 419,425 ****
    struct include_file *file;
  
    if (fname[0] == '/')
!     return lookup_include_file (pfile, fname);
        
    /* Search directory path for the file.  */
    name = (char *) alloca (strlen (fname) + pfile->max_include_len
--- 428,434 ----
    struct include_file *file;
  
    if (fname[0] == '/')
!     return open_file (pfile, fname);
        
    /* Search directory path for the file.  */
    name = (char *) alloca (strlen (fname) + pfile->max_include_len
*************** find_include_file (pfile, fname, search_
*** 433,439 ****
        if (CPP_OPTION (pfile, remap))
  	name = remap_filename (pfile, name, path);
  
!       file = lookup_include_file (pfile, name);
        if (file)
  	{
  	  file->sysp = path->sysp;
--- 442,448 ----
        if (CPP_OPTION (pfile, remap))
  	name = remap_filename (pfile, name, path);
  
!       file = open_file (pfile, name);
        if (file)
  	{
  	  file->sysp = path->sysp;
*************** _cpp_fake_include (pfile, fname)
*** 478,486 ****
        free (name);
        return (const char *) nd->key;
      }
  
!   splay_tree_insert (pfile->all_include_files, (splay_tree_key) name, 0);
!   return (const char *)name;
  }
  
  /* Not everyone who wants to set system-header-ness on a buffer can
--- 487,500 ----
        free (name);
        return (const char *) nd->key;
      }
+ 
+   file = xcnew (struct include_file);
+   file->name = name;
+   file->fd = -2;
+   splay_tree_insert (pfile->all_include_files, (splay_tree_key) name,
+ 		     (splay_tree_value) file);
  
!   return file->name;
  }
  
  /* Not everyone who wants to set system-header-ness on a buffer can
*************** cpp_read_file (pfile, fname)
*** 701,707 ****
    if (fname == NULL)
      fname = "";
  
!   f = lookup_include_file (pfile, fname);
  
    if (f == NULL)
      {
--- 715,721 ----
    if (fname == NULL)
      fname = "";
  
!   f = open_file (pfile, fname);
  
    if (f == NULL)
      {
Index: testsuite/gcc.dg/cpp/mi4.c
===================================================================
RCS file: mi4.c
diff -N mi4.c
*** /dev/null	Tue May  5 13:32:27 1998
--- mi4.c	Wed Sep 20 15:24:29 2000
***************
*** 0 ****
--- 1,10 ----
+ /* Copyright (C) 2000 Free Software Foundation, Inc.  */
+ 
+ /* { dg-do preprocess } */
+ 
+ /* Undefining a macro guard and re-including the file used to confuse
+    file caching in cppfiles.c, and attempt to open a bad fd.  */
+ 
+ #include "mi1c.h"
+ #undef CPP_MIC_H
+ #include "mi1c.h"


More information about the Gcc-patches mailing list