This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

cpplib: Be safe in presence of symlinks


This prevents cpplib from simplifying "path/to/symlink/.." into "path/to".
It has always done this, except for (erroneously) absolute paths.
My fixing is to happen for absolute paths caused the problem to be hit
more often.

So, with ".." we check the LHS to see if it's a symlink (unless the
LHS itself ends in ".."), and don't simplify if it is or if it is
not lstat-able.

It also clears up and fixes some nits with _cpp_simplify_pathname: we
no longer try to simplify VMS paths; we used to replace "" in-place with
"." which is a potential buffer overflow; we didn't remove trailing '/'
even though we claimed we did, and I have removed some code duplication
(".." followed by '/' or '\0' are now handled together).

I couldn't see any point in simplifying paths in #line directives;
the code was only there to get cpp_included () right.  Since the
directives relevant to this test were output by a previous preprocessor
run, (as opposed to user "#line" directives), and so should already be
simplified, I've removed the code.

Does this look good to you Zack?  If so, I'll put it in mainline and
work on avoiding repeatedly simplifying (and hopefully lazily) the
include paths.

Neil.

	* cpplib.c (do_line): Don't simplify #line paths.
	* cppfiles.c (remove_component_p): New function.
	(_cpp_simplify_pathname): Don't simplify VMS paths.  Return
	the empty path untouched.  Don't leave a trailing '/'.

Index: cppfiles.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppfiles.c,v
retrieving revision 1.114
diff -u -p -c -r1.114 cppfiles.c
*** cppfiles.c	2001/03/16 05:19:46	1.114
--- cppfiles.c	2001/03/31 20:27:44
*************** static int report_missing_guard		PARAMS 
*** 101,106 ****
--- 101,107 ----
  static splay_tree_node find_or_create_entry PARAMS ((cpp_reader *,
  						     const char *));
  static void handle_missing_header PARAMS ((cpp_reader *, const char *, int));
+ static int remove_component_p	PARAMS ((const char *));
  
  /* Set up the splay tree we use to store information about all the
     file names seen in this compilation.  We also have entries for each
*************** remap_filename (pfile, name, loc)
*** 1002,1007 ****
--- 1003,1023 ----
    return name;
  }
  
+ /* Returns true if it is safe to remove the final component of path,
+    when it is followed by a ".." component.  */
+ static int
+ remove_component_p (path)
+      const char *path ATTRIBUTE_UNUSED;
+ {
+ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) || defined (VMS)
+   return 1;
+ #else
+   struct stat s;
+ 
+   return lstat (path, &s) == 0 && S_ISDIR (s.st_mode);
+ #endif
+ }
+ 
  /* Simplify a path name in place, deleting redundant components.  This
     reduces OS overhead and guarantees that equivalent paths compare
     the same (modulo symlinks).
*************** remap_filename (pfile, name, loc)
*** 1013,1136 ****
     /../quux		/quux
     //quux		//quux  (POSIX allows leading // as a namespace escape)
  
!    Guarantees no trailing slashes. All transforms reduce the length
!    of the string.  Returns PATH;
   */
  char *
  _cpp_simplify_pathname (path)
      char *path;
  {
!     char *from, *to;
!     char *base;
!     int absolute = 0;
  
  #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
!     /* Convert all backslashes to slashes. */
!     for (from = path; *from; from++)
! 	if (*from == '\\') *from = '/';
      
!     /* Skip over leading drive letter if present. */
!     if (ISALPHA (path[0]) && path[1] == ':')
! 	from = to = &path[2];
!     else
! 	from = to = path;
! #else
      from = to = path;
  #endif
      
!     /* Remove redundant initial /s.  */
!     if (*from == '/')
      {
! 	absolute = 1;
! 	to++;
! 	from++;
! 	if (*from == '/')
  	{
! 	    if (*++from == '/')
! 		/* 3 or more initial /s are equivalent to 1 /.  */
! 		while (*++from == '/');
! 	    else
! 		/* On some hosts // differs from /; Posix allows this.  */
! 		to++;
  	}
      }
!     base = to;
      
!     for (;;)
      {
! 	while (*from == '/')
! 	    from++;
  
! 	if (from[0] == '.' && from[1] == '/')
! 	    from += 2;
! 	else if (from[0] == '.' && from[1] == '\0')
! 	    goto done;
! 	else if (from[0] == '.' && from[1] == '.' && from[2] == '/')
  	{
! 	    if (base == to)
! 	    {
! 		if (absolute)
! 		    from += 3;
! 		else
! 		{
! 		    *to++ = *from++;
! 		    *to++ = *from++;
! 		    *to++ = *from++;
! 		    base = to;
! 		}
! 	    }
! 	    else
  	    {
! 		to -= 2;
! 		while (to > base && *to != '/') to--;
! 		if (*to == '/')
! 		    to++;
! 		from += 3;
  	    }
! 	}
! 	else if (from[0] == '.' && from[1] == '.' && from[2] == '\0')
! 	{
! 	    if (base == to)
  	    {
! 		if (!absolute)
  		{
! 		    *to++ = *from++;
! 		    *to++ = *from++;
  		}
! 	    }
! 	    else
! 	    {
! 		to -= 2;
! 		while (to > base && *to != '/') to--;
! 		if (*to == '/')
! 		    to++;
! 	    }
! 	    goto done;
! 	}
! 	else
! 	    /* Copy this component and trailing /, if any.  */
! 	    while ((*to++ = *from++) != '/')
! 	    {
! 		if (!to[-1])
  		{
! 		    to--;
! 		    goto done;
  		}
  	    }
! 	
      }
      
!  done:
!     /* Trim trailing slash */
!     if (to[0] == '/' && (!absolute || to > path+1))
! 	to--;
! 
!     /* Change the empty string to "." so that stat() on the result
!        will always work. */
!     if (to == path)
!       *to++ = '.';
!     
!     *to = '\0';
  
!     return path;
  }
