Cleanup prefix.c to remove remaining cpplib memory leaks

Neil Booth neil@daikokuya.demon.co.uk
Sun Aug 12 04:46:00 GMT 2001


This patch cleans up prefix.c so as to remove the remaining memory
leaks in cpplib.  The diff is not as large as it looks; much is
whitespace change.

The basic idea is to make it clear in prefix.c what memory is
malloc-ed, and who is responsible for freeing it.  Because this was
not clearly stated before, all users would assume the worst and
allocate a new copy of something in order to modify it, and not free
what was there before.

The new semantics are simple, and make prefix.c memory leak free: the
returned value of update_path() is guaranteed to be malloced, and the
caller is responsible for freeing it.  The patch includes the
appropriate documentation changes.

These semantics are appropriate for both users of prefix.c (gcc.c and
cppinit.c), and as a result the number of allocations actually
decreases rather than increasing.

I've updated UPDATE_PATH_HOST_CANONICALIZE to take only one argument.
Only xm-djgpp.h uses this macro, and it only used the one argument,
and had some redundant code and variables, so I've touched it up.
I've checked the code with this macro expanded compiles (apart from
the non-existence of the DJGPP function _fixpath on my system).

Bootstrapping x86 Linux.  OK to commit?

Neil.

	* cppinit.c (init_standard_includes): The returned buffer
	is already malloc-ed.
	* gcc.c (add_prefix): Similarly.
	* prefix.c (translate_name): Update to support clear buffer
	ownership rules.
	(update_path): Similarly.  Be sure to free any newly allocated
	key.  UPDATE_PATH_HOST_CANONICALIZE takes only one argument.
	(tr): New function.
	* prefix.h (update_path): Update prototype and document.
	* config/i386/xm-djgpp.h (UPDATE_PATH_HOST_CANONICALIZE): Clean
	up and update to new buffer ownership rules.
	* doc/gcc.texi (UPDATE_PATH_HOST_CANONICALIZE): Update.

============================================================
Index: gcc/cppinit.c
*** cppinit.c	2001/08/11 12:37:18	1.170
--- gcc/cppinit.c	2001/08/12 11:22:11
*************** init_standard_includes (pfile)
*** 861,867 ****
  	  || (CPP_OPTION (pfile, cplusplus)
  	      && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
  	{
! 	  char *str = xstrdup (update_path (p->fname, p->component));
  	  append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
  	}
      }
--- 861,867 ----
  	  || (CPP_OPTION (pfile, cplusplus)
  	      && !CPP_OPTION (pfile, no_standard_cplusplus_includes)))
  	{
! 	  char *str = update_path (p->fname, p->component);
  	  append_include_chain (pfile, str, SYSTEM, p->cxx_aware);
  	}
      }
============================================================
Index: gcc/gcc.c
*** gcc.c	2001/08/02 12:26:00	1.237
--- gcc/gcc.c	2001/08/12 11:22:31
*************** add_prefix (pprefix, prefix, component, 
*** 2607,2613 ****
      pprefix->max_len = len;
  
    pl = (struct prefix_list *) xmalloc (sizeof (struct prefix_list));
!   pl->prefix = save_string (prefix, len);
    pl->require_machine_suffix = require_machine_suffix;
    pl->used_flag_ptr = warn;
    pl->priority = priority;
--- 2607,2613 ----
      pprefix->max_len = len;
  
    pl = (struct prefix_list *) xmalloc (sizeof (struct prefix_list));
!   pl->prefix = prefix;
    pl->require_machine_suffix = require_machine_suffix;
    pl->used_flag_ptr = warn;
    pl->priority = priority;
============================================================
Index: gcc/prefix.c
*** prefix.c	2001/04/29 12:43:20	1.28
--- gcc/prefix.c	2001/08/12 11:22:31
*************** Boston, MA 02111-1307, USA.  */
*** 74,81 ****
  static const char *std_prefix = PREFIX;
  
  static const char *get_key_value	PARAMS ((char *));
! static const char *translate_name	PARAMS ((const char *));
  static char *save_string		PARAMS ((const char *, int));
  
  #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
  static char *lookup_key		PARAMS ((char *));
--- 74,82 ----
  static const char *std_prefix = PREFIX;
  
  static const char *get_key_value	PARAMS ((char *));
! static char *translate_name		PARAMS ((char *));
  static char *save_string		PARAMS ((const char *, int));
+ static void tr				PARAMS ((char *, int, int));
  
  #if defined(_WIN32) && defined(ENABLE_WIN32_REGISTRY)
  static char *lookup_key		PARAMS ((char *));
*************** lookup_key (key)
*** 230,330 ****
  }
  #endif
  
