]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/rebase: fix options.strategy memory lifecycle
authorAndrzej Hunt <ajrhunt@google.com>
Sun, 25 Jul 2021 13:08:29 +0000 (15:08 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 26 Jul 2021 19:19:21 +0000 (12:19 -0700)
- cmd_rebase populates rebase_options.strategy with newly allocated
  strings, hence we need to free those strings at the end of cmd_rebase
  to avoid a leak.
- In some cases: get_replay_opts() is called, which prepares replay_opts
  using data from rebase_options. We used to simply copy the pointer
  from rebase_options.strategy,  however that would now result in a
  double-free because sequencer_remove_state() is eventually used to
  free replay_opts.strategy. To avoid this we xstrdup() strategy when
  adding it to replay_opts.

The original leak happens because we always populate
rebase_options.strategy, but we don't always enter the path that calls
get_replay_opts() and later sequencer_remove_state() - in  other words
we'd always allocate a new string into rebase_options.strategy but
only sometimes did we free it. We now make sure that rebase_options
and replay_opts both own their own copies of strategy, and each copy
is free'd independently.

This was first seen when running t0021 with LSAN, but t2012 helped catch
the fact that we can't just free(options.strategy) at the end of
cmd_rebase (as that can cause a double-free). LSAN output from t0021:

LSAN output from t0021:

Direct leak of 4 byte(s) in 1 object(s) allocated from:
    #0 0x486804 in strdup ../projects/compiler-rt/lib/asan/asan_interceptors.cpp:452:3
    #1 0xa71eb8 in xstrdup wrapper.c:29:14
    #2 0x61b1cc in cmd_rebase builtin/rebase.c:1779:22
    #3 0x4ce83e in run_builtin git.c:475:11
    #4 0x4ccafe in handle_builtin git.c:729:3
    #5 0x4cb01c in run_argv git.c:818:4
    #6 0x4cb01c in cmd_main git.c:949:19
    #7 0x6b3fad in main common-main.c:52:11
    #8 0x7f267b512349 in __libc_start_main (/lib64/libc.so.6+0x24349)

SUMMARY: AddressSanitizer: 4 byte(s) leaked in 1 allocation(s).

Signed-off-by: Andrzej Hunt <andrzej@ahunt.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/rebase.c

index 12f093121d9ed3df0d345992da14de908c119271..33e09619005b2aa706ffb33c0f31f2378eba1fe7 100644 (file)
@@ -139,7 +139,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts)
        replay.ignore_date = opts->ignore_date;
        replay.gpg_sign = xstrdup_or_null(opts->gpg_sign_opt);
        if (opts->strategy)
-               replay.strategy = opts->strategy;
+               replay.strategy = xstrdup_or_null(opts->strategy);
        else if (!replay.strategy && replay.default_strategy) {
                replay.strategy = replay.default_strategy;
                replay.default_strategy = NULL;
@@ -2109,6 +2109,7 @@ cleanup:
        free(options.head_name);
        free(options.gpg_sign_opt);
        free(options.cmd);
+       free(options.strategy);
        strbuf_release(&options.git_format_patch_opt);
        free(squash_onto_name);
        return ret;