Module Name:    src
Committed By:   rillig
Date:           Mon Dec 13 05:25:04 UTC 2021

Modified Files:
        src/usr.bin/make: main.c make.h parse.c str.c str.h

Log Message:
make: fix memory leak for filenames in .for loops (since 2013-06-18)

Previously, each time a .for directive pushed its buffer on the input
file stack, the current filename was duplicated.  This was a waste of
memory.

The name of a file is typically only used while it is read in.  There is
one situation when the filename is needed for longer, which is when a
target is defined.

Since .for loops are implemented as a special form of included files,
each .for loop duplicated the current filename as well.

$ cat << EOF > for.mk
.for i in 1 2 3 4 5 6 7 8 9 0
.for i in 1 2 3 4 5 6 7 8 9 0
.for i in 1 2 3 4 5 6 7 8 9 0
.for i in 1 2 3 4 5 6 7 8 9 0
.for i in 1 2 3 4 5 6 7 8 9 0
.for i in 1 2 3 4 5 6 7 8 9 0
.for i in 1 2 3 4 5 6 7 8 9 0
.endfor
.endfor
.endfor
.endfor
.endfor
.endfor
.endfor

all:
        @ps -o rsz -p ${.MAKE.PID}
EOF

$ make-2021.12.13.03.55.16 -r -f for.mk
  RSZ
10720

$ ./make -r -f for.mk
 RSZ
1716

The difference is 8 MB, which amounts to 1 million .for loops.


To generate a diff of this commit:
cvs rdiff -u -r1.541 -r1.542 src/usr.bin/make/main.c
cvs rdiff -u -r1.270 -r1.271 src/usr.bin/make/make.h
cvs rdiff -u -r1.575 -r1.576 src/usr.bin/make/parse.c
cvs rdiff -u -r1.86 -r1.87 src/usr.bin/make/str.c
cvs rdiff -u -r1.13 -r1.14 src/usr.bin/make/str.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/make/main.c
diff -u src/usr.bin/make/main.c:1.541 src/usr.bin/make/main.c:1.542
--- src/usr.bin/make/main.c:1.541	Sat Aug 14 13:32:12 2021
+++ src/usr.bin/make/main.c	Mon Dec 13 05:25:04 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: main.c,v 1.541 2021/08/14 13:32:12 rillig Exp $	*/
+/*	$NetBSD: main.c,v 1.542 2021/12/13 05:25:04 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -111,7 +111,7 @@
 #include "trace.h"
 
 /*	"@(#)main.c	8.3 (Berkeley) 3/19/94"	*/
-MAKE_RCSID("$NetBSD: main.c,v 1.541 2021/08/14 13:32:12 rillig Exp $");
+MAKE_RCSID("$NetBSD: main.c,v 1.542 2021/12/13 05:25:04 rillig Exp $");
 #if defined(MAKE_NATIVE) && !defined(lint)
 __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
 	    "The Regents of the University of California.  "
@@ -1346,6 +1346,7 @@ main_Init(int argc, char **argv)
 	/* default to writing debug to stderr */
 	opts.debug_file = stderr;
 
+	Str_Intern_Init();
 	HashTable_Init(&cached_realpaths);
 
 #ifdef SIGINFO

Index: src/usr.bin/make/make.h
diff -u src/usr.bin/make/make.h:1.270 src/usr.bin/make/make.h:1.271
--- src/usr.bin/make/make.h:1.270	Sun Nov 28 23:12:51 2021
+++ src/usr.bin/make/make.h	Mon Dec 13 05:25:04 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: make.h,v 1.270 2021/11/28 23:12:51 rillig Exp $	*/
+/*	$NetBSD: make.h,v 1.271 2021/12/13 05:25:04 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -435,8 +435,7 @@ typedef struct GNode {
 	 * everyone but the Suff module) */
 	struct Suffix *suffix;
 
-	/* Filename where the GNode got defined */
-	/* XXX: What is the lifetime of this string? */
+	/* Filename where the GNode got defined, unlimited lifetime */
 	const char *fname;
 	/* Line number where the GNode got defined */
 	int lineno;

Index: src/usr.bin/make/parse.c
diff -u src/usr.bin/make/parse.c:1.575 src/usr.bin/make/parse.c:1.576
--- src/usr.bin/make/parse.c:1.575	Mon Dec 13 00:09:07 2021
+++ src/usr.bin/make/parse.c	Mon Dec 13 05:25:04 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: parse.c,v 1.575 2021/12/13 00:09:07 rillig Exp $	*/
+/*	$NetBSD: parse.c,v 1.576 2021/12/13 05:25:04 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -109,7 +109,7 @@
 #include "pathnames.h"
 
 /*	"@(#)parse.c	8.3 (Berkeley) 3/19/94"	*/
-MAKE_RCSID("$NetBSD: parse.c,v 1.575 2021/12/13 00:09:07 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.576 2021/12/13 05:25:04 rillig Exp $");
 
 /* types and constants */
 