! /* If NAME starts with a '@' or '$', apply the translation rules above
!    and return a new name.  Otherwise, return the given name.  */
  
! static const char *
  translate_name (name)
!   const char *name;
  {
!   char code = name[0];
!   char *key;
!   const char *prefix = 0;
    int keylen;
  
!   if (code != '@' && code != '$')
!     return name;
  
!   for (keylen = 0;
!        (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1]));
!        keylen++)
!     ;
  
!   key = (char *) alloca (keylen + 1);
!   strncpy (key, &name[1], keylen);
!   key[keylen] = 0;
  
!   name = &name[keylen + 1];
  
!   if (code == '@')
      {
!       prefix = get_key_value (key);
!       if (prefix == 0)
! 	prefix = std_prefix;
      }
!   else
!     prefix = getenv (key);
! 
!   if (prefix == 0)
!     prefix = PREFIX;
! 
!   /* We used to strip trailing DIR_SEPARATORs here, but that can
!      sometimes yield a result with no separator when one was coded
!      and intended by the user, causing two path components to run
!      together.  */
! 
!   return concat (prefix, name, NULL);
  }
  
! /* Update PATH using KEY if PATH starts with PREFIX.  */
  
! const char *
  update_path (path, key)
    const char *path;
    const char *key;
  {
    if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0)
      {
!       if (key[0] != '$')
! 	key = concat ("@", key, NULL);
  
!       path = concat (key, &path[strlen (std_prefix)], NULL);
! 
!       while (path[0] == '@' || path[0] == '$')
! 	path = translate_name (path);
      }
  
  #ifdef UPDATE_PATH_HOST_CANONICALIZE
! /* Perform host dependant canonicalization when needed.  */
! UPDATE_PATH_HOST_CANONICALIZE (path, key);
  #endif
  
  #ifdef DIR_SEPARATOR_2
    /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */
!   if (DIR_SEPARATOR != DIR_SEPARATOR_2)
!     {
!       char *new_path = xstrdup (path);
!       path = new_path;
!       do {
! 	if (*new_path == DIR_SEPARATOR_2)
! 	  *new_path = DIR_SEPARATOR;
!       } while (*new_path++);
!     }
  #endif
!       
  #if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2)
    if (DIR_SEPARATOR != '/')
!     {
!       char *new_path = xstrdup (path);
!       path = new_path;
!       do {
! 	if (*new_path == '/')
! 	  *new_path = DIR_SEPARATOR;
!       } while (*new_path++);
!     }
  #endif
  
!   return path;
  }
  
  /* Reset the standard prefix */
--- 231,349 ----
  }
  #endif
  
! /* If NAME, a malloc-ed string, starts with a '@' or '$', apply the
!    translation rules above and return a newly malloc-ed name.
!    Otherwise, return the given name.  */
  
! static char *
  translate_name (name)
