From: jtc@gain.COM (J.T. Conklin)
Subject: Memory leaks in Gnu Make 3.62
Reply-To: jtc@gain.com
Organization: GNUs Not Usenet
Distribution: gnu
Date: Wed, 7 Oct 1992 04:40:23 GMT

After seeing John Gilmore's fixes/speedups to Make, I decided to use
purify to see if Make had any significant memory leaks.

I discovered that over 15% (A few hundred K) of the heap was leaked
memory with our makefiles.  I was able to reduce that to just over a
1000 bytes with very few changes.

The enclosed patch fixes the most significant leaks, and some trivial,
easy to fix ones.  If you are on a system with not a lot of memory,
MSDOS, Xenix 286, etc., you may want to apply this patch.

	--jtc

diff -c gnu/make/Makefile:1.1.1.1 gnu/make/Makefile:1.3
*** gnu/make/Makefile:1.1.1.1	Wed Oct  7 10:59:29 1992
--- gnu/make/Makefile	Wed Oct  7 10:59:30 1992
***************
*** 102,111 ****

  objs = commands.o job.o dir.o file.o load.o misc.o main.o read.o \
         remake.o remote.o rule.o implicit.o default.o variable.o expand.o \
!        function.o vpath.o version.o $(ARCHIVES) $(ALLOCA) $(extras)
  srcs = commands.c job.c dir.c file.c load.c misc.c main.c read.c \
         remake.c remote.c rule.c implicit.c default.c variable.c expand.c \
!        function.c vpath.c version.c $(ALLOCASRC) $(ARCHIVES_SRC) \
         commands.h dep.h file.h job.h make.h rule.h variable.h


--- 102,113 ----

  objs = commands.o job.o dir.o file.o load.o misc.o main.o read.o \
         remake.o remote.o rule.o implicit.o default.o variable.o expand.o \
!        function.o vpath.o version.o basename.o dirname.o $(ALLOCA) \
!        $(ARCHIVES) $(extras)
  srcs = commands.c job.c dir.c file.c load.c misc.c main.c read.c \
         remake.c remote.c rule.c implicit.c default.c variable.c expand.c \
!        function.c vpath.c version.c basename.c dirname.c $(ALLOCASRC) \
!        $(ARCHIVES_SRC) \
         commands.h dep.h file.h job.h make.h rule.h variable.h


diff -c /dev/null gnu/make/basename.c:1.1
*** /dev/null	Wed Oct  7 10:59:30 1992
--- gnu/make/basename.c	Wed Oct  7 10:59:30 1992
***************
*** 0 ****
--- 1,35 ----
+ /* basename.c -- return the last element in a path
+    Copyright (C) 1990 Free Software Foundation, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+ #if defined(USG) || defined(STDC_HEADERS)
+ #include <string.h>
+ #define rindex strrchr
+ #else
+ #include <strings.h>
+ #endif
+
+ /* Return NAME with any leading path stripped off.  */
+
+ char *
+ basename (name)
+      char *name;
+ {
+   char *base;
+
+   base = rindex (name, '/');
+   return base ? base + 1 : name;
+ }
diff -c gnu/make/commands.c:1.1.1.1 gnu/make/commands.c:1.2
*** gnu/make/commands.c:1.1.1.1	Wed Oct  7 10:59:31 1992
--- gnu/make/commands.c	Wed Oct  7 10:59:31 1992
***************
*** 56,62 ****
  #endif	/* NO_ARCHIVES.  */
      {
        at = savestring (file->name, strlen (file->name));
!       percent = "";
      }

    DEFINE_VARIABLE ("@", 1, at);
--- 56,62 ----
  #endif	/* NO_ARCHIVES.  */
      {
        at = savestring (file->name, strlen (file->name));
!       percent = savestring ("", 0);
      }

    DEFINE_VARIABLE ("@", 1, at);
***************
*** 63,71 ****
    DEFINE_VARIABLE ("%", 1, percent);

  #define	LASTSLASH(s)	rindex ((s), '/')
- #define	FILEONLY(s)	(p != 0 ? p + 1 : (s))
- #define	DIRONLY(s)	(p == 0 ? "./" : p == (s) ? "/" \
- 			 : savestring ((s), (p - (s)) + 1))

    /* $* is the stem from an implicit or static pattern rule.  */
    if (file->stem == 0)
--- 63,68 ----
***************
*** 102,120 ****
    DEFINE_VARIABLE ("<", 1, less);

    /* Set up the D and F versions.  */