@@ -117,7 +117,7 @@ MAKE_RCSID("$NetBSD: parse.c,v 1.575 202
  * Structure for a file being read ("included file")
  */
 typedef struct IFile {
-	char *fname;		/* name of file (relative? absolute?) */
+	FStr name;		/* absolute or relative to the cwd */
 	bool fromForLoop;	/* simulated .include by the .for loop */
 	int lineno;		/* current line number in file */
 	int first_lineno;	/* line number of start of text */
@@ -491,7 +491,7 @@ PrintStackTrace(void)
 
 	for (i = n; i-- > 0;) {
 		const IFile *entry = entries + i;
-		const char *fname = entry->fname;
+		const char *fname = entry->name.str;
 		bool printLineno;
 		char dirbuf[MAXPATHLEN + 1];
 
@@ -533,7 +533,7 @@ static void
 RememberLocation(GNode *gn)
 {
 	IFile *curFile = CurFile();
-	gn->fname = curFile->fname;
+	gn->fname = Str_Intern(curFile->name.str);
 	gn->lineno = curFile->lineno;
 }
 
@@ -662,7 +662,7 @@ Parse_Error(ParseErrorLevel type, const 
 		lineno = 0;
 	} else {
 		IFile *curFile = CurFile();
-		fname = curFile->fname;
+		fname = curFile->name.str;
 		lineno = (size_t)curFile->lineno;
 	}
 
@@ -2143,7 +2143,7 @@ IncludeFile(const char *file, bool isSys
 		 * we can locate the file.
 		 */
 
-		incdir = bmake_strdup(CurFile()->fname);
+		incdir = bmake_strdup(CurFile()->name.str);
 		slash = strrchr(incdir, '/');
 		if (slash != NULL) {
 			*slash = '\0';
@@ -2322,7 +2322,7 @@ GetActuallyIncludingFile(void)
 
 	for (i = includes.len; i >= 2; i--)
 		if (!incs[i - 1].fromForLoop)
-			return incs[i - 2].fname;
+			return incs[i - 2].name.str;
 	return NULL;
 }
 
@@ -2413,7 +2413,7 @@ Parse_PushInput(const char *name, int li
 	bool fromForLoop = name == NULL;
 
 	if (fromForLoop)
-		name = CurFile()->fname;
+		name = CurFile()->name.str;
 	else
 		ParseTrackInput(name);
 
@@ -2426,7 +2426,7 @@ Parse_PushInput(const char *name, int li
 		return;
 
 	curFile = Vector_Push(&includes);
-	curFile->fname = bmake_strdup(name);
+	curFile->name = FStr_InitOwn(bmake_strdup(name));
 	curFile->fromForLoop = fromForLoop;
 	curFile->lineno = lineno;
 	curFile->first_lineno = lineno;
@@ -2441,8 +2441,7 @@ Parse_PushInput(const char *name, int li
 	buf = curFile->readMore(curFile->readMoreArg, &len);
 	if (buf == NULL) {
 		/* Was all a waste of time ... */
-		if (curFile->fname != NULL)
-			free(curFile->fname);
+		FStr_Done(&curFile->name);
 		free(curFile);
 		return;
 	}
@@ -2605,8 +2604,7 @@ ParseEOF(void)
 		curFile->lf = NULL;
 	}
 
-	/* Dispose of curFile info */
-	/* Leak curFile->fname because all the GNodes have pointers to it. */
+	FStr_Done(&curFile->name);
 	free(curFile->buf_freeIt);
 	Vector_Pop(&includes);
 
@@ -2621,9 +2619,9 @@ ParseEOF(void)
 
 	curFile = CurFile();
 	DEBUG2(PARSE, "ParseEOF: returning to file %s, line %d\n",
-	    curFile->fname, curFile->lineno);
+	    curFile->name.str, curFile->lineno);
 
-	ParseSetParseFile(curFile->fname);
+	ParseSetParseFile(curFile->name.str);
 	return true;
 }
 

Index: src/usr.bin/make/str.c
diff -u src/usr.bin/make/str.c:1.86 src/usr.bin/make/str.c:1.87
--- src/usr.bin/make/str.c:1.86	Mon Jun 21 16:59:18 2021
+++ src/usr.bin/make/str.c	Mon Dec 13 05:25:04 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: str.c,v 1.86 2021/06/21 16:59:18 rillig Exp $	*/
+/*	$NetBSD: str.c,v 1.87 2021/12/13 05:25:04 rillig Exp $	*/
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -71,7 +71,11 @@
 #include "make.h"
 
 /*	"@(#)str.c	5.8 (Berkeley) 6/1/90"	*/
-MAKE_RCSID("$NetBSD: str.c,v 1.86 2021/06/21 16:59:18 rillig Exp $");
+MAKE_RCSID("$NetBSD: str.c,v 1.87 2021/12/13 05:25:04 rillig Exp $");
+
+
+static HashTable interned_strings;
+
 
 /* Return the concatenation of s1 and s2, freshly allocated. */
 char *
@@ -395,3 +399,16 @@ Str_Match(const char *str, const char *p
 		str++;
 	}
 }
+
+void
+Str_Intern_Init(void)
+{
+	HashTable_Init(&interned_strings);
+}
+
+/* Return a canonical instance of str, with unlimited lifetime. */
+const char *
+Str_Intern(const char *str)
+{
+	return HashTable_CreateEntry(&interned_strings, str, NULL)->key;
+}

Index: src/usr.bin/make/str.h
diff -u src/usr.bin/make/str.h:1.13 src/usr.bin/make/str.h:1.14
--- src/usr.bin/make/str.h:1.13	Sun Dec 12 23:39:34 2021
+++ src/usr.bin/make/str.h	Mon Dec 13 05:25:04 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: str.h,v 1.13 2021/12/12 23:39:34 rillig Exp $	*/
+/*	$NetBSD: str.h,v 1.14 2021/12/13 05:25:04 rillig Exp $	*/
 
 /*
  Copyright (c) 2021 Roland Illig <ril...@netbsd.org>
@@ -343,3 +343,6 @@ char *str_concat2(const char *, const ch
 char *str_concat3(const char *, const char *, const char *);
 
 bool Str_Match(const char *, const char *);
+
+void Str_Intern_Init(void);
+const char *Str_Intern(const char *);

Reply via email to