!      char *name;
  {
!   char code;
!   char *key, *old_name;
!   const char *prefix;
    int keylen;
  
!   for (;;)
!     {
!       code = name[0];
!       if (code != '@' && code != '$')
! 	break;
! 
!       for (keylen = 0;
! 	   (name[keylen + 1] != 0 && !IS_DIR_SEPARATOR (name[keylen + 1]));
! 	   keylen++)
! 	;
! 
!       key = (char *) alloca (keylen + 1);
!       strncpy (key, &name[1], keylen);
!       key[keylen] = 0;
! 
!       if (code == '@')
! 	{
! 	  prefix = get_key_value (key);
! 	  if (prefix == 0)
! 	    prefix = std_prefix;
! 	}
!       else
! 	prefix = getenv (key);
  
!       if (prefix == 0)
! 	prefix = PREFIX;
  
!       /* We used to strip trailing DIR_SEPARATORs here, but that can
! 	 sometimes yield a result with no separator when one was coded
! 	 and intended by the user, causing two path components to run
! 	 together.  */
! 
!       old_name = name;
!       name = concat (prefix, &name[keylen + 1], NULL);
!       free (old_name);
!     }
  
!   return name;
! }
  
! /* In a NUL-terminated STRING, replace character C1 with C2 in-place.  */
! static void
! tr (string, c1, c2)
!      char *string;
!      int c1, c2;
! {
!   do
      {
!       if (*string == c1)
! 	*string = c2;
      }
!   while (*string++);
  }
  
! /* Update PATH using KEY if PATH starts with PREFIX.  The returned
!    string is always malloc-ed, and the caller is responsible for
!    freeing it.  */
  
! char *
  update_path (path, key)
    const char *path;
    const char *key;
  {
+   char *result;
+ 
    if (! strncmp (path, std_prefix, strlen (std_prefix)) && key != 0)
      {
!       bool free_key = false;
  
!       if (key[0] != '$')
! 	{
! 	  key = concat ("@", key, NULL);
! 	  free_key = true;
! 	}
! 
!       result = concat (key, &path[strlen (std_prefix)], NULL);
!       if (free_key)
! 	free ((char *) key);
!       result = translate_name (result);
      }
+   else
+     result = xstrdup (path);
  
  #ifdef UPDATE_PATH_HOST_CANONICALIZE
!   /* Perform host dependant canonicalization when needed.  */
!   UPDATE_PATH_HOST_CANONICALIZE (result);
  #endif
  
  #ifdef DIR_SEPARATOR_2
    /* Convert DIR_SEPARATOR_2 to DIR_SEPARATOR. */
!   if (DIR_SEPARATOR_2 != DIR_SEPARATOR)
!     tr (result, DIR_SEPARATOR_2, DIR_SEPARATOR);
  #endif
! 
  #if defined (DIR_SEPARATOR) && !defined (DIR_SEPARATOR_2)
    if (DIR_SEPARATOR != '/')
!     tr (result, '/', DIR_SEPARATOR);
  #endif
  
!   return result;
  }
  
  /* Reset the standard prefix */
============================================================
Index: gcc/prefix.h
*** prefix.h	2001/05/26 01:31:34	1.4
--- gcc/prefix.h	2001/08/12 11:22:31
*************** Boston, MA 02111-1307, USA.  */
*** 22,28 ****
  #ifndef GCC_PREFIX_H
  #define GCC_PREFIX_H
  
! extern const char *update_path PARAMS ((const char *, const char *));
  extern void set_std_prefix PARAMS ((const char *, int));
  
  #endif /* ! GCC_PREFIX_H */
--- 22,31 ----
  #ifndef GCC_PREFIX_H
  #define GCC_PREFIX_H
  
! /* Update PATH using KEY if PATH starts with PREFIX.  The returned
!    string is always malloc-ed, and the caller is responsible for
!    freeing it.  */
! extern char *update_path PARAMS ((const char *path, const char *key));
  extern void set_std_prefix PARAMS ((const char *, int));
  
  #endif /* ! GCC_PREFIX_H */
