unpack_trees_options: free messages when done

The strings allocated in `setup_unpack_trees_porcelain()` are never
freed. Provide a function `clear_unpack_trees_porcelain()` to do so and
call it where we use `setup_unpack_trees_porcelain()`. The only
non-trivial user is `unpack_trees_start()`, where we should place the
new call in `unpack_trees_finish()`.

We keep the string pointers in an array, mixing pointers to static
memory and memory that we allocate on the heap. We also keep several
copies of the individual pointers. So we need to make sure that we do
not free what we must not free and that we do not double-free. Let a
separate argv_array take ownership of all the strings we create so that
we can easily free them.

Zero the whole array of string pointers to make sure that we do not
leave any dangling pointers.

Note that we only take responsibility for the memory allocated in
`setup_unpack_trees_porcelain()` and not any other members of the
`struct unpack_trees_options`.

Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Martin Ågren 2018-05-21 16:54:28 +02:00 committed by Junio C Hamano
parent 342c513a4a
commit 1c41d2805e
5 changed files with 26 additions and 4 deletions

View File

@ -526,6 +526,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
init_tree_desc(&trees[1], tree->buffer, tree->size); init_tree_desc(&trees[1], tree->buffer, tree->size);
ret = unpack_trees(2, trees, &topts); ret = unpack_trees(2, trees, &topts);
clear_unpack_trees_porcelain(&topts);
if (ret == -1) { if (ret == -1) {
/* /*
* Unpack couldn't do a trivial merge; either * Unpack couldn't do a trivial merge; either

View File

@ -382,6 +382,7 @@ static int unpack_trees_start(struct merge_options *o,
static void unpack_trees_finish(struct merge_options *o) static void unpack_trees_finish(struct merge_options *o)
{ {
discard_index(&o->orig_index); discard_index(&o->orig_index);
clear_unpack_trees_porcelain(&o->unpack_opts);
} }
struct tree *write_tree_from_memory(struct merge_options *o) struct tree *write_tree_from_memory(struct merge_options *o)

View File

@ -130,8 +130,11 @@ int checkout_fast_forward(const struct object_id *head,
if (unpack_trees(nr_trees, t, &opts)) { if (unpack_trees(nr_trees, t, &opts)) {
rollback_lock_file(&lock_file); rollback_lock_file(&lock_file);
clear_unpack_trees_porcelain(&opts);
return -1; return -1;
} }
clear_unpack_trees_porcelain(&opts);
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK)) if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
return error(_("unable to write new index file")); return error(_("unable to write new index file"));
return 0; return 0;

View File

@ -1,5 +1,6 @@
#define NO_THE_INDEX_COMPATIBILITY_MACROS #define NO_THE_INDEX_COMPATIBILITY_MACROS
#include "cache.h" #include "cache.h"
#include "argv-array.h"
#include "repository.h" #include "repository.h"
#include "config.h" #include "config.h"
#include "dir.h" #include "dir.h"
@ -103,6 +104,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
const char **msgs = opts->msgs; const char **msgs = opts->msgs;
const char *msg; const char *msg;
argv_array_init(&opts->msgs_to_free);
if (!strcmp(cmd, "checkout")) if (!strcmp(cmd, "checkout"))
msg = advice_commit_before_merge msg = advice_commit_before_merge
? _("Your local changes to the following files would be overwritten by checkout:\n%%s" ? _("Your local changes to the following files would be overwritten by checkout:\n%%s"
@ -119,7 +122,7 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
"Please commit your changes or stash them before you %s.") "Please commit your changes or stash them before you %s.")
: _("Your local changes to the following files would be overwritten by %s:\n%%s"); : _("Your local changes to the following files would be overwritten by %s:\n%%s");
msgs[ERROR_WOULD_OVERWRITE] = msgs[ERROR_NOT_UPTODATE_FILE] = msgs[ERROR_WOULD_OVERWRITE] = msgs[ERROR_NOT_UPTODATE_FILE] =
xstrfmt(msg, cmd, cmd); argv_array_pushf(&opts->msgs_to_free, msg, cmd, cmd);
msgs[ERROR_NOT_UPTODATE_DIR] = msgs[ERROR_NOT_UPTODATE_DIR] =
_("Updating the following directories would lose untracked files in them:\n%s"); _("Updating the following directories would lose untracked files in them:\n%s");
@ -139,7 +142,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
? _("The following untracked working tree files would be removed by %s:\n%%s" ? _("The following untracked working tree files would be removed by %s:\n%%s"
"Please move or remove them before you %s.") "Please move or remove them before you %s.")
: _("The following untracked working tree files would be removed by %s:\n%%s"); : _("The following untracked working tree files would be removed by %s:\n%%s");
msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = xstrfmt(msg, cmd, cmd); msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] =
argv_array_pushf(&opts->msgs_to_free, msg, cmd, cmd);
if (!strcmp(cmd, "checkout")) if (!strcmp(cmd, "checkout"))
msg = advice_commit_before_merge msg = advice_commit_before_merge
@ -156,7 +160,8 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
? _("The following untracked working tree files would be overwritten by %s:\n%%s" ? _("The following untracked working tree files would be overwritten by %s:\n%%s"
"Please move or remove them before you %s.") "Please move or remove them before you %s.")
: _("The following untracked working tree files would be overwritten by %s:\n%%s"); : _("The following untracked working tree files would be overwritten by %s:\n%%s");
msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = xstrfmt(msg, cmd, cmd); msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] =
argv_array_pushf(&opts->msgs_to_free, msg, cmd, cmd);
/* /*
* Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
@ -179,6 +184,12 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
opts->unpack_rejects[i].strdup_strings = 1; opts->unpack_rejects[i].strdup_strings = 1;
} }
void clear_unpack_trees_porcelain(struct unpack_trees_options *opts)
{
argv_array_clear(&opts->msgs_to_free);
memset(opts->msgs, 0, sizeof(opts->msgs));
}
static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce, static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
unsigned int set, unsigned int clear) unsigned int set, unsigned int clear)
{ {

View File

@ -2,7 +2,7 @@
#define UNPACK_TREES_H #define UNPACK_TREES_H
#include "tree-walk.h" #include "tree-walk.h"
#include "string-list.h" #include "argv-array.h"
#define MAX_UNPACK_TREES 8 #define MAX_UNPACK_TREES 8
@ -33,6 +33,11 @@ enum unpack_trees_error_types {
void setup_unpack_trees_porcelain(struct unpack_trees_options *opts, void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
const char *cmd); const char *cmd);
/*
* Frees resources allocated by setup_unpack_trees_porcelain().
*/
void clear_unpack_trees_porcelain(struct unpack_trees_options *opts);
struct unpack_trees_options { struct unpack_trees_options {
unsigned int reset, unsigned int reset,
merge, merge,
@ -57,6 +62,7 @@ struct unpack_trees_options {
struct pathspec *pathspec; struct pathspec *pathspec;
merge_fn_t fn; merge_fn_t fn;
const char *msgs[NB_UNPACK_TREES_ERROR_TYPES]; const char *msgs[NB_UNPACK_TREES_ERROR_TYPES];
struct argv_array msgs_to_free;
/* /*
* Store error messages in an array, each case * Store error messages in an array, each case
* corresponding to a error message type * corresponding to a error message type