diff mbox series

[v2,2/3] sequencer: add a "goto cleanup" to do_reset()

Message ID patch-v2-2.3-1d5f5e9fff0-20211007T094019Z-avarab@gmail.com (mailing list archive)
State Superseded
Headers show
Series unpack-trees: memory-leak fixes | expand

Commit Message

Ævar Arnfjörð Bjarmason Oct. 7, 2021, 9:46 a.m. UTC
Restructure code that's mostly added in 9055e401dd6 (sequencer:
introduce new commands to reset the revision, 2018-04-25) to avoid
code duplication, and to make freeing other resources easier in a
subsequent commit.

It's safe to initialize "tree_desc" to be zero'd out in order to
unconditionally free desc.buffer, it won't be initialized on the first
couple of "goto"'s.

There are three earlier "return"'s in this function that I'm not
bothering to covert, those don't need to rollback anything, or free
any resources, so let's leave, even though they could safely "goto
cleanup" as well.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 sequencer.c | 32 +++++++++++++-------------------
 1 file changed, 13 insertions(+), 19 deletions(-)

Comments

Elijah Newren Oct. 7, 2021, 4:06 p.m. UTC | #1
On Thu, Oct 7, 2021 at 2:46 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> Restructure code that's mostly added in 9055e401dd6 (sequencer:
> introduce new commands to reset the revision, 2018-04-25) to avoid
> code duplication, and to make freeing other resources easier in a
> subsequent commit.

Since the first goto you add precedes the call to
setup_unpack_trees_porcelain(), the next commit will introduce a case
where some code calls clear_unpack_trees_porcelain() without having
first called setup_unpack_trees_porcelain().  With the current code
that is fine since you do initialize unpack_trees_opts to { 0 } first,
and clear_unpack_trees_porcelain() doesn't rely on any special setup,
but I wonder if the naming similarity of the two functions might lead
to future authors to presume they are always called in pairs.

I wonder if we should rename clear_unpack_trees_porcelain() to e.g.
unpack_trees_clear() just to avoid this problem, and then include the
other bits of your previous round to just make all callers of
unpack_trees() call unpack_trees_clear() when they are done.

Or, maybe we could just make unpack_trees() call unpack_trees_clear()
automatically and remove that responsibility from callers...except
that merge-recursive is weird and special and would need a new
function (unpack_trees_without_automatic_cleanup() or something like
that?) since it's the one caller that needs to use
unpack_trees_options data after calling unpack_trees().

So, multiple competing ideas here, and all for theoretical future code
safety.  As such, if any of it sounds like too much of a pain, I'm
fine with punting on it.

> It's safe to initialize "tree_desc" to be zero'd out in order to
> unconditionally free desc.buffer, it won't be initialized on the first
> couple of "goto"'s.
>
> There are three earlier "return"'s in this function that I'm not
> bothering to covert,

s/covert/convert/

> those don't need to rollback anything,

They aren't currently rolling back the lockfile right now, but I think
they should.  Those error cases are pretty unlikely to happen (hard
disk full?), but if they did, they'd leave the lock file in place.

Granted, that's a pre-existing problem rather than a problem
introduced by your patch, so it doesn't need to be part of this
series, but the commit message should at least be tweaked.

> or free any resources

True.

> , so let's leave, even though they could safely "goto
> cleanup" as well.