============================================================
Index: gcc/config/i386/xm-djgpp.h
*** xm-djgpp.h	2001/04/19 20:28:05	1.12
--- gcc/config/i386/xm-djgpp.h	2001/08/12 11:22:31
*************** Boston, MA 02111-1307, USA.  */
*** 82,108 ****
      md_exec_prefix = update_path (md_exec_prefix, NULL); \
    } while (0)
  
! /* Canonicalize paths containing '/dev/env/', especially those in
!    prefix.c.  */
! #define UPDATE_PATH_HOST_CANONICALIZE(PATH, KEY) \
!   do { \
!     if (strncmp (PATH, "/dev/env/", sizeof("/dev/env/") - 1) == 0) \
!       { \
!         static char *djdir; \
!         static int djdir_len; \
!         static char fixed_path[FILENAME_MAX + 1]; \
!         char *new_path; \
!         /* The default prefixes all use '/dev/env/DJDIR', so optimize \
!            for this. All other uses of '/dev/env/' go through \
!            libc's canonicalization function.  */ \
!         _fixpath (PATH, fixed_path); \
!         /* _fixpath removes any trailing '/', so add it back.  */ \
!         strcat (fixed_path, "/"); \
!         new_path = xstrdup (fixed_path); \
!         PATH = new_path; \
!         return PATH; \
!       } \
!     /* If DIR_SEPARATOR_2 isn't in PATH, nothing more need be done.  */ \
!     if (strchr (PATH, DIR_SEPARATOR_2) == NULL) \
!       return PATH; \
!   } while (0)
--- 82,98 ----
      md_exec_prefix = update_path (md_exec_prefix, NULL); \
    } while (0)
  
! /* Canonicalize paths containing '/dev/env/'; used in prefix.c.
!    _fixpath is a djgpp-specific function to canonicalize a path.
!    "/dev/env/DJDIR" evaluates to "c:/djgpp" if DJDIR is "c:/djgpp" for
!    example.  It removes any trailing '/', so add it back.  */
! #define UPDATE_PATH_HOST_CANONICALIZE(PATH) \
!   if (memcmp ((PATH), "/dev/env/", sizeof("/dev/env/") - 1) == 0) \
!     {						\
!       static char fixed_path[FILENAME_MAX + 1];	\
! 						\
!       _fixpath ((PATH), fixed_path);		\
!       strcat (fixed_path, "/");			\
!       free (PATH);				\
!       (PATH) = xstrdup (fixed_path);		\
!     } 
============================================================
Index: gcc/doc/gcc.texi
*** gcc.texi	2001/08/10 21:50:45	1.32
--- gcc/doc/gcc.texi	2001/08/12 11:22:54
*************** If defined, a C statement (sans semicolo
*** 4053,4064 ****
  initialization when a compilation driver is being initialized.
  
  @findex UPDATE_PATH_HOST_CANONICALIZE
! @item UPDATE_PATH_HOST_CANONICALIZE (@var{path}, @var{key})
  If defined, a C statement (sans semicolon) that performs host-dependent
! canonicalization when a path used in a compilation driver or preprocessor is
! canonicalized.  @var{path} is the path to be canonicalized, and @var{key} is
! a translation prefix when its value isn't @code{NULL}.  If the C statement
! does canonicalize @var{path}, the new path should be returned.
  @end table
  
  @findex bzero
--- 4053,4065 ----
  initialization when a compilation driver is being initialized.
  
  @findex UPDATE_PATH_HOST_CANONICALIZE
! @item UPDATE_PATH_HOST_CANONICALIZE (@var{path})
  If defined, a C statement (sans semicolon) that performs host-dependent
! canonicalization when a path used in a compilation driver or
! preprocessor is canonicalized.  @var{path} is a malloc-ed path to be
! canonicalized.  If the C statement does canonicalize @var{path} into a
! different buffer, the old path should be freed and the new buffer should
! have been allocated with malloc.
  @end table
  
  @findex bzero



More information about the Gcc-patches mailing list