Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/make make: fix memory leak in LazyBuf



details:   https://anonhg.NetBSD.org/src/rev/742089430ef2
branches:  trunk
changeset: 1027581:742089430ef2
user:      rillig <rillig%NetBSD.org@localhost>
date:      Sun Dec 12 13:43:47 2021 +0000

description:
make: fix memory leak in LazyBuf

This affects many operations on variable expressions.  Those using
LazyBuf_Done are affected, those using LazyBuf_DoneGet aren't.

$ cat <<'EOF' > lazybuf-memleak.mk
.for i in ${:U:range=5}
.  for j in ${:U:range=1000}
.    for k in ${:U:range=1000}
.      if 0 && ${VAR:Dpattern\: that needs unescaping}
.      endif
.    endfor
.  endfor
.endfor

all:
        @ps -o vsz -p ${.MAKE.PID} | sed 1d
EOF

Before using LazyBuf for the modifier ':D':

    $ make-2021.04.14.16.12.26 -r -f lazybuf-memleak.mk
        VSZ     RSZ
    1357136 1336432

Using LazyBuf for the modifier ':D':

    $ make-2021.04.14.16.59.34 -r -f lazybuf-memleak.mk
        VSZ     RSZ
    1590864 1574164

This commit alone allocates around 150 MB more data, which matches
5_000_000 strings * 30 bytes/string.

It looks very wrong that the above simple makefile uses 1.3 GB of RAM at
all, and it had already done this in 2017, long before LazyBuf was
introduced.  Before 2017.01.30.02.46.20, the above test makefile reports
way smaller numbers, but that's because the modifier ':range' did not
exist back then.

diffstat:

 usr.bin/make/str.h |  11 +++++++----
 1 files changed, 7 insertions(+), 4 deletions(-)

diffs (44 lines):

diff -r 875c577fb8c9 -r 742089430ef2 usr.bin/make/str.h
--- a/usr.bin/make/str.h        Sun Dec 12 13:05:13 2021 +0000
+++ b/usr.bin/make/str.h        Sun Dec 12 13:43:47 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: str.h,v 1.11 2021/12/05 12:17:49 rillig Exp $  */
+/*     $NetBSD: str.h,v 1.12 2021/12/12 13:43:47 rillig Exp $  */
 
 /*
  Copyright (c) 2021 Roland Illig <rillig%NetBSD.org@localhost>
@@ -60,7 +60,6 @@
        size_t len;
        size_t cap;
        const char *expected;
-       void *freeIt;
 } LazyBuf;
 
 /* The result of splitting a string into words. */
@@ -274,13 +273,12 @@
        buf->len = 0;
        buf->cap = 0;
        buf->expected = expected;
-       buf->freeIt = NULL;
 }
 
 MAKE_INLINE void
 LazyBuf_Done(LazyBuf *buf)
 {
-       free(buf->freeIt);
+       free(buf->data);
 }
 
 MAKE_STATIC void
@@ -337,6 +335,11 @@
        return Substring_Init(start, start + buf->len);
 }
 
+/*
+ * Returns the content of the buffer as a newly allocated string.
+ *
+ * See LazyBuf_Get to avoid unnecessary memory allocations.
+ */
 MAKE_STATIC FStr
 LazyBuf_DoneGet(LazyBuf *buf)
 {



Home | Main Index | Thread Index | Old Index