--- 1029,1142 ----
     /../quux		/quux
     //quux		//quux  (POSIX allows leading // as a namespace escape)
  
!    Guarantees no trailing slashes.  All transforms reduce the length
!    of the string.  Returns PATH.
   */
+ 
  char *
  _cpp_simplify_pathname (path)
      char *path;
  {
! #ifndef VMS
!   char *from, *to;
!   char *base;
!   int absolute = 0;
  
+   /* Don't overflow the empty path by putting a '.' in it below.  */
+   if (*path == '\0')
+     return path;
+ 
  #if defined (HAVE_DOS_BASED_FILE_SYSTEM)
!   /* Convert all backslashes to slashes. */
!   for (from = path; *from; from++)
!     if (*from == '\\') *from = '/';
      
!   /* Skip over leading drive letter if present. */
!   if (ISALPHA (path[0]) && path[1] == ':')
!     from = to = &path[2];
!   else
      from = to = path;
+ #else
+   from = to = path;
  #endif
      
!   /* Remove redundant leading /s.  */
!   if (*from == '/')
      {
!       absolute = 1;
!       to++;
!       from++;
!       if (*from == '/')
  	{
! 	  if (*++from == '/')
! 	    /* 3 or more initial /s are equivalent to 1 /.  */
! 	    while (*++from == '/');
! 	  else
! 	    /* On some hosts // differs from /; Posix allows this.  */
! 	    to++;
  	}
      }
!   base = to;
      
!   for (;;)
      {
!       while (*from == '/')
! 	from++;
  
!       if (*from == '\0')
! 	break;
! 
!       if (*from == '.')
  	{
! 	  if (from[1] == '\0')
! 	    break;
! 	  if (from[1] == '/')
  	    {
! 	      from += 2;
! 	      continue;
  	    }
! 	  else if (from[1] == '.' && (from[2] == '/' || from[2] == '\0'))
  	    {
! 	      if (base == to)
  		{
! 		  if (absolute)
! 		    {
! 		      from += 2; /* Don't go past the NUL.  */
! 		      continue;
! 		    }
! 		  /* Prevent backing up over this component.  */
! 		  base += 3;
  		}
! 	      else
  		{
! 		  /* We don't back up if it's a symlink.  */
! 		  *to = '\0';
! 		  if (remove_component_p (path))
! 		    {
! 		      while (to > base && *to != '/')
! 			to--;
! 		      from += 2; /* Don't go past the NUL.  */
! 		      continue;
! 		    }
  		}
  	    }
! 	}
! 
!       /* Add the component separator.  */
!       if (to > base)
! 	*to++ = '/';
! 
!       /* Copy this component until the trailing null or '/'.  */
!       while (*from != '\0' && *from != '/')
! 	*to++ = *from++;
      }
      
!   /* Change the empty string to "." so that it is not treated as stdin.
!      Null terminate.  */
!   if (to == path)
!     *to++ = '.';
!   *to = '\0';
  
! #endif /* !VMS  */
!   return path;
  }
Index: cpplib.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.c,v
retrieving revision 1.245
diff -u -p -c -r1.245 cpplib.c
*** cpplib.c	2001/03/27 15:31:45	1.245
--- cpplib.c	2001/03/31 20:27:47
*************** do_line (pfile)
*** 729,740 ****
    cpp_get_token (pfile, &token);
    if (token.type == CPP_STRING)
      {
!       char *fname;
!       unsigned int len = token.val.str.len + 1;
! 
!       fname = (char *) _cpp_pool_alloc (&pfile->ident_pool, len);
!       memcpy (fname, token.val.str.text, len);
!       _cpp_simplify_pathname (fname);
  
        /* Only accept flags for the # 55 form.  */
        if (! pfile->state.line_extension)
--- 729,735 ----
    cpp_get_token (pfile, &token);
    if (token.type == CPP_STRING)
      {
!       char *fname = token.val.str.text;
  
        /* Only accept flags for the # 55 form.  */
        if (! pfile->state.line_extension)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]