>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  sequencer.c | 32 +++++++++++++-------------------
>  1 file changed, 13 insertions(+), 19 deletions(-)
>
> diff --git a/sequencer.c b/sequencer.c
> index 6872b7b00a4..457eba4ab10 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -3650,7 +3650,7 @@ static int do_reset(struct repository *r,
>         struct strbuf ref_name = STRBUF_INIT;
>         struct object_id oid;
>         struct lock_file lock = LOCK_INIT;
> -       struct tree_desc desc;
> +       struct tree_desc desc = { 0 };
>         struct tree *tree;
>         struct unpack_trees_options unpack_tree_opts;
>         int ret = 0;
> @@ -3684,10 +3684,8 @@ static int do_reset(struct repository *r,
>                 strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
>                 if (get_oid(ref_name.buf, &oid) &&
>                     get_oid(ref_name.buf + strlen("refs/rewritten/"), &oid)) {
> -                       error(_("could not read '%s'"), ref_name.buf);
> -                       rollback_lock_file(&lock);
> -                       strbuf_release(&ref_name);
> -                       return -1;
> +                       ret = error(_("could not read '%s'"), ref_name.buf);
> +                       goto cleanup;
>                 }
>         }
>
> @@ -3703,24 +3701,18 @@ static int do_reset(struct repository *r,
>         init_checkout_metadata(&unpack_tree_opts.meta, name, &oid, NULL);
>
>         if (repo_read_index_unmerged(r)) {
> -               rollback_lock_file(&lock);
> -               strbuf_release(&ref_name);
> -               return error_resolve_conflict(_(action_name(opts)));
> +               ret = error_resolve_conflict(_(action_name(opts)));
> +               goto cleanup;
>         }
>
>         if (!fill_tree_descriptor(r, &desc, &oid)) {
> -               error(_("failed to find tree of %s"), oid_to_hex(&oid));
> -               rollback_lock_file(&lock);
> -               free((void *)desc.buffer);
> -               strbuf_release(&ref_name);
> -               return -1;
> +               ret = error(_("failed to find tree of %s"), oid_to_hex(&oid));
> +               goto cleanup;
>         }
>
>         if (unpack_trees(1, &desc, &unpack_tree_opts)) {
> -               rollback_lock_file(&lock);
> -               free((void *)desc.buffer);
> -               strbuf_release(&ref_name);
> -               return -1;
> +               ret = -1;
> +               goto cleanup;
>         }
>
>         tree = parse_tree_indirect(&oid);
> @@ -3728,13 +3720,15 @@ static int do_reset(struct repository *r,
>
>         if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
>                 ret = error(_("could not write index"));
> -       free((void *)desc.buffer);
>
>         if (!ret)
>                 ret = update_ref(reflog_message(opts, "reset", "'%.*s'",
>                                                 len, name), "HEAD", &oid,
>                                  NULL, 0, UPDATE_REFS_MSG_ON_ERR);
> -
> +cleanup:
> +       free((void *)desc.buffer);
> +       if (ret < 0)
> +               rollback_lock_file(&lock);
>         strbuf_release(&ref_name);
>         return ret;
>  }
> --
> 2.33.0.1446.g6af949f83bd
>
diff mbox series

Patch

diff --git a/sequencer.c b/sequencer.c
index 6872b7b00a4..457eba4ab10 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -3650,7 +3650,7 @@  static int do_reset(struct repository *r,
 	struct strbuf ref_name = STRBUF_INIT;
 	struct object_id oid;
 	struct lock_file lock = LOCK_INIT;
-	struct tree_desc desc;
+	struct tree_desc desc = { 0 };
 	struct tree *tree;
 	struct unpack_trees_options unpack_tree_opts;
 	int ret = 0;
@@ -3684,10 +3684,8 @@  static int do_reset(struct repository *r,
 		strbuf_addf(&ref_name, "refs/rewritten/%.*s", len, name);
 		if (get_oid(ref_name.buf, &oid) &&
 		    get_oid(ref_name.buf + strlen("refs/rewritten/"), &oid)) {
-			error(_("could not read '%s'"), ref_name.buf);
-			rollback_lock_file(&lock);
-			strbuf_release(&ref_name);
-			return -1;
+			ret = error(_("could not read '%s'"), ref_name.buf);
+			goto cleanup;
 		}
 	}
 
@@ -3703,24 +3701,18 @@  static int do_reset(struct repository *r,
 	init_checkout_metadata(&unpack_tree_opts.meta, name, &oid, NULL);
 
 	if (repo_read_index_unmerged(r)) {
-		rollback_lock_file(&lock);
-		strbuf_release(&ref_name);
-		return error_resolve_conflict(_(action_name(opts)));
+		ret = error_resolve_conflict(_(action_name(opts)));
+		goto cleanup;
 	}
 
 	if (!fill_tree_descriptor(r, &desc, &oid)) {
-		error(_("failed to find tree of %s"), oid_to_hex(&oid));
-		rollback_lock_file(&lock);
-		free((void *)desc.buffer);
-		strbuf_release(&ref_name);
-		return -1;
+		ret = error(_("failed to find tree of %s"), oid_to_hex(&oid));
+		goto cleanup;
 	}
 
 	if (unpack_trees(1, &desc, &unpack_tree_opts)) {
-		rollback_lock_file(&lock);
-		free((void *)desc.buffer);
-		strbuf_release(&ref_name);
-		return -1;
+		ret = -1;
+		goto cleanup;
 	}
 
 	tree = parse_tree_indirect(&oid);
@@ -3728,13 +3720,15 @@  static int do_reset(struct repository *r,
 
 	if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)
 		ret = error(_("could not write index"));
-	free((void *)desc.buffer);
 
 	if (!ret)
 		ret = update_ref(reflog_message(opts, "reset", "'%.*s'",
 						len, name), "HEAD", &oid,
 				 NULL, 0, UPDATE_REFS_MSG_ON_ERR);
-
+cleanup:
+	free((void *)desc.buffer);
+	if (ret < 0)
+		rollback_lock_file(&lock);
 	strbuf_release(&ref_name);
 	return ret;
 }