!   p = LASTSLASH (at);
!   DEFINE_VARIABLE ("@D", 2, DIRONLY (at));
!   DEFINE_VARIABLE ("@F", 2, FILEONLY (at));
!   p = LASTSLASH (star);
!   DEFINE_VARIABLE ("*D", 2, DIRONLY (star));
!   DEFINE_VARIABLE ("*F", 2, FILEONLY (star));
!   p = LASTSLASH (less);
!   DEFINE_VARIABLE ("<D", 2, DIRONLY (less));
!   DEFINE_VARIABLE ("<F", 2, FILEONLY (less));
!   p = LASTSLASH (percent);
!   DEFINE_VARIABLE ("%D", 2, DIRONLY (percent));
!   DEFINE_VARIABLE ("%F", 2, FILEONLY (percent));

    /* Compute the values for $^ and $? and their F and D versions.  */

    {
--- 99,124 ----
    DEFINE_VARIABLE ("<", 1, less);

    /* Set up the D and F versions.  */
!   p = dirname (at);
!   DEFINE_VARIABLE ("@D", 2, p);
!   DEFINE_VARIABLE ("@F", 2, basename (at));
!   free (p);
!   p = dirname (star);
!   DEFINE_VARIABLE ("*D", 2, p);
!   DEFINE_VARIABLE ("*F", 2, basename (star));
!   free (p);
!   p = dirname (less);
!   DEFINE_VARIABLE ("<D", 2, p);
!   DEFINE_VARIABLE ("<F", 2, basename (less));
!   free (p);
!   p = dirname (percent);
!   DEFINE_VARIABLE ("%D", 2, p);
!   DEFINE_VARIABLE ("%F", 2, basename (percent));
!   free (p);

+   free(at);
+   free(percent);
+
    /* Compute the values for $^ and $? and their F and D versions.  */

    {
***************
*** 213,224 ****
      DEFINE_VARIABLE ("?D", 2, qmarkD_value);
      qFp[qFp > qmarkF_value ? -1 : 0] = '\0';
      DEFINE_VARIABLE ("?F", 2, qmarkF_value);
    }

  #undef	LASTSLASH
- #undef	FILEONLY
- #undef	DIRONLY
-
  #undef	DEFINE_VARIABLE
  }
  
--- 217,232 ----
      DEFINE_VARIABLE ("?D", 2, qmarkD_value);
      qFp[qFp > qmarkF_value ? -1 : 0] = '\0';
      DEFINE_VARIABLE ("?F", 2, qmarkF_value);
+
+     free(caret_value);
+     free(caretD_value);
+     free(caretF_value);
+     free(qmark_value);
+     free(qmarkD_value);
+     free(qmarkF_value);
    }

  #undef	LASTSLASH
  #undef	DEFINE_VARIABLE
  }
  
diff -c /dev/null gnu/make/dirname.c:1.1
*** /dev/null	Wed Oct  7 10:59:31 1992
--- gnu/make/dirname.c	Wed Oct  7 10:59:31 1992
***************
*** 0 ****
--- 1,64 ----
+ /* dirname.c -- return all but the last element in a path
+    Copyright (C) 1990 Free Software Foundation, Inc.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2, or (at your option)
+    any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+
+ #ifdef STDC_HEADERS
+ #include <stdlib.h>
+ #else
+ char *malloc ();
+ #endif
+ #if defined(USG) || defined(STDC_HEADERS)
+ #include <string.h>
+ #define rindex strrchr
+ #else
+ #include <strings.h>
+ #endif
+
+ /* Return the leading directories part of PATH,
+    allocated with malloc.  If out of memory, return 0.
+    Assumes that trailing slashes have already been
+    removed.  */
+
+ char *
+ dirname (path)
+      char *path;
+ {
+   char *newpath;
+   char *slash;
+   int length;			/* Length of result, not including NUL.  */
+
+   slash = rindex (path, '/');
+   if (slash == 0)
+     {
+       /* File is in the current directory.  */
+       path = ".";
+       length = 1;
+     }
+   else
+     {
+       /* Remove any trailing slashes from the result.  */
+       while (slash > path && *slash == '/')
+ 	--slash;
+
+       length = slash - path + 1;
+     }
+   newpath = malloc (length + 1);
+   if (newpath == 0)
+     return 0;
+   strncpy (newpath, path, length);
+   newpath[length] = 0;
+   return newpath;
+ }
diff -c gnu/make/read.c:1.1.1.1 gnu/make/read.c:1.3
*** gnu/make/read.c:1.1.1.1	Wed Oct  7 10:59:32 1992
--- gnu/make/read.c	Wed Oct  7 10:59:32 1992
***************
*** 628,633 ****
--- 628,634 ----
  	    definition[idx - 1] = '\0';
  	  (void) define_variable (name, namelen, definition, origin, 1);
  	  free (definition);
+ 	  freebuffer(&lb);
  	  return lineno;
  	}
        else
***************
*** 1048,1054 ****
  	  /* Defining .SUFFIXES with no dependencies
  	     clears out the list of suffixes.  */
  	  if (f == suffix_file && this == 0)
! 	    f->deps = 0;
  	  else if (f->deps != 0)
  	    {
  	      d = f->deps;
--- 1049,1064 ----
  	  /* Defining .SUFFIXES with no dependencies
  	     clears out the list of suffixes.  */
  	  if (f == suffix_file && this == 0)
! 	    {
! 	      struct dep *nextd;
! 	      for (d = f->deps; d != 0; d = nextd)
! 		{
! 		  nextd = d->next;
! 		  free(d->name);
! 		  free(d);
! 		}
! 	      f->deps = 0;
! 	    }
  	  else if (f->deps != 0)
  	    {
  	      d = f->deps;
***************
*** 1536,1541 ****
--- 1546,1553 ----
  		elt->next = new;
  		new = elt;
  	      }
+ 	    free (old->name);
+ 	    free (old);
  	    globfree (&gl);
  	    break;
  	  }
diff -c gnu/make/variable.c:1.1.1.1 gnu/make/variable.c:1.2
*** gnu/make/variable.c:1.1.1.1	Wed Oct  7 10:59:33 1992
--- gnu/make/variable.c	Wed Oct  7 10:59:33 1992
***************
*** 105,110 ****
--- 105,114 ----
  	 than this one, don't redefine it.  */
        if ((int) origin >= (int) v->origin)
  	{
+ 	  if (v->value != 0)
+ 	    {
+ 	      free(v->value);
+ 	    }
  	  v->value = savestring (value, strlen (value));
  	  v->origin = origin;
  	  v->recursive = recursive;

Newsgroups: gnu.utils.bug