diff mbox series

[08/20] midx-write: fix leaking hashfile on error cases

Message ID 5f042ce5098563aa0662026006c356c278dad0b8.1724159575.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series Memory leak fixes (pt.5) | expand

Commit Message

Patrick Steinhardt Aug. 20, 2024, 2:05 p.m. UTC
When writing the MIDX file we first create the `struct hashfile` used to
write the trailer hash, and then afterwards we verify whether we can
actually write the MIDX in the first place. When we decide that we
can't, this leads to a memory leak because we never free the hash file
contents.

We could fix this by freeing the hashfile on the exit path. There is a
better option though: we can simply move the checks for the error
condition earlier. As there is no early exit between creating the
hashfile and finalizing it anymore this is sufficient to fix the memory
leak.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 midx-write.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

Comments

Junio C Hamano Aug. 20, 2024, 11:19 p.m. UTC | #1
Patrick Steinhardt <ps@pks.im> writes:

> When writing the MIDX file we first create the `struct hashfile` used to
> write the trailer hash, and then afterwards we verify whether we can
> actually write the MIDX in the first place. When we decide that we
> can't, this leads to a memory leak because we never free the hash file
> contents.
>
> We could fix this by freeing the hashfile on the exit path. There is a
> better option though: we can simply move the checks for the error
> condition earlier. As there is no early exit between creating the
> hashfile and finalizing it anymore this is sufficient to fix the memory
> leak.

The above is a good explanation why "are we dropping everything"
block was moved up, but does not explain why the other "if there is
no objects" block has to move (it is however easy to see that the
latter block can be moved without any bad side effect).

In any case, the struct hashfile hashfd() gives us is now associated
with the struct chunkfile cf immediately after it is instanciated,
and there is no early exit while the chunkfile is in use, which is
great.
Patrick Steinhardt Aug. 22, 2024, 8:19 a.m. UTC | #2
On Tue, Aug 20, 2024 at 04:19:13PM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
> 
> > When writing the MIDX file we first create the `struct hashfile` used to
> > write the trailer hash, and then afterwards we verify whether we can
> > actually write the MIDX in the first place. When we decide that we
> > can't, this leads to a memory leak because we never free the hash file
> > contents.
> >
> > We could fix this by freeing the hashfile on the exit path. There is a
> > better option though: we can simply move the checks for the error
> > condition earlier. As there is no early exit between creating the
> > hashfile and finalizing it anymore this is sufficient to fix the memory
> > leak.
> 
> The above is a good explanation why "are we dropping everything"
> block was moved up, but does not explain why the other "if there is
> no objects" block has to move (it is however easy to see that the
> latter block can be moved without any bad side effect).
> 
> In any case, the struct hashfile hashfd() gives us is now associated
> with the struct chunkfile cf immediately after it is instanciated,
> and there is no early exit while the chunkfile is in use, which is
> great.

There basically is no reason why the other block needs to move. It just
felt more natural to keep massaging of parameters closly together before
we go off and actually do "the thing". I'll document this accordingly.

Patrick
diff mbox series

Patch

diff --git a/midx-write.c b/midx-write.c
index e3fa33203fa..07d98d494aa 100644
--- a/midx-write.c
+++ b/midx-write.c
@@ -1308,6 +1308,18 @@  static int write_midx_internal(const char *object_dir,
 		pack_name_concat_len += MIDX_CHUNK_ALIGNMENT -
 					(pack_name_concat_len % MIDX_CHUNK_ALIGNMENT);
 
+	if (ctx.nr - dropped_packs == 0) {
+		error(_("no pack files to index."));
+		result = 1;
+		goto cleanup;
+	}
+
+	if (!ctx.entries_nr) {
+		if (flags & MIDX_WRITE_BITMAP)
+			warning(_("refusing to write multi-pack .bitmap without any objects"));
+		flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
+	}
+
 	if (ctx.incremental) {
 		struct strbuf lock_name = STRBUF_INIT;
 
@@ -1333,18 +1345,6 @@  static int write_midx_internal(const char *object_dir,
 		f = hashfd(get_lock_file_fd(&lk), get_lock_file_path(&lk));
 	}
 
-	if (ctx.nr - dropped_packs == 0) {
-		error(_("no pack files to index."));
-		result = 1;
-		goto cleanup;
-	}
-
-	if (!ctx.entries_nr) {
-		if (flags & MIDX_WRITE_BITMAP)
-			warning(_("refusing to write multi-pack .bitmap without any objects"));
-		flags &= ~(MIDX_WRITE_REV_INDEX | MIDX_WRITE_BITMAP);
-	}
-
 	cf = init_chunkfile(f);
 
 	add_chunk(cf, MIDX_CHUNKID_PACKNAMES, pack_name_concat_len,