[PATCH 08/13] sparse-checkout: always free "line" strbuf after reading input
- From
Jeff King <peff@peff.net>
- Date
- May 31, 2024, 11:34 UTC
- Message-ID
- <20240531113407.GH428814@coredump.intra.peff.net>
- In-Reply-To
- <20240531112433.GA428583@coredump.intra.peff.net>
In add_patterns_from_input(), we may read lines from a file with a loop like this:
while (!strbuf_getline(&line, file)) {
...
strbuf_to_cone_pattern(&line, pl);
}
/* we don't strbuf_release(&line) here! */This generally is OK because strbuf_to_cone_pattern() consumes the buffer via strbuf_detach(). But we can leak in a few cases:
1. We don't always consume the buffer! If the line ends up empty after
trimming, we leave strbuf_to_cone_pattern() without detaching. In
most cases this is OK, because a subsequent getline() call will use
the same buffer. But if you had an empty line at the end of file,
for example, it would leak. 2. Even if strbuf_to_cone_pattern() always consumed the buffer,
there's a subtle issue with strbuf_getline(). As we saw in
94e2aa555e (strbuf: fix leak when `appendwholeline()` fails with
EOF, 2024-05-27), it's possible for it to return EOF with an
allocated buffer (e.g., if the underlying getdelim() call saw an
error). So we should always strbuf_release() after finishing a read
loop like this.Note that even the code to read patterns from argv has the same problem. Because that also uses strbuf_to_cone_pattern(), we stuff each argv entry into a strbuf. It uses the same "line" strbuf as the getline code, but we should position the strbuf_release() to cover both code paths.
This fixes at least 9 leaks found in t1091.
Signed-off-by: Jeff King <peff@peff.net> --- This touches on the strbuf_appendwholeline() thing we were talking about in the earlier thread. But even if we taught strbuf_getline() to never return an allocated buf on EOF, we'd still need this because of point (1) above. I do suspect this anti-pattern may exist in more places, though (it was also present in the preimage of patch 7).
builtin/sparse-checkout.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c index 75c07d5bb4..8f8f5c359f 100644 --- a/builtin/sparse-checkout.c +++ b/builtin/sparse-checkout.c @@ -581,6 +581,7 @@ static void add_patterns_from_input(struct pattern_list *pl, strbuf_to_cone_pattern(&line, pl); } } + strbuf_release(&line); } else { if (file) { struct strbuf line = STRBUF_INIT;
-- 2.45.1.727.ge984192922