threads / patch / 45809

patch, 26 partsAddress a couple of issues identified by Coverity

Subject: [PATCH 00/26] Address a couple of issues identified by Coverity

## tl;dr

178 messages between Apr 26, 2017 and May 11, 2017. Diffs are folded; open one to read it.

replies: 177people: 7as markdown or json

Johannes Schindelin· Apr 26, 2017, 20:19 UTC · lore

I recently registered the git-for-windows fork with Coverity to ensure that even the Windows-specific patches get some static analysis love.

While at it, I squashed a couple of obvious issues in the part that is not Windows-specific.

Note: while this patch series squashes some of those issues, the
remaining issues are not necessarily all false positives (e.g. Coverity
getting fooled by our FLEX_ARRAY trick into believing that the last
member of the struct is indeed a 0 or 1 size array) or intentional (e.g.
builtins not releasing memory because exit() is called right after
returning from the function that leaks memory).
Notable examples of the remaining issues are:
- a couple of callers of shorten_unambiguous_ref() assume that they do
  not have to release the memory returned from that function, often
  assigning the pointer to a `const` variable that typically does not
  hold a pointer that needs to be free()d. My hunch is that we will want
  to convert that function to have a fixed number of static buffers and
  use those in a round robin fashion à la sha1_to_hex().
- pack-redundant.c seems to have hard-to-reason-about code paths that
  may eventually leak memory. Essentially, the custody of the allocated
  memory is not clear at all.
- fast-import.c calls strbuf_detach() on the command_buf without any
  obvious rationale. Turns out that *some* code paths assign
  command_buf.buf to a `recent_command` which releases the buffer later.
  However, from a cursory look it appears to me as if there are some
  other code paths that skip that assignment, effectively causing a memory
  leak once strbuf_detach() is called.
Sadly, I lack the time to pursue those remaining issues further.
Johannes Schindelin (26):
  mingw: avoid memory leak when splitting PATH
  winansi: avoid use of uninitialized value
  winansi: avoid buffer overrun
  add_commit_patch_id(): avoid allocating memory unnecessarily
  git_config_rename_section_in_file(): avoid resource leak
  get_mail_commit_oid(): avoid resource leak
  http-backend: avoid memory leaks
  difftool: close file descriptors after reading
  status: close file descriptor after reading git-rebase-todo
  Check for EOF while parsing mails
  cat-file: fix memory leak
  checkout: fix memory leak
  split_commit_in_progress(): fix memory leak
  setup_bare_git_dir(): fix memory leak
  setup_discovered_git_dir(): fix memory leak
  pack-redundant: plug memory leak
  mktree: plug memory leaks reported by Coverity
  fast-export: avoid leaking memory in handle_tag()
  receive-pack: plug memory leak in update()
  line-log: avoid memory leak
  shallow: avoid memory leak
  add_reflog_for_walk: avoid memory leak
  remote: plug memory leak in match_explicit()
  name-rev: avoid leaking memory in the `deref` case
  show_worktree(): plug memory leak
  submodule_uses_worktrees(): plug memory leak
 builtin/am.c             | 11 ++++++-----
 builtin/cat-file.c       |  1 +
 builtin/checkout.c       |  1 +
 builtin/difftool.c       |  2 ++
 builtin/fast-export.c    |  1 +
 builtin/mailsplit.c      |  2 +-
 builtin/mktree.c         |  5 +++--
 builtin/name-rev.c       |  7 +++++--
 builtin/pack-redundant.c |  1 +
 builtin/receive-pack.c   |  4 +++-
 builtin/worktree.c       |  8 +++++---
 compat/mingw.c           |  4 +++-
 compat/winansi.c         |  7 +++++++
 config.c                 |  5 ++++-
 http-backend.c           |  6 +++++-
 line-log.c               |  1 +
 mailinfo.c               |  2 +-
 patch-ids.c              |  3 ++-
 reflog-walk.c            |  6 +++++-
 remote.c                 |  5 +++--
 setup.c                  | 11 ++++++++---
 shallow.c                |  8 ++++++--
 worktree.c               |  2 +-
 wt-status.c              |  8 +++++++-
 24 files changed, 82 insertions(+), 29 deletions(-)
base-commit: e2cb6ab84c94f147f1259260961513b40c36108a
Published-As: https://github.com/dscho/git/releases/tag/coverity-v1
Fetch-It-Via: git fetch https://github.com/dscho/git coverity-v1
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 01/26] mingw: avoid memory leak when splitting PATH

In the (admittedly, concocted) case that PATH consists only of colons, we would leak the duplicated string.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/mingw.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
Show changes to compat/mingw.c +3 −1
diff --git a/compat/mingw.c b/compat/mingw.c
index 3fbfda5978b..fe0e3ccd248 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -961,8 +961,10 @@ static char **get_path_split(void)
 			++n;
 		}
 	}
-	if (!n)
+	if (!n) {
+		free(envpath);
 		return NULL;
+	}
 
 	ALLOC_ARRAY(path, n + 1);
 	p = envpath;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 02/26] winansi: avoid use of uninitialized value

When stdout is not connected to a Win32 console, we incorrectly used an uninitialized value for the "plain" character attributes.

Detected by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 2 ++
 1 file changed, 2 insertions(+)
Show changes to compat/winansi.c +2 −0
diff --git a/compat/winansi.c b/compat/winansi.c
index 793420f9d0d..fd6910746c8 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -105,6 +105,8 @@ static int is_console(int fd)
 	if (!fd) {
 		if (!GetConsoleMode(hcon, &mode))
 			return 0;
+		sbi.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
+			FOREGROUND_RED;
 	} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 03/26] winansi: avoid buffer overrun

When we could not convert the UTF-8 sequence into Unicode for writing to the Console, we should not try to write an insanely-long sequence of invalid wide characters (mistaking the negative return value for an unsigned length).

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 5 +++++
 1 file changed, 5 insertions(+)
Show changes to compat/winansi.c +5 −0
diff --git a/compat/winansi.c b/compat/winansi.c
index fd6910746c8..861b79d8c31 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -135,6 +135,11 @@ static void write_console(unsigned char *str, size_t len)
 
 	/* convert utf-8 to utf-16 */
 	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
+	if (wlen < 0) {
+		wchar_t *err = L"[invalid]";
+		WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
+		return;
+	}
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, &dummy, NULL);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 04/26] add_commit_patch_id(): avoid allocating memory unnecessarily

It would appear that we allocate (and forget to release) memory if the patch ID is not even defined.

Reported by the Coverity tool.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 patch-ids.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
Show changes to patch-ids.c +2 −1
diff --git a/patch-ids.c b/patch-ids.c
index fa8f11de826..92eba7a059e 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -99,11 +99,12 @@ struct patch_id *has_commit_patch_id(struct commit *commit,
 struct patch_id *add_commit_patch_id(struct commit *commit,
 				     struct patch_ids *ids)
 {
-	struct patch_id *key = xcalloc(1, sizeof(*key));
+	struct patch_id *key;
 
 	if (!patch_id_defined(commit))
 		return NULL;
 
+	key = xcalloc(1, sizeof(*key));
 	if (init_patch_id_entry(key, commit, ids)) {
 		free(key);
 		return NULL;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 06/26] get_mail_commit_oid(): avoid resource leak

When we fail to read, or parse, the file, we still want to close the file descriptor and release the strbuf.

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/am.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
Show changes to builtin/am.c +6 −5
diff --git a/builtin/am.c b/builtin/am.c
index 805f56cec2f..01b700e5e74 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1359,15 +1359,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
 	struct strbuf sb = STRBUF_INIT;
 	FILE *fp = xfopen(mail, "r");
 	const char *x;
+	int ret = 0;
 
 	if (strbuf_getline_lf(&sb, fp))
-		return -1;
+		ret = -1;
 
-	if (!skip_prefix(sb.buf, "From ", &x))
-		return -1;
+	if (!ret && !skip_prefix(sb.buf, "From ", &x))
+		ret = -1;
 
-	if (get_oid_hex(x, commit_id) < 0)
-		return -1;
+	if (!ret && get_oid_hex(x, commit_id) < 0)
+		ret = -1;
 
 	strbuf_release(&sb);
 	fclose(fp);
-- 
2.12.2.windows.2.800.gede8f145e06
Stefan Beller· Apr 26, 2017, 21:06 UTC · re: Johannes Schindelin · lore

Re: [PATCH 06/26] get_mail_commit_oid(): avoid resource leak

On Wed, Apr 26, 2017 at 1:19 PM, Johannes Schindelin <johannes.schindelin@gmx.de> wrote:

Show 34 quoted lines
> When we fail to read, or parse, the file, we still want to close the file
> descriptor and release the strbuf.
>
> Reported via Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/am.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/am.c b/builtin/am.c
> index 805f56cec2f..01b700e5e74 100644
> --- a/builtin/am.c
> +++ b/builtin/am.c
> @@ -1359,15 +1359,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
>         struct strbuf sb = STRBUF_INIT;
>         FILE *fp = xfopen(mail, "r");
>         const char *x;
> +       int ret = 0;
>
>         if (strbuf_getline_lf(&sb, fp))
> -               return -1;
> +               ret = -1;
>
> -       if (!skip_prefix(sb.buf, "From ", &x))
> -               return -1;
> +       if (!ret && !skip_prefix(sb.buf, "From ", &x))
> +               ret = -1;
>
> -       if (get_oid_hex(x, commit_id) < 0)
> -               return -1;
> +       if (!ret && get_oid_hex(x, commit_id) < 0)
> +               ret = -1;
>

In similar cases of fixing mem leaks, we'd put a label here and make excessive use of goto, instead of setting ret to -1. As "ret" and the commands are short, this is visually just as appealing.

Thanks, Stefan

Junio C Hamano· Apr 27, 2017, 05:53 UTC · re: Stefan Beller · lore

Re: [PATCH 06/26] get_mail_commit_oid(): avoid resource leak

Stefan Beller <sbeller@google.com> writes:
Show 9 quoted lines
>> -       if (get_oid_hex(x, commit_id) < 0)
>> -               return -1;
>> +       if (!ret && get_oid_hex(x, commit_id) < 0)
>> +               ret = -1;
>>
>
> In similar cases of fixing mem leaks, we'd put a label here
> and make excessive use of goto, instead of setting ret to -1.
> As "ret" and the commands are short, this is visually just as appealing.

I wouldn't call that visually appealing. Fixing resource leaks is good, and only because this function is short enough and the funny way to skip over various operation need to last for just a few instructions, it is tolerable. If the function were shorter, then we may have used

	if (!strbuf_getline_lf() &&
	    skip_prefix() &&
	    !get_oid_hex())
		ret = 0; /* happy */
	else
		ret = -1;
	release resources here;
        return ret;

and that would have been OK. If longer, as you said, jumping to a label at the end of function to release the acquired resource would be a lot more maintainable way than either of the above alternatives that are only usable for short functions.

The patch as posted makes the function fail to return -1 when it finds problems, by the way. It needs to return "ret" not the hardcoded "0" at the end.

        
Johannes Schindelin· Apr 28, 2017, 13:39 UTC · re: Junio C Hamano · lore

Re: [PATCH 06/26] get_mail_commit_oid(): avoid resource leak

Hi Junio & Stefan,
On Wed, 26 Apr 2017, Junio C Hamano wrote:
Show 26 quoted lines
> Stefan Beller <sbeller@google.com> writes:
> 
> >> -       if (get_oid_hex(x, commit_id) < 0)
> >> -               return -1;
> >> +       if (!ret && get_oid_hex(x, commit_id) < 0)
> >> +               ret = -1;
> >>
> >
> > In similar cases of fixing mem leaks, we'd put a label here
> > and make excessive use of goto, instead of setting ret to -1.
> > As "ret" and the commands are short, this is visually just as appealing.
> 
> I wouldn't call that visually appealing.  Fixing resource leaks is
> good, and only because this function is short enough and the funny
> way to skip over various operation need to last for just a few
> instructions, it is tolerable.  If the function were shorter, then
> we may have used
> 
> 	if (!strbuf_getline_lf() &&
> 	    skip_prefix() &&
> 	    !get_oid_hex())
> 		ret = 0; /* happy */
> 	else
> 		ret = -1;
> 	release resources here;
>         return ret;

I did almost what you suggested here, but I avoided the explicit ret = 0, as it is initialized that way.

Show 8 quoted lines
> and that would have been OK.  If longer, as you said, jumping to a
> label at the end of function to release the acquired resource would
> be a lot more maintainable way than either of the above alternatives
> that are only usable for short functions.
> 
> The patch as posted makes the function fail to return -1 when it
> finds problems, by the way.  It needs to return "ret" not the
> hardcoded "0" at the end.
Oops.

Ciao, Dscho

Johannes Sixt· Apr 27, 2017, 06:14 UTC · re: Johannes Schindelin · lore

Re: [PATCH 06/26] get_mail_commit_oid(): avoid resource leak

Am 26.04.2017 um 22:19 schrieb Johannes Schindelin:
Show 37 quoted lines
> When we fail to read, or parse, the file, we still want to close the file
> descriptor and release the strbuf.
>
> Reported via Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/am.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/am.c b/builtin/am.c
> index 805f56cec2f..01b700e5e74 100644
> --- a/builtin/am.c
> +++ b/builtin/am.c
> @@ -1359,15 +1359,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
>  	struct strbuf sb = STRBUF_INIT;
>  	FILE *fp = xfopen(mail, "r");
>  	const char *x;
> +	int ret = 0;
>
>  	if (strbuf_getline_lf(&sb, fp))
> -		return -1;
> +		ret = -1;
>
> -	if (!skip_prefix(sb.buf, "From ", &x))
> -		return -1;
> +	if (!ret && !skip_prefix(sb.buf, "From ", &x))
> +		ret = -1;
>
> -	if (get_oid_hex(x, commit_id) < 0)
> -		return -1;
> +	if (!ret && get_oid_hex(x, commit_id) < 0)
> +		ret = -1;
>
>  	strbuf_release(&sb);
>  	fclose(fp);
>
You forgot to 'return ret;', didn't you?
-- Hannes
Johannes Schindelin· Apr 28, 2017, 10:02 UTC · re: Johannes Sixt · lore

Re: [PATCH 06/26] get_mail_commit_oid(): avoid resource leak

Hi Hannes,
On Thu, 27 Apr 2017, Johannes Sixt wrote:
Show 32 quoted lines
> Am 26.04.2017 um 22:19 schrieb Johannes Schindelin:
> >
> > diff --git a/builtin/am.c b/builtin/am.c
> > index 805f56cec2f..01b700e5e74 100644
> > --- a/builtin/am.c
> > +++ b/builtin/am.c
> > @@ -1359,15 +1359,16 @@ static int get_mail_commit_oid(struct object_id
> > *commit_id, const char *mail)
> >   struct strbuf sb = STRBUF_INIT;
> >   FILE *fp = xfopen(mail, "r");
> >   const char *x;
> > +	int ret = 0;
> >
> > 	if (strbuf_getline_lf(&sb, fp))
> > -		return -1;
> > +		ret = -1;
> >
> > -	if (!skip_prefix(sb.buf, "From ", &x))
> > -		return -1;
> > +	if (!ret && !skip_prefix(sb.buf, "From ", &x))
> > +		ret = -1;
> >
> > -	if (get_oid_hex(x, commit_id) < 0)
> > -		return -1;
> > +	if (!ret && get_oid_hex(x, commit_id) < 0)
> > +		ret = -1;
> >
> >   strbuf_release(&sb);
> >   fclose(fp);
> >
> 
> You forgot to 'return ret;', didn't you?
I sure did!

Thanks, Dscho

Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 05/26] git_config_rename_section_in_file(): avoid resource leak

In case of errors, we really want the file descriptor to be closed.
Discovered by a Coverity scan.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 config.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
Show changes to config.c +4 −1
diff --git a/config.c b/config.c
index 0daaed338ea..ed1420fb096 100644
--- a/config.c
+++ b/config.c
@@ -2599,7 +2599,7 @@ int git_config_rename_section_in_file(const char *config_filename,
 	struct lock_file *lock;
 	int out_fd;
 	char buf[1024];
-	FILE *config_file;
+	FILE *config_file = NULL;
 	struct stat st;
 
 	if (new_name && !section_name_is_ok(new_name)) {
@@ -2681,11 +2681,14 @@ int git_config_rename_section_in_file(const char *config_filename,
 		}
 	}
 	fclose(config_file);
+	config_file = NULL;
 commit_and_out:
 	if (commit_lock_file(lock) < 0)
 		ret = error_errno("could not write config file %s",
 				  config_filename);
 out:
+	if (config_file)
+		fclose(config_file);
 	rollback_lock_file(lock);
 out_no_rollback:
 	free(filename_buf);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 08/26] difftool: close file descriptors after reading

Spotted by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/difftool.c | 2 ++
 1 file changed, 2 insertions(+)
Show changes to builtin/difftool.c +2 −0
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 1354d0e4625..a4f1d117ef6 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -226,6 +226,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
 		hashmap_entry_init(entry, strhash(buf.buf));
 		hashmap_add(result, entry);
 	}
+	fclose(fp);
 	if (finish_command(&diff_files))
 		die("diff-files did not exit properly");
 	strbuf_release(&index_env);
@@ -497,6 +498,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		}
 	}
 
+	fclose(fp);
 	if (finish_command(&child)) {
 		ret = error("error occurred running diff --raw");
 		goto finish;
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· Apr 27, 2017, 06:05 UTC · re: Johannes Schindelin · lore

Re: [PATCH 08/26] difftool: close file descriptors after reading

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 19 quoted lines
> Spotted by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/difftool.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/builtin/difftool.c b/builtin/difftool.c
> index 1354d0e4625..a4f1d117ef6 100644
> --- a/builtin/difftool.c
> +++ b/builtin/difftool.c
> @@ -226,6 +226,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
>  		hashmap_entry_init(entry, strhash(buf.buf));
>  		hashmap_add(result, entry);
>  	}
> +	fclose(fp);
>  	if (finish_command(&diff_files))
>  		die("diff-files did not exit properly");
>  	strbuf_release(&index_env);
This one looks sensible.
Show 5 quoted lines
> @@ -497,6 +498,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
>  		}
>  	}
>  
> +	fclose(fp);

The huge loop we see in the pre-context of this hunk has many "return"s and "goto finish"es that can leave fp still open; while this patch does not hurt, it is probably somewhat insufficient.

>  	if (finish_command(&child)) {
>  		ret = error("error occurred running diff --raw");
>  		goto finish;
Johannes Schindelin· Apr 28, 2017, 09:51 UTC · re: Junio C Hamano · lore

Re: [PATCH 08/26] difftool: close file descriptors after reading

Hi Junio,
On Wed, 26 Apr 2017, Junio C Hamano wrote:
Show 14 quoted lines
> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> > diff --git a/builtin/difftool.c b/builtin/difftool.c
> > index 1354d0e4625..a4f1d117ef6 100644
> > --- a/builtin/difftool.c
> > +++ b/builtin/difftool.c
> > @@ -497,6 +498,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
> >  		}
> >  	}
> >  
> > +	fclose(fp);
> 
> The huge loop we see in the pre-context of this hunk has many
> "return"s and "goto finish"es that can leave fp still open; while
> this patch does not hurt, it is probably somewhat insufficient.

You are absolutely correct, and I am somewhat surprised that Coverity did not complain more loudly.

TBH I really only tried to address these fixes on the cheap, as my main aim was to get to the critical bugs in the Windows-specific part (I did not find anything major, though). Therefore, I only looked at what Coverity labels as the "high impact" issues. The leaks in the loop that you pointed out may be labeled as minor by Coverity.

I also noticed that a couple of error messages have not been marked as translateable, I must have forgotten that before submitting the difftool patch series :-(

In any case, in the next iteration of this patch series, this patch will convert all returns to `ret = ...; goto finish;` calls, and fclose(fp) there unless it has been closed already.

Thanks, Dscho

Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 07/26] http-backend: avoid memory leaks

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 http-backend.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
Show changes to http-backend.c +5 −1
diff --git a/http-backend.c b/http-backend.c
index eef0a361f4f..d12572fda10 100644
--- a/http-backend.c
+++ b/http-backend.c
@@ -681,8 +681,10 @@ int cmd_main(int argc, const char **argv)
 		if (!regexec(&re, dir, 1, out, 0)) {
 			size_t n;
 
-			if (strcmp(method, c->method))
+			if (strcmp(method, c->method)) {
+				free(dir);
 				return bad_request(&hdr, c);
+			}
 
 			cmd = c;
 			n = out[0].rm_eo - out[0].rm_so;
@@ -708,5 +710,7 @@ int cmd_main(int argc, const char **argv)
 					   max_request_buffer);
 
 	cmd->imp(&hdr, cmd_arg);
+	free(dir);
+	free(cmd_arg);
 	return 0;
 }
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· Apr 27, 2017, 06:00 UTC · re: Johannes Schindelin · lore

Re: [PATCH 07/26] http-backend: avoid memory leaks

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 31 quoted lines
> Reported via Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  http-backend.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/http-backend.c b/http-backend.c
> index eef0a361f4f..d12572fda10 100644
> --- a/http-backend.c
> +++ b/http-backend.c
> @@ -681,8 +681,10 @@ int cmd_main(int argc, const char **argv)
>  		if (!regexec(&re, dir, 1, out, 0)) {
>  			size_t n;
>  
> -			if (strcmp(method, c->method))
> +			if (strcmp(method, c->method)) {
> +				free(dir);
>  				return bad_request(&hdr, c);
> +			}
>  
>  			cmd = c;
>  			n = out[0].rm_eo - out[0].rm_so;
> @@ -708,5 +710,7 @@ int cmd_main(int argc, const char **argv)
>  					   max_request_buffer);
>  
>  	cmd->imp(&hdr, cmd_arg);
> +	free(dir);
> +	free(cmd_arg);
>  	return 0;
>  }

Hmph. I find a "leak" of a resource acquired inside the main function and not released when the main function leaves a lot less interesting than the other ones this series covers.

When the "return" in the first hunk leaves the function and also the same block of the if () statement breaks out the loop, we also fail to call regfree(&re). Shouldn't we be cleaning it up as well?

Johannes Schindelin· Apr 28, 2017, 09:40 UTC · re: Junio C Hamano · lore

Re: [PATCH 07/26] http-backend: avoid memory leaks

Hi Junio,
On Wed, 26 Apr 2017, Junio C Hamano wrote:
Show 37 quoted lines
> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> 
> > Reported via Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  http-backend.c | 6 +++++-
> >  1 file changed, 5 insertions(+), 1 deletion(-)
> >
> > diff --git a/http-backend.c b/http-backend.c
> > index eef0a361f4f..d12572fda10 100644
> > --- a/http-backend.c
> > +++ b/http-backend.c
> > @@ -681,8 +681,10 @@ int cmd_main(int argc, const char **argv)
> >  		if (!regexec(&re, dir, 1, out, 0)) {
> >  			size_t n;
> >  
> > -			if (strcmp(method, c->method))
> > +			if (strcmp(method, c->method)) {
> > +				free(dir);
> >  				return bad_request(&hdr, c);
> > +			}
> >  
> >  			cmd = c;
> >  			n = out[0].rm_eo - out[0].rm_so;
> > @@ -708,5 +710,7 @@ int cmd_main(int argc, const char **argv)
> >  					   max_request_buffer);
> >  
> >  	cmd->imp(&hdr, cmd_arg);
> > +	free(dir);
> > +	free(cmd_arg);
> >  	return 0;
> >  }
> 
> Hmph.  I find a "leak" of a resource acquired inside the main
> function and not released when the main function leaves a lot less
> interesting than the other ones this series covers.

Ah, I missed that this falls squarely into the "one-shot programs are allowed to be sloppy in their memory management, essentially using exit() as garbage collector" category.

Will drop, Dscho

Junio C Hamano· May 1, 2017, 01:19 UTC · re: Johannes Schindelin · lore

Re: [PATCH 07/26] http-backend: avoid memory leaks

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 7 quoted lines
>> Hmph.  I find a "leak" of a resource acquired inside the main
>> function and not released when the main function leaves a lot less
>> interesting than the other ones this series covers.
>
> Ah, I missed that this falls squarely into the "one-shot programs are
> allowed to be sloppy in their memory management, essentially using exit()
> as garbage collector" category.

I actually think it was a good intention of yours and I would agree with the patch. The automated tools that find and complain about these issues do not know about our local house rules like "do not bother freeing immediately before exit" and will keep notifying us of leaks. One way to reduce the noise level so that we can focus on real issues they may find for us in the future is to squelch these "uninteresting" ones by "fixing" them, even if our local house rule says OK, like this patch does.

I said "a lot less interesting" and did not mean "it is bad for our code to do this".

Thanks.
Johannes Schindelin· May 1, 2017, 19:05 UTC · re: Junio C Hamano · lore

Re: [PATCH 07/26] http-backend: avoid memory leaks

Hi Junio,
On Sun, 30 Apr 2017, Junio C Hamano wrote:
Show 15 quoted lines
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
> >> Hmph.  I find a "leak" of a resource acquired inside the main
> >> function and not released when the main function leaves a lot less
> >> interesting than the other ones this series covers.
> >
> > Ah, I missed that this falls squarely into the "one-shot programs are
> > allowed to be sloppy in their memory management, essentially using
> > exit() as garbage collector" category.
> 
> I actually think it was a good intention of yours and I would agree
> with the patch.  The automated tools that find and complain about
> these issues do not know about our local house rules like "do not
> bother freeing immediately before exit" and will keep notifying us
> of leaks.

In Coverity, I marked them as "Intentional", so that they can be dropped from the default view.

Unfortunately, the verdict "Intentional" does not percolate to other projects, so I will probably have to do the entire shebang in the `git` project again.

Of course, we could also decide that we want to shut up static analyzers by actually *not* leaking memory, by *not* using exit() as our garbage collector in one-shot commands, with the added benefit of making the code easier to libify/reuse.

But I fear that I distract the discussion away from a more focused attention to the actual patch series, which is actually still in flight and in actual need for review, as I actually want to get those patches integrated into git.git.

Ciao, Dscho

Johannes Schindelin· Apr 26, 2017, 20:19 UTC · re: Johannes Schindelin · lore

[PATCH 09/26] status: close file descriptor after reading git-rebase-todo

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to wt-status.c +1 −0
diff --git a/wt-status.c b/wt-status.c
index 03754849626..0a6e16dbe0f 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1168,6 +1168,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines)
 		abbrev_sha1_in_line(&line);
 		string_list_append(lines, line.buf);
 	}
+	fclose(f);
 	return 0;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:20 UTC · re: Johannes Schindelin · lore

[PATCH 10/26] Check for EOF while parsing mails

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/mailsplit.c | 2 +-
 mailinfo.c          | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
Show changes to 2 files +2 −2

builtin/mailsplit.c, mailinfo.c

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30681681c13..c0d88f97512 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -232,7 +232,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
 
 	do {
 		peek = fgetc(f);
-	} while (isspace(peek));
+	} while (peek >= 0 && isspace(peek));
 	ungetc(peek, f);
 
 	if (strbuf_getwholeline(&buf, f, '\n')) {
diff --git a/mailinfo.c b/mailinfo.c
index 68037758f2f..60dcad7b714 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -1099,7 +1099,7 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
 
 	do {
 		peek = fgetc(mi->input);
-	} while (isspace(peek));
+	} while (peek >= 0 && isspace(peek));
 	ungetc(peek, mi->input);
 
 	/* process the email header */
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· Apr 27, 2017, 06:07 UTC · re: Johannes Schindelin · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 7 quoted lines
> Reported via Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/mailsplit.c | 2 +-
>  mailinfo.c          | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
Good find.  I'd retitle with a prefix
	mailinfo & mailsplit: check for EOF while parsing

so that it is clear that this patch is about lower level machinery (as oppose to something like "git am").

Thanks.
Show 27 quoted lines
>
> diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> index 30681681c13..c0d88f97512 100644
> --- a/builtin/mailsplit.c
> +++ b/builtin/mailsplit.c
> @@ -232,7 +232,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
>  
>  	do {
>  		peek = fgetc(f);
> -	} while (isspace(peek));
> +	} while (peek >= 0 && isspace(peek));
>  	ungetc(peek, f);
>  
>  	if (strbuf_getwholeline(&buf, f, '\n')) {
> diff --git a/mailinfo.c b/mailinfo.c
> index 68037758f2f..60dcad7b714 100644
> --- a/mailinfo.c
> +++ b/mailinfo.c
> @@ -1099,7 +1099,7 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
>  
>  	do {
>  		peek = fgetc(mi->input);
> -	} while (isspace(peek));
> +	} while (peek >= 0 && isspace(peek));
>  	ungetc(peek, mi->input);
>  
>  	/* process the email header */
Johannes Schindelin· Apr 28, 2017, 09:55 UTC · re: Junio C Hamano · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

Hi Junio,
On Wed, 26 Apr 2017, Junio C Hamano wrote:
Show 16 quoted lines
> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> 
> > Reported via Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  builtin/mailsplit.c | 2 +-
> >  mailinfo.c          | 2 +-
> >  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> Good find.  I'd retitle with a prefix
> 
> 	mailinfo & mailsplit: check for EOF while parsing
> 
> so that it is clear that this patch is about lower level machinery
> (as oppose to something like "git am").

True. Will be fixed in the next iteration, Dscho

Johannes Sixt· Apr 27, 2017, 06:20 UTC · re: Johannes Schindelin · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

Am 26.04.2017 um 22:20 schrieb Johannes Schindelin:
Show 35 quoted lines
> Reported via Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/mailsplit.c | 2 +-
>  mailinfo.c          | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> index 30681681c13..c0d88f97512 100644
> --- a/builtin/mailsplit.c
> +++ b/builtin/mailsplit.c
> @@ -232,7 +232,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
>
>  	do {
>  		peek = fgetc(f);
> -	} while (isspace(peek));
> +	} while (peek >= 0 && isspace(peek));
>  	ungetc(peek, f);
>
>  	if (strbuf_getwholeline(&buf, f, '\n')) {
> diff --git a/mailinfo.c b/mailinfo.c
> index 68037758f2f..60dcad7b714 100644
> --- a/mailinfo.c
> +++ b/mailinfo.c
> @@ -1099,7 +1099,7 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
>
>  	do {
>  		peek = fgetc(mi->input);
> -	} while (isspace(peek));
> +	} while (peek >= 0 && isspace(peek));
>  	ungetc(peek, mi->input);
>
>  	/* process the email header */
>
Why? isspace(EOF) is well-defined.
-- Hannes
Johannes Schindelin· Apr 28, 2017, 10:41 UTC · re: Johannes Sixt · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

Hi Hannes,
On Thu, 27 Apr 2017, Johannes Sixt wrote:
Show 33 quoted lines
> Am 26.04.2017 um 22:20 schrieb Johannes Schindelin:
>
> > diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> > index 30681681c13..c0d88f97512 100644
> > --- a/builtin/mailsplit.c
> > +++ b/builtin/mailsplit.c
> > @@ -232,7 +232,7 @@ static int split_mbox(const char *file, const char *dir,
> > int allow_bare,
> >
> >   do {
> > 		peek = fgetc(f);
> > -	} while (isspace(peek));
> > +	} while (peek >= 0 && isspace(peek));
> >   ungetc(peek, f);
> >
> > 	if (strbuf_getwholeline(&buf, f, '\n')) {
> > diff --git a/mailinfo.c b/mailinfo.c
> > index 68037758f2f..60dcad7b714 100644
> > --- a/mailinfo.c
> > +++ b/mailinfo.c
> > @@ -1099,7 +1099,7 @@ int mailinfo(struct mailinfo *mi, const char *msg,
> > const char *patch)
> >
> >   do {
> > 		peek = fgetc(mi->input);
> > -	} while (isspace(peek));
> > +	} while (peek >= 0 && isspace(peek));
> >   ungetc(peek, mi->input);
> >
> >   /* process the email header */
> >
> 
> Why? isspace(EOF) is well-defined.
So let's look at the man page on Linux:
	These functions check whether c,  which  must  have  the  value  of  an
	unsigned char or EOF, [...]

That is the only mention of it. I find it highly unobvious whether EOF should be treated as a space or not. So let's look at the MSDN page (https://msdn.microsoft.com/en-us/library/y13z34da.aspx) whether they talk more about EOF:

	The behavior of isspace and _isspace_l is undefined if c is not
	EOF or in the range 0 through 0xFF, inclusive.

That's it. So I kind of *guess* that EOF is treated as not being a whitespace character (why does this make me think of politics now? Focus, Johannes, focus...). But the mathematician in me protests: why would we be able to decide the character class of a character that does not exist?

Technically, you are correct, of course. The specs of fgetc() specify quite clearly that either an unsigned char cast to an int is returned, or EOF on end-of-file *or error*. And a quick test verifies that isspace(EOF) returns 0.

But then, I guess I misunderstood what Coverity complained about: maybe the problem was not so much the isspace() call but that EOF is not being handled correctly. We pass it, unchecked, to ungetc().

It appears that I (or Coverity, if you will), missed another instance where we simply passed EOF unchecked to ungetc().

The next iteration will have it completely reworked: I no longer guard the isspace() behind an `!= EOF` check, but rather handle an early EOF as I think it should be handled. Extra eyes very welcome (this is the fixup! patch):

-- snip --
Show changes to 2 files +15 −8

builtin/mailsplit.c, mailinfo.c

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index c0d88f97512..9b3efc8e987 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -232,8 +232,9 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
 
 	do {
 		peek = fgetc(f);
-	} while (peek >= 0 && isspace(peek));
-	ungetc(peek, f);
+	} while (isspace(peek));
+	if (peek != EOF)
+		ungetc(peek, f);
 
 	if (strbuf_getwholeline(&buf, f, '\n')) {
 		/* empty stdin is OK */
diff --git a/mailinfo.c b/mailinfo.c
index 60dcad7b714..a319911b510 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE *in)
 	for (;;) {
 		int peek;
 
-		peek = fgetc(in); ungetc(peek, in);
+		peek = fgetc(in);
+		if (peek == EOF)
+			break;
+		ungetc(peek, in);
 		if (peek != ' ' && peek != '\t')
 			break;
 		if (strbuf_getline_lf(&continuation, in))
@@ -1094,14 +1097,18 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
 		return -1;
 	}
 
-	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
-	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
-
 	do {
 		peek = fgetc(mi->input);
-	} while (peek >= 0 && isspace(peek));
+		if (peek == EOF) {
+			fclose(cmitmsg);
+			return error("empty patch: '%s'", patch);
+		}
+	} while (isspace(peek));
 	ungetc(peek, mi->input);
 
+	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
+	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
+
 	/* process the email header */
 	while (read_one_header_line(&line, mi->input))
 		check_header(mi, &line, mi->p_hdr_data, 1);
-- snap --

In the first hunk, I simply rely on the code after ungetc() to figure out
that there are no headers and to handle that case as before.

The second hunk handles the case where looking for a continuation line in
the header section hits EOF; it is still a valid header, but we should
avoid ungetc(EOF) to allow the next read to report EOF correctly.

The third hunk moves the malloc()s around so that we can complain about an
empty patch, close the file and return an error value without leaking
memory.

Ciao,
Dscho
Jeff King· Apr 28, 2017, 11:20 UTC · re: Johannes Schindelin · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

On Fri, Apr 28, 2017 at 12:41:02PM +0200, Johannes Schindelin wrote:
Show 19 quoted lines
> > Why? isspace(EOF) is well-defined.
> 
> So let's look at the man page on Linux:
> 
> 	These functions check whether c,  which  must  have  the  value  of  an
> 	unsigned char or EOF, [...]
> 
> That is the only mention of it. I find it highly unobvious whether EOF
> should be treated as a space or not. So let's look at the MSDN page
> (https://msdn.microsoft.com/en-us/library/y13z34da.aspx) whether they talk
> more about EOF:
> 
> 	The behavior of isspace and _isspace_l is undefined if c is not
> 	EOF or in the range 0 through 0xFF, inclusive.
> 
> That's it. So I kind of *guess* that EOF is treated as not being a
> whitespace character (why does this make me think of politics now? Focus,
> Johannes, focus...). But the mathematician in me protests: why would we
> be able to decide the character class of a character that does not exist?
This behavior actually comes from the C standard. From C99, 7.4:
  1 The header <ctype.h> declares several functions useful for
    classifying and mapping characters. 166) In all cases the argument
    is an int, the value of which shall be representable as an unsigned
    char or shall equal the value of the macro EOF. If the argument has
    any other value, the behavior is undefined.

It doesn't explicitly say that EOF returns false for these functions, but it does seem implied. For instance:

  The isspace function tests for any character that is a standard
  white-space character or is one of a locale-specific set of characters
  for which isalnum is false. The standard white-space characters are
  the following: space (' '), form feed ('\f'), new-line ('\n'),
  carriage return ('\r'), horizontal tab ('\t'), and vertical tab
  ('\v'). In the "C" locale, isspace returns true only for the standard
  white-space characters.

So I think it is a reasonable thing to depend on. But as I said elsewhere in the thread, we don't actually use the standard isspace() anyway.

Show 6 quoted lines
> But then, I guess I misunderstood what Coverity complained about: maybe
> the problem was not so much the isspace() call but that EOF is not being
> handled correctly. We pass it, unchecked, to ungetc().
> 
> It appears that I (or Coverity, if you will), missed another instance
> where we simply passed EOF unchecked to ungetc().
I think that is also fine according to the standard.

Do you happen to have the exact error from Coverity? I'm wondering if it is complaining about some aspect of our custom isspace() when used with EOF.

> The next iteration will have it completely reworked: I no longer guard the
> isspace() behind an `!= EOF` check, but rather handle an early EOF as I
> think it should be handled. Extra eyes very welcome (this is the fixup!
> patch):

I do think handling EOF explicitly is probably a better strategy anyway, as it lets us tell when we have an empty patch.

-Peff
Johannes Schindelin· Apr 28, 2017, 13:33 UTC · re: Jeff King · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

Hi Peff,
On Fri, 28 Apr 2017, Jeff King wrote:
Show 12 quoted lines
> On Fri, Apr 28, 2017 at 12:41:02PM +0200, Johannes Schindelin wrote:
> 
> > But then, I guess I misunderstood what Coverity complained about:
> > maybe the problem was not so much the isspace() call but that EOF is
> > not being handled correctly. We pass it, unchecked, to ungetc().
> > 
> > It appears that I (or Coverity, if you will), missed another instance
> > where we simply passed EOF unchecked to ungetc().
> 
> I think that is also fine according to the standard.
> 
> Do you happen to have the exact error from Coverity?

Wow, that was unnecessarily hard. It is a major hassle to get to any scan other than the latest one.

But I did it. Call me tenatious.
The report says this:
233        do {
   2. negative_return_fn: Function mingw_fgetc(f) returns a negative number.
   3. var_assign: Assigning: signed variable peek = mingw_fgetc.
234                peek = fgetc(f);
   CID 1049734: Negative array index read (NEGATIVE_RETURNS)
   4.  negative_returns: Using variable peek as an index to array sane_ctype.
235        } while (isspace(peek));
236        ungetc(peek, f);

So part of the thing is that we use mingw_fgetc() instead of fgetc(). However, the return value is *still* the one from the "real" fgetc(), even if we intercept what appears to be a Ctrl+C from an interactive console.

> I'm wondering if it is complaining about some aspect of our custom
> isspace() when used with EOF.

That would appear to be the real issue, yes, and I should have double-checked the claim that POSIX isspace() handles EOF properly: we override isspace() with our own version, after all:

	#define isspace(x) sane_istest(x,GIT_SPACE)
where
	#define sane_istest(x,mask) \
		((sane_ctype[(unsigned char)(x)] & (mask)) != 0)
(rewrapped for readability)

As usual, EOF is defined as -1 in Git for Windows' context, meaning that we look at the last entry of the sane_ctype array, which returns 0 for any sane_istest(x,mask) test for x >= 0x80:

        /* Nothing in the 128.. range */

So it would appear that it happens to work, but I doubt that it was intentional.

Having said that, it is really curious why Coverity should get confused by the code and not realize that casting a negative number to (unsigned char) will make it valid as an index for the sane_ctype array.

I double-checked, and there is no override for the isspace() function in what Coverity calls a "model file" (i.e. pseudo code intended to helping Coverity realize where it can stop reporting false positives).

Show 7 quoted lines
> > The next iteration will have it completely reworked: I no longer guard
> > the isspace() behind an `!= EOF` check, but rather handle an early EOF
> > as I think it should be handled. Extra eyes very welcome (this is the
> > fixup!  patch):
> 
> I do think handling EOF explicitly is probably a better strategy anyway,
> as it lets us tell when we have an empty patch.
I agree, I came to the same conclusion independently.

Ciao, Dscho

Jeff King· Apr 28, 2017, 13:45 UTC · re: Johannes Schindelin · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

On Fri, Apr 28, 2017 at 03:33:41PM +0200, Johannes Schindelin wrote:
Show 8 quoted lines
> As usual, EOF is defined as -1 in Git for Windows' context, meaning that
> we look at the last entry of the sane_ctype array, which returns 0 for any
> sane_istest(x,mask) test for x >= 0x80:
> 
>         /* Nothing in the 128.. range */
> 
> So it would appear that it happens to work, but I doubt that it was
> intentional.

Yeah, that was the same analysis I came to. Even though it works, it is a potential portability problem if a platform defines EOF in a weird way. The "right" thing in such a case is probably checking explicitly for EOF, but I'd hate to add an extra conditional to sane_istest(). It's a fairly hot code path. So I'm fine with punting on that until we see evidence of such a system.

> Having said that, it is really curious why Coverity should get confused by
> the code and not realize that casting a negative number to (unsigned char)
> will make it valid as an index for the sane_ctype array.

Yeah, that is the part that confuses me, too. It seems like an easy case to get right.

Oh well. If you are tweaking it to handle EOF separately for other reasons, then the Coverity question goes away entirely.

-Peff
Jeff King· Apr 27, 2017, 06:21 UTC · re: Johannes Schindelin · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

On Wed, Apr 26, 2017 at 10:20:16PM +0200, Johannes Schindelin wrote:
Show 11 quoted lines
> diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> index 30681681c13..c0d88f97512 100644
> --- a/builtin/mailsplit.c
> +++ b/builtin/mailsplit.c
> @@ -232,7 +232,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
>  
>  	do {
>  		peek = fgetc(f);
> -	} while (isspace(peek));
> +	} while (peek >= 0 && isspace(peek));
>  	ungetc(peek, f);

Are we guaranteed that EOF is a negative number? Also, what is the behavior of ungetc when we pass it EOF?

It looks like POSIX does what we want (pushing EOF is a noop, and the stream retains its feof() status), but I don't know if there are other implementations to worry about.

Perhaps:
  /* soak up whitespace */
  while ((peek = fgetc(f)) != EOF) {
	if (!isspace(peek)) {
		ungetc(peek, f);
		break;
	}
  }
would be more portable.
-Peff
Johannes Schindelin· Apr 28, 2017, 10:44 UTC · re: Jeff King · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

Hi Peff,
On Thu, 27 Apr 2017, Jeff King wrote:
Show 15 quoted lines
> On Wed, Apr 26, 2017 at 10:20:16PM +0200, Johannes Schindelin wrote:
> 
> > diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> > index 30681681c13..c0d88f97512 100644
> > --- a/builtin/mailsplit.c
> > +++ b/builtin/mailsplit.c
> > @@ -232,7 +232,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
> >  
> >  	do {
> >  		peek = fgetc(f);
> > -	} while (isspace(peek));
> > +	} while (peek >= 0 && isspace(peek));
> >  	ungetc(peek, f);
> 
> Are we guaranteed that EOF is a negative number?
No, you're right.
> Also, what is the behavior of ungetc when we pass it EOF?

According to the documentation, it would cast EOF to an unsigned char and push that back. Definitely incorrect.

> It looks like POSIX does what we want (pushing EOF is a noop, and the
> stream retains its feof() status), but I don't know if there are other
> implementations to worry about.
That's not what my man page here says:
	ungetc()  pushes  c  back to stream, cast to unsigned char, where
	it is available for subsequent read operations.  Pushed-back
	characters will be returned in reverse order; only one pushback is
	guaranteed.
Show 11 quoted lines
> Perhaps:
> 
>   /* soak up whitespace */
>   while ((peek = fgetc(f)) != EOF) {
> 	if (!isspace(peek)) {
> 		ungetc(peek, f);
> 		break;
> 	}
>   }
> 
> would be more portable.
True. I changed it slightly differently, please see my reply to Hannes.

Thanks, Dscho

Jeff King· Apr 28, 2017, 11:08 UTC · re: Johannes Schindelin · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

On Fri, Apr 28, 2017 at 12:44:52PM +0200, Johannes Schindelin wrote:
Show 15 quoted lines
> > Also, what is the behavior of ungetc when we pass it EOF?
> 
> According to the documentation, it would cast EOF to an unsigned char and
> push that back. Definitely incorrect.
> 
> > It looks like POSIX does what we want (pushing EOF is a noop, and the
> > stream retains its feof() status), but I don't know if there are other
> > implementations to worry about.
> 
> That's not what my man page here says:
> 
> 	ungetc()  pushes  c  back to stream, cast to unsigned char, where
> 	it is available for subsequent read operations.  Pushed-back
> 	characters will be returned in reverse order; only one pushback is
> 	guaranteed.
POSIX covers this this case explicitly:
  If the value of c equals that of the macro EOF, the operation shall
  fail and the input stream shall be left unchanged.
That comes straight from C99, which says:
  If the value of c equals that of the macro EOF, the operation fails
  and the input stream is unchanged.

I don't have a copy of C89 handy, but I didn't see any mention of the behavior in the "changes from the previous edition" section of C99.

So it's possible that there's an implementation that is unhappy with ungetc(EOF), but unless we know of one specifically, it seems pretty safe. Given that and the similar explicit rule for EOF via isspace(), I think the original code actually behaves fine.

Of course, we do not use the standard isspace() anyway. Our implementation will cast the EOF to an unsigned char. If it's "-1", that ends up as 255, which matches no classes. But if the platform has an oddball EOF like 288, that would confuse our isspace().

-Peff
Johannes Schindelin· Apr 28, 2017, 13:37 UTC · re: Jeff King · lore

Re: [PATCH 10/26] Check for EOF while parsing mails

Hi Peff,
On Fri, 28 Apr 2017, Jeff King wrote:
Show 30 quoted lines
> On Fri, Apr 28, 2017 at 12:44:52PM +0200, Johannes Schindelin wrote:
> 
> > > Also, what is the behavior of ungetc when we pass it EOF?
> > 
> > According to the documentation, it would cast EOF to an unsigned char and
> > push that back. Definitely incorrect.
> > 
> > > It looks like POSIX does what we want (pushing EOF is a noop, and the
> > > stream retains its feof() status), but I don't know if there are other
> > > implementations to worry about.
> > 
> > That's not what my man page here says:
> > 
> > 	ungetc()  pushes  c  back to stream, cast to unsigned char, where
> > 	it is available for subsequent read operations.  Pushed-back
> > 	characters will be returned in reverse order; only one pushback is
> > 	guaranteed.
> 
> POSIX covers this this case explicitly:
> 
>   If the value of c equals that of the macro EOF, the operation shall
>   fail and the input stream shall be left unchanged.
> 
> That comes straight from C99, which says:
> 
>   If the value of c equals that of the macro EOF, the operation fails
>   and the input stream is unchanged.
> 
> I don't have a copy of C89 handy, but I didn't see any mention of the
> behavior in the "changes from the previous edition" section of C99.

Yeah. I'd still be more comfortable with being explicit in this case, also because our documentation states explicitly that we do not necessarily live by the POSIX standard.

Ciao, Dscho

Johannes Schindelin· Apr 26, 2017, 20:20 UTC · re: Johannes Schindelin · lore

[PATCH 11/26] cat-file: fix memory leak

Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/cat-file.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/cat-file.c +1 −0
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 1890d7a6390..9af863e7915 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 		die("git cat-file %s: bad file", obj_name);
 
 	write_or_die(1, buf, size);
+	free(buf);
 	return 0;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· Apr 27, 2017, 06:10 UTC · re: Johannes Schindelin · lore

Re: [PATCH 11/26] cat-file: fix memory leak

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 18 quoted lines
> Discovered by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/cat-file.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/builtin/cat-file.c b/builtin/cat-file.c
> index 1890d7a6390..9af863e7915 100644
> --- a/builtin/cat-file.c
> +++ b/builtin/cat-file.c
> @@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
>  		die("git cat-file %s: bad file", obj_name);
>  
>  	write_or_die(1, buf, size);
> +	free(buf);
>  	return 0;
>  }

This is a border-line "Meh". Just like we do not free resources immediately before calling die(), we can leave this as-is as the only thing that happens after this is a return from cmd_cat_file() back to main() that exits.

The patch is not wrong per-se, so I've applied it anyway, though.
Thanks.
Johannes Schindelin· Apr 28, 2017, 09:59 UTC · re: Junio C Hamano · lore

Re: [PATCH 11/26] cat-file: fix memory leak

Hi Junio,
On Wed, 26 Apr 2017, Junio C Hamano wrote:
Show 25 quoted lines
> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> 
> > Discovered by Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  builtin/cat-file.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/builtin/cat-file.c b/builtin/cat-file.c
> > index 1890d7a6390..9af863e7915 100644
> > --- a/builtin/cat-file.c
> > +++ b/builtin/cat-file.c
> > @@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
> >  		die("git cat-file %s: bad file", obj_name);
> >  
> >  	write_or_die(1, buf, size);
> > +	free(buf);
> >  	return 0;
> >  }
> 
> This is a border-line "Meh".  Just like we do not free resources
> immediately before calling die(), we can leave this as-is as the
> only thing that happens after this is a return from cmd_cat_file()
> back to main() that exits.
If you are mostly concerned about the status quo, that is true.

I am a lot more concerned with future changes, where we may easily decide that it is time to move a file-local function out of its hiding place and make it more usable.

From that perspective, it is one thing to have a blatant memory leak in a cmd_*() function, and it is an entirely different matter to have such a leak in a function that happens to be called only from cmd_*() functions: somebody familiar enough with Git's coding conventions (such as myself) will *expect* cmd_*() to have leaks left and right and pay attention when libifying that code, but be a lot less concerned about such leaks in other functions.

And of course this concerns me more than you, as I am still trying to drive forward the effort to convert more scripts into builtins.

So on my own behalf: thank you for accepting this patch.

Ciao, Dscho

Johannes Schindelin· Apr 26, 2017, 20:20 UTC · re: Johannes Schindelin · lore

[PATCH 12/26] checkout: fix memory leak

Discovered via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/checkout.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/checkout.c +1 −0
diff --git a/builtin/checkout.c b/builtin/checkout.c
index bfa5419f335..98f98256608 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
 	if (!ce)
 		die(_("make_cache_entry failed for path '%s'"), path);
 	status = checkout_entry(ce, state, NULL);
+	free(ce);
 	return status;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· Apr 27, 2017, 06:40 UTC · re: Johannes Schindelin · lore

Re: [PATCH 12/26] checkout: fix memory leak

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 18 quoted lines
> Discovered via Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/checkout.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index bfa5419f335..98f98256608 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
>  	if (!ce)
>  		die(_("make_cache_entry failed for path '%s'"), path);
>  	status = checkout_entry(ce, state, NULL);
> +	free(ce);
>  	return status;
>  }
Thanks for spotting this one and fixing it.  

In case anybody is wondering what the "only to leak" comment before this part of the code is about (which by the way may need to be updated, as the bulk of its reasoning still applies but at least we are no longer leaking with this patch), back when this code was written in 2008 or so it wasn't kosher to free cache_entry under certain conditions, but it has been a long time since it became OK to free any cache entries in later 2011---we should have done this a long time ago.

Johannes Schindelin· Apr 28, 2017, 10:51 UTC · re: Junio C Hamano · lore

Re: [PATCH 12/26] checkout: fix memory leak

Hi Junio,
On Wed, 26 Apr 2017, Junio C Hamano wrote:
Show 31 quoted lines
> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> 
> > Discovered via Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  builtin/checkout.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/builtin/checkout.c b/builtin/checkout.c
> > index bfa5419f335..98f98256608 100644
> > --- a/builtin/checkout.c
> > +++ b/builtin/checkout.c
> > @@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
> >  	if (!ce)
> >  		die(_("make_cache_entry failed for path '%s'"), path);
> >  	status = checkout_entry(ce, state, NULL);
> > +	free(ce);
> >  	return status;
> >  }
> 
> Thanks for spotting this one and fixing it.  
> 
> In case anybody is wondering what the "only to leak" comment before
> this part of the code is about (which by the way may need to be
> updated, as the bulk of its reasoning still applies but at least we
> are no longer leaking with this patch), back when this code was
> written in 2008 or so it wasn't kosher to free cache_entry under
> certain conditions, but it has been a long time since it became OK
> to free any cache entries in later 2011---we should have done this a
> long time ago.

Thanks for the background. The next iteration will change that comment, too (simply removing "just to leak" and rewrapping to 74 columns/line.

Ciao, Dscho

Johannes Schindelin· Apr 26, 2017, 20:20 UTC · re: Johannes Schindelin · lore

[PATCH 13/26] split_commit_in_progress(): fix memory leak

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
Show changes to wt-status.c +6 −1
diff --git a/wt-status.c b/wt-status.c
index 0a6e16dbe0f..1f3f6bcb980 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1088,8 +1088,13 @@ static int split_commit_in_progress(struct wt_status *s)
 	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
 
 	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
-	    !s->branch || strcmp(s->branch, "HEAD"))
+	    !s->branch || strcmp(s->branch, "HEAD")) {
+		free(head);
+		free(orig_head);
+		free(rebase_amend);
+		free(rebase_orig_head);
 		return split_in_progress;
+	}
 
 	if (!strcmp(rebase_amend, rebase_orig_head)) {
 		if (strcmp(head, rebase_amend))
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:20 UTC · re: Johannes Schindelin · lore

[PATCH 14/26] setup_bare_git_dir(): fix memory leak

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 setup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to setup.c +1 −1
diff --git a/setup.c b/setup.c
index 0309c278218..0320a9ad14c 100644
--- a/setup.c
+++ b/setup.c
@@ -748,7 +748,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
 
 	/* --work-tree is set without --git-dir; use discovered one */
 	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
-		const char *gitdir;
+		static const char *gitdir;
 
 		gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
 		if (chdir(cwd->buf))
-- 
2.12.2.windows.2.800.gede8f145e06
Stefan Beller· Apr 26, 2017, 21:20 UTC · re: Johannes Schindelin · lore

Re: [PATCH 14/26] setup_bare_git_dir(): fix memory leak

On Wed, Apr 26, 2017 at 1:20 PM, Johannes Schindelin <johannes.schindelin@gmx.de> wrote:

Show 17 quoted lines
> Reported by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  setup.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/setup.c b/setup.c
> index 0309c278218..0320a9ad14c 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -748,7 +748,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
>
>         /* --work-tree is set without --git-dir; use discovered one */
>         if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
> -               const char *gitdir;
> +               static const char *gitdir;

This alone doesn't fix the memleak if the code were called multiple times. As by having it static it will be init'd to NULL, we could introduce a

    static const char *gitdir; /* must live until the end of time because ... */
    if (!gitdir)
        die("BUG: called setup_bare_git_dir twice?");

I tried looking into setup_explicit_git_dir that is called with gitdir here and it looks like it duplicates the memory in most cases, so maybe we can even get away with no static variable here and instead either inline the gitdir computation in the arguments of setup_explicit_git_dir or have a variable here that holds the returns of setup_explicit_git_dir such that we can free after?

Thanks, Stefan

Johannes Schindelin· Apr 27, 2017, 22:54 UTC · re: Stefan Beller · lore

Re: [PATCH 14/26] setup_bare_git_dir(): fix memory leak

Hi Stefan,
On Wed, 26 Apr 2017, Stefan Beller wrote:
Show 33 quoted lines
> On Wed, Apr 26, 2017 at 1:20 PM, Johannes Schindelin
> <johannes.schindelin@gmx.de> wrote:
> > Reported by Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  setup.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/setup.c b/setup.c
> > index 0309c278218..0320a9ad14c 100644
> > --- a/setup.c
> > +++ b/setup.c
> > @@ -748,7 +748,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
> >
> >         /* --work-tree is set without --git-dir; use discovered one */
> >         if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
> > -               const char *gitdir;
> > +               static const char *gitdir;
> 
> This alone doesn't fix the memleak if the code were called multiple times.
> As by having it static it will be init'd to NULL, we could introduce a
> 
>     static const char *gitdir; /* must live until the end of time because ... */
>     if (!gitdir)
>         die("BUG: called setup_bare_git_dir twice?");
> 
> I tried looking into setup_explicit_git_dir that is called with gitdir here
> and it looks like it duplicates the memory in most cases, so maybe we
> can even get away with no static variable here and instead either inline
> the gitdir computation in the arguments of setup_explicit_git_dir
> or have a variable here that holds the returns of setup_explicit_git_dir
> such that we can free after?

setup_bare_git_directory() is called by setup_git_directory(), and that latter function is not reentrant. If you call setup_git_directory() multiple times, it will wreak havoc, as e.g. the second time the prefix cannot be determined correctly because we chdir()ed up into the top-level directory.

So I am not worried about this new static, it is essentially a singleton.

Ciao, Dscho

Johannes Sixt· Apr 27, 2017, 06:27 UTC · re: Johannes Schindelin · lore

Re: [PATCH 14/26] setup_bare_git_dir(): fix memory leak

Am 26.04.2017 um 22:20 schrieb Johannes Schindelin:
Show 21 quoted lines
> Reported by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  setup.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/setup.c b/setup.c
> index 0309c278218..0320a9ad14c 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -748,7 +748,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
>
>  	/* --work-tree is set without --git-dir; use discovered one */
>  	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
> -		const char *gitdir;
> +		static const char *gitdir;
>
>  		gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
>  		if (chdir(cwd->buf))
>

Whoa! Look what values are assigned to the variable: Either a static string or allocated memory. I suspect that this does not fix a memory leak at all, but only shuts up Coverity.

-- Hannes
PS: stopping here as I'm running out of time.
Johannes Schindelin· Apr 27, 2017, 22:57 UTC · re: Johannes Sixt · lore

Re: [PATCH 14/26] setup_bare_git_dir(): fix memory leak

Hi Hannes,
On Thu, 27 Apr 2017, Johannes Sixt wrote:
Show 31 quoted lines
> Am 26.04.2017 um 22:20 schrieb Johannes Schindelin:
> > Reported by Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  setup.c | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/setup.c b/setup.c
> > index 0309c278218..0320a9ad14c 100644
> > --- a/setup.c
> > +++ b/setup.c
> > @@ -748,7 +748,7 @@ static const char *setup_bare_git_dir(struct strbuf
> > *cwd, int offset,
> >
> >   /* --work-tree is set without --git-dir; use discovered one */
> >   if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
> > -		const char *gitdir;
> > +		static const char *gitdir;
> >
> >    gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
> >    if (chdir(cwd->buf))
> >
> 
> Whoa! Look what values are assigned to the variable: Either a static string or
> allocated memory. I suspect that this does not fix a memory leak at all, but
> only shuts up Coverity.
> 
> -- Hannes
> 
> PS: stopping here as I'm running out of time.

Sorry, I meant to amend the commit message and forgot before sending the first time: setup_git_directory() (and consequently, setup_bare_git_dir()) can only be called once.

Yes, this patch is here to shut up Coverity, as it cannot know that we are talking about a singleton here.

Ciao, Dscho

Johannes Schindelin· Apr 26, 2017, 20:20 UTC · re: Johannes Schindelin · lore

[PATCH 15/26] setup_discovered_git_dir(): fix memory leak

Identified by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 setup.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
Show changes to setup.c +7 −2
diff --git a/setup.c b/setup.c
index 0320a9ad14c..12efca85a41 100644
--- a/setup.c
+++ b/setup.c
@@ -703,11 +703,16 @@ static const char *setup_discovered_git_dir(const char *gitdir,
 
 	/* --work-tree is set without --git-dir; use discovered one */
 	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+		char *p = NULL;
+		const char *ret;
+
 		if (offset != cwd->len && !is_absolute_path(gitdir))
-			gitdir = real_pathdup(gitdir, 1);
+			gitdir = p = real_pathdup(gitdir, 1);
 		if (chdir(cwd->buf))
 			die_errno("Could not come back to cwd");
-		return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+		ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+		free(p);
+		return ret;
 	}
 
 	/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:20 UTC · re: Johannes Schindelin · lore

[PATCH 16/26] pack-redundant: plug memory leak

Identified via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/pack-redundant.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/pack-redundant.c +1 −0
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 72c815844dd..cb1df1c7614 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -442,6 +442,7 @@ static void minimize(struct pack_list **min)
 	/* return if there are no objects missing from the unique set */
 	if (missing->size == 0) {
 		*min = unique;
+		free(missing);
 		return;
 	}
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 17/26] mktree: plug memory leaks reported by Coverity

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/mktree.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to builtin/mktree.c +3 −2
diff --git a/builtin/mktree.c b/builtin/mktree.c
index de9b40fc63b..f0354bc9718 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -72,7 +72,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 	unsigned mode;
 	enum object_type mode_type; /* object type derived from mode */
 	enum object_type obj_type; /* object type derived from sha */
-	char *path;
+	char *path, *p = NULL;
 	unsigned char sha1[20];
 
 	ptr = buf;
@@ -102,7 +102,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 		struct strbuf p_uq = STRBUF_INIT;
 		if (unquote_c_style(&p_uq, path, NULL))
 			die("invalid quoting");
-		path = strbuf_detach(&p_uq, NULL);
+		path = p = strbuf_detach(&p_uq, NULL);
 	}
 
 	/*
@@ -136,6 +136,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 	}
 
 	append_to_tree(mode, sha1, path);
+	free(p);
 }
 
 int cmd_mktree(int ac, const char **av, const char *prefix)
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 18/26] fast-export: avoid leaking memory in handle_tag()

Reported by, you guessed it, Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/fast-export.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/fast-export.c +1 −0
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index e0220630d00..828d41c0c11 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -765,6 +765,7 @@ static void handle_tag(const char *name, struct tag *tag)
 	       (int)(tagger_end - tagger), tagger,
 	       tagger == tagger_end ? "" : "\n",
 	       (int)message_size, (int)message_size, message ? message : "");
+	free(buf);
 }
 
 static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Sixt· Apr 27, 2017, 16:39 UTC · re: Johannes Schindelin · lore

Re: [PATCH 18/26] fast-export: avoid leaking memory in handle_tag()

Am 26.04.2017 um 22:21 schrieb Johannes Schindelin:
Show 20 quoted lines
> Reported by, you guessed it, Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/fast-export.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/builtin/fast-export.c b/builtin/fast-export.c
> index e0220630d00..828d41c0c11 100644
> --- a/builtin/fast-export.c
> +++ b/builtin/fast-export.c
> @@ -765,6 +765,7 @@ static void handle_tag(const char *name, struct tag *tag)
>  	       (int)(tagger_end - tagger), tagger,
>  	       tagger == tagger_end ? "" : "\n",
>  	       (int)message_size, (int)message_size, message ? message : "");
> +	free(buf);
>  }
>
>  static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
>

There is an early return in the function that is not covered by this patch. Look for "case DROP".

-- Hannes
Johannes Schindelin· Apr 28, 2017, 10:58 UTC · re: Johannes Sixt · lore

Re: [PATCH 18/26] fast-export: avoid leaking memory in handle_tag()

Hi Hannes,
On Thu, 27 Apr 2017, Johannes Sixt wrote:
Show 25 quoted lines
> Am 26.04.2017 um 22:21 schrieb Johannes Schindelin:
> > Reported by, you guessed it, Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  builtin/fast-export.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/builtin/fast-export.c b/builtin/fast-export.c
> > index e0220630d00..828d41c0c11 100644
> > --- a/builtin/fast-export.c
> > +++ b/builtin/fast-export.c
> > @@ -765,6 +765,7 @@ static void handle_tag(const char *name, struct tag
> > *tag)
> >          (int)(tagger_end - tagger), tagger,
> >          tagger == tagger_end ? "" : "\n",
> >          (int)message_size, (int)message_size, message ? message : "");
> > +	free(buf);
> >  }
> >
> >  static struct commit *get_commit(struct rev_cmdline_entry *e, char
> >  *full_name)
> >
> 
> There is an early return in the function that is not covered by this patch.
Thanks!
> Look for "case DROP".
Or for "return" ;-)

I briefly looked into simply releasing the memory earlier, but the tagger variable used just before the inserted free(buf) actually points into the buffer, so I had to repeat the free(buf) for the early return.

Thank you! Dscho

Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 19/26] receive-pack: plug memory leak in update()

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/receive-pack.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
Show changes to builtin/receive-pack.c +3 −1
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index f96834f42c9..48c07ddb659 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -986,7 +986,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 {
 	const char *name = cmd->ref_name;
 	struct strbuf namespaced_name_buf = STRBUF_INIT;
-	const char *namespaced_name, *ret;
+	static char *namespaced_name;
+	const char *ret;
 	struct object_id *old_oid = &cmd->old_oid;
 	struct object_id *new_oid = &cmd->new_oid;
 
@@ -997,6 +998,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 	}
 
 	strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+	free(namespaced_name);
 	namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
 
 	if (is_ref_checked_out(namespaced_name)) {
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 20/26] line-log: avoid memory leak

Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 line-log.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to line-log.c +1 −0
diff --git a/line-log.c b/line-log.c
index a23b910471b..19d46e9ea2c 100644
--- a/line-log.c
+++ b/line-log.c
@@ -1125,6 +1125,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
 	changed = process_all_files(&parent_range, rev, &queue, range);
 	if (parent)
 		add_line_range(rev, parent, parent_range);
+	free(parent_range);
 	return changed;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Sixt· Apr 27, 2017, 17:14 UTC · re: Johannes Schindelin · lore

Re: [PATCH 20/26] line-log: avoid memory leak

Am 26.04.2017 um 22:21 schrieb Johannes Schindelin:
Show 20 quoted lines
> Discovered by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  line-log.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/line-log.c b/line-log.c
> index a23b910471b..19d46e9ea2c 100644
> --- a/line-log.c
> +++ b/line-log.c
> @@ -1125,6 +1125,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
>  	changed = process_all_files(&parent_range, rev, &queue, range);
>  	if (parent)
>  		add_line_range(rev, parent, parent_range);
> +	free(parent_range);
>  	return changed;
>  }
>
>

parent_range is of type struct line_log_data *, which needs more than a mere free(). I think it's free_line_log_data(parent_range).

-- Hannes
Johannes Schindelin· Apr 28, 2017, 11:02 UTC · re: Johannes Sixt · lore

Re: [PATCH 20/26] line-log: avoid memory leak

Hi Hannes,
On Thu, 27 Apr 2017, Johannes Sixt wrote:
Show 25 quoted lines
> Am 26.04.2017 um 22:21 schrieb Johannes Schindelin:
> > Discovered by Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  line-log.c | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/line-log.c b/line-log.c
> > index a23b910471b..19d46e9ea2c 100644
> > --- a/line-log.c
> > +++ b/line-log.c
> > @@ -1125,6 +1125,7 @@ static int process_ranges_ordinary_commit(struct
> > rev_info *rev, struct commit *c
> >   changed = process_all_files(&parent_range, rev, &queue, range);
> >   if (parent)
> > 		add_line_range(rev, parent, parent_range);
> > +	free(parent_range);
> >  	return changed;
> >  }
> >
> >
> 
> parent_range is of type struct line_log_data *, which needs more than a mere
> free(). I think it's free_line_log_data(parent_range).
Oh wow, thanks for pointing that out. Will be fixed in the next iteration.

Ciao, Dscho

Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 21/26] shallow: avoid memory leak

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 shallow.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
Show changes to shallow.c +6 −2
diff --git a/shallow.c b/shallow.c
index 25b6db989bf..f9370961f99 100644
--- a/shallow.c
+++ b/shallow.c
@@ -473,11 +473,15 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,
 	struct commit_list *head = NULL;
 	int bitmap_nr = (info->nr_bits + 31) / 32;
 	size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr);
-	uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */
-	uint32_t *bitmap = paint_alloc(info);
 	struct commit *c = lookup_commit_reference_gently(sha1, 1);
+	uint32_t *tmp; /* to be freed before return */
+	uint32_t *bitmap;
+
 	if (!c)
 		return;
+
+	tmp = xmalloc(bitmap_size);
+	bitmap = paint_alloc(info);
 	memset(bitmap, 0, bitmap_size);
 	bitmap[id / 32] |= (1U << (id % 32));
 	commit_list_insert(c, &head);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 22/26] add_reflog_for_walk: avoid memory leak

We free()d the `log` buffer when dwim_log() returned 1, but not when it returned a larger value (which meant that it still allocated the buffer but we simply ignored it).

Identified by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 reflog-walk.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
Show changes to reflog-walk.c +5 −1
diff --git a/reflog-walk.c b/reflog-walk.c
index 99679f58255..ec66f2b16e6 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -183,7 +183,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 		if (!reflogs || reflogs->nr == 0) {
 			struct object_id oid;
 			char *b;
-			if (dwim_log(branch, strlen(branch), oid.hash, &b) == 1) {
+			int ret = dwim_log(branch, strlen(branch),
+					   oid.hash, &b);
+			if (ret > 1)
+				free(b);
+			else if (ret == 1) {
 				if (reflogs) {
 					free(reflogs->ref);
 					free(reflogs);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Sixt· Apr 27, 2017, 17:24 UTC · re: Johannes Schindelin · lore

Re: [PATCH 22/26] add_reflog_for_walk: avoid memory leak

Am 26.04.2017 um 22:21 schrieb Johannes Schindelin:
Show 29 quoted lines
> We free()d the `log` buffer when dwim_log() returned 1, but not when it
> returned a larger value (which meant that it still allocated the buffer
> but we simply ignored it).
>
> Identified by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  reflog-walk.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/reflog-walk.c b/reflog-walk.c
> index 99679f58255..ec66f2b16e6 100644
> --- a/reflog-walk.c
> +++ b/reflog-walk.c
> @@ -183,7 +183,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
>  		if (!reflogs || reflogs->nr == 0) {
>  			struct object_id oid;
>  			char *b;
> -			if (dwim_log(branch, strlen(branch), oid.hash, &b) == 1) {
> +			int ret = dwim_log(branch, strlen(branch),
> +					   oid.hash, &b);
> +			if (ret > 1)
> +				free(b);
> +			else if (ret == 1) {
>  				if (reflogs) {
>  					free(reflogs->ref);
>  					free(reflogs);
>

Right after this hunk, there is another conditional that looks like it forgets to free reflogs.

-- Hannes
Johannes Schindelin· Apr 28, 2017, 11:33 UTC · re: Johannes Sixt · lore

Re: [PATCH 22/26] add_reflog_for_walk: avoid memory leak

Hi Hannes,
On Thu, 27 Apr 2017, Johannes Sixt wrote:
Show 34 quoted lines
> Am 26.04.2017 um 22:21 schrieb Johannes Schindelin:
> > We free()d the `log` buffer when dwim_log() returned 1, but not when it
> > returned a larger value (which meant that it still allocated the buffer
> > but we simply ignored it).
> >
> > Identified by Coverity.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >  reflog-walk.c | 6 +++++-
> >  1 file changed, 5 insertions(+), 1 deletion(-)
> >
> > diff --git a/reflog-walk.c b/reflog-walk.c
> > index 99679f58255..ec66f2b16e6 100644
> > --- a/reflog-walk.c
> > +++ b/reflog-walk.c
> > @@ -183,7 +183,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
> >    if (!reflogs || reflogs->nr == 0) {
> >     struct object_id oid;
> >     char *b;
> > -			if (dwim_log(branch, strlen(branch), oid.hash, &b) ==
> > 1) {
> > +			int ret = dwim_log(branch, strlen(branch),
> > +					   oid.hash, &b);
> > +			if (ret > 1)
> > +				free(b);
> > +			else if (ret == 1) {
> >      if (reflogs) {
> >       free(reflogs->ref);
> >       free(reflogs);
> >
> 
> Right after this hunk, there is another conditional that looks like it
> forgets to free reflogs.

Thanks! Seems I got too hung up with the line to which Coverity pointed and failed to see the bigger picture.

It seems that there are plenty of leaks, even further down. For one, the `branch` variable is not released at the very end of the function! One might think that read_complete_reflogs() takes custody of it, but no, it xstrdup()s the refname right at the beginning.

So there was a lot more memory leaking going on in that function...

Ciao, Dscho

Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 23/26] remote: plug memory leak in match_explicit()

The `guess_ref()` returns an allocated buffer of which `make_linked_ref()` does not take custody (`alloc_ref()` makes a copy), therefore we need to release the buffer afterwards.

Noticed via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 remote.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to remote.c +3 −2
diff --git a/remote.c b/remote.c
index 801137c72eb..72b4591b983 100644
--- a/remote.c
+++ b/remote.c
@@ -1191,9 +1191,10 @@ static int match_explicit(struct ref *src, struct ref *dst,
 		else if (is_null_oid(&matched_src->new_oid))
 			error("unable to delete '%s': remote ref does not exist",
 			      dst_value);
-		else if ((dst_guess = guess_ref(dst_value, matched_src)))
+		else if ((dst_guess = guess_ref(dst_value, matched_src))) {
 			matched_dst = make_linked_ref(dst_guess, dst_tail);
-		else
+			free(dst_guess);
+		} else
 			error("unable to push to unqualified destination: %s\n"
 			      "The destination refspec neither matches an "
 			      "existing ref on the remote nor\n"
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:22 UTC · re: Johannes Schindelin · lore

[PATCH 26/26] submodule_uses_worktrees(): plug memory leak

There is really no reason why we would need to hold onto the allocated string longer than necessary.

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 worktree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to worktree.c +1 −1
diff --git a/worktree.c b/worktree.c
index bae787cf8d7..89a81b13de3 100644
--- a/worktree.c
+++ b/worktree.c
@@ -399,6 +399,7 @@ int submodule_uses_worktrees(const char *path)
 
 	/* The env would be set for the superproject. */
 	get_common_dir_noenv(&sb, submodule_gitdir);
+	free(submodule_gitdir);
 
 	/*
 	 * The check below is only known to be good for repository format
@@ -418,7 +419,6 @@ int submodule_uses_worktrees(const char *path)
 	/* See if there is any file inside the worktrees directory. */
 	dir = opendir(sb.buf);
 	strbuf_release(&sb);
-	free(submodule_gitdir);
 
 	if (!dir)
 		return 0;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 25/26] show_worktree(): plug memory leak

The buffer allocated by shorten_unambiguous_ref() needs to be released.
Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/worktree.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Show changes to builtin/worktree.c +5 −3
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 9993ded41aa..6bfd7ad5323 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -409,9 +409,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
 				find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
 		if (wt->is_detached)
 			strbuf_addstr(&sb, "(detached HEAD)");
-		else if (wt->head_ref)
-			strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
-		else
+		else if (wt->head_ref) {
+			char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
+			strbuf_addf(&sb, "[%s]", ref);
+			free(ref);
+		} else
 			strbuf_addstr(&sb, "(error)");
 	}
 	printf("%s\n", sb.buf);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 26, 2017, 20:21 UTC · re: Johannes Schindelin · lore

[PATCH 24/26] name-rev: avoid leaking memory in the `deref` case

When the `name_rev()` function is asked to dereference the tip name, it allocates memory. But when it turns out that another tip already described the commit better than the current one, we forgot to release the memory.

Pointed out by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/name-rev.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
Show changes to builtin/name-rev.c +5 −2
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 92a5d8a5d26..a4ce73fb1e9 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
 	struct rev_name *name = (struct rev_name *)commit->util;
 	struct commit_list *parents;
 	int parent_number = 1;
+	char *p = NULL;
 
 	parse_commit(commit);
 
@@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
 		return;
 
 	if (deref) {
-		tip_name = xstrfmt("%s^0", tip_name);
+		tip_name = p = xstrfmt("%s^0", tip_name);
 
 		if (generation)
 			die("generation: %d, but deref?", generation);
@@ -53,8 +54,10 @@ static void name_rev(struct commit *commit,
 		name->taggerdate = taggerdate;
 		name->generation = generation;
 		name->distance = distance;
-	} else
+	} else {
+		free(p);
 		return;
+	}
 
 	for (parents = commit->parents;
 			parents;
-- 
2.12.2.windows.2.800.gede8f145e06
Stefan Beller· Apr 26, 2017, 21:34 UTC · re: Johannes Schindelin · lore

Re: [PATCH 00/26] Address a couple of issues identified by Coverity

On Wed, Apr 26, 2017 at 1:19 PM, Johannes Schindelin <johannes.schindelin@gmx.de> wrote:

> I recently registered the git-for-windows fork with Coverity to ensure
> that even the Windows-specific patches get some static analysis love.

YAY! How do you trigger the coverity scan? (via travis or uploading a tarball manually every once in a while?) Can you talk about the setup? I'm interested in that as I run coverity for Junios pu branch, plus a couple patches on top[1].

[1] https://github.com/stefanbeller/git/commits/coverity
>
> While at it, I squashed a couple of obvious issues in the part that is
> not Windows-specific.
Thanks.
Show 6 quoted lines
> Note: while this patch series squashes some of those issues, the
> remaining issues are not necessarily all false positives (e.g. Coverity
> getting fooled by our FLEX_ARRAY trick into believing that the last
> member of the struct is indeed a 0 or 1 size array) or intentional (e.g.
> builtins not releasing memory because exit() is called right after
> returning from the function that leaks memory).

For the latter I think we could get away with maintaining patches on a dedicated coverity branch (which I do currently, just not in an extensive manner). For the first, I think we can just compile with FLEX_ARRAY defined as an insanely large number. I'll experiment with that.

Show 22 quoted lines
> Notable examples of the remaining issues are:
>
> - a couple of callers of shorten_unambiguous_ref() assume that they do
>   not have to release the memory returned from that function, often
>   assigning the pointer to a `const` variable that typically does not
>   hold a pointer that needs to be free()d. My hunch is that we will want
>   to convert that function to have a fixed number of static buffers and
>   use those in a round robin fashion à la sha1_to_hex().
>
> - pack-redundant.c seems to have hard-to-reason-about code paths that
>   may eventually leak memory. Essentially, the custody of the allocated
>   memory is not clear at all.
>
> - fast-import.c calls strbuf_detach() on the command_buf without any
>   obvious rationale. Turns out that *some* code paths assign
>   command_buf.buf to a `recent_command` which releases the buffer later.
>   However, from a cursory look it appears to me as if there are some
>   other code paths that skip that assignment, effectively causing a memory
>   leak once strbuf_detach() is called.
>
> Sadly, I lack the time to pursue those remaining issues further.
>

Thanks, Stefan

Johannes Schindelin· Apr 27, 2017, 22:50 UTC · re: Stefan Beller · lore

Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Hi Stefan,
On Wed, 26 Apr 2017, Stefan Beller wrote:
Show 6 quoted lines
> On Wed, Apr 26, 2017 at 1:19 PM, Johannes Schindelin
> <johannes.schindelin@gmx.de> wrote:
> > I recently registered the git-for-windows fork with Coverity to ensure
> > that even the Windows-specific patches get some static analysis love.
> 
> YAY! How do you trigger the coverity scan?

For starters, I did everything manually. But I already have the grand plan to use VSTS build (I do not want to advertise this system too blatantly, but I have to say that I really love working with that system, it is so much more powerful than Travis or AppVeyor, Jenkins comes closer but not by far).

As you may have glimpsed in one of my mails, Git for Windows needs a very special and extensive build setup. I call it the "Git for Windows SDK", and what it is, in a nutshell, is a custom MSYS2 installation that has all the packages installed that are needed to build Git for Windows, its most important dependencies, and to bundle everything in an installer. Think of MSYS2 as something like Homebrew. But cozier, as it really lives inside its own directory tree, its /etc/ is not really visible to any other software, for example.

This makes Continuous Testing a bit of a challenge, as you cannot hammer the package repository of MSYS2 with tons of fresh full installations all the time (that package repository is run by a volunteer, and it is sometimes unreachable, too).

So after talking to a GitHub guy at the Developer Summit during GitMerge (Patrick asked a couple of questions and then said my plan was okay), I put two new repositories up that host the initialized Git for Windows SDKs (one for 32-bit, one for 64-bit).

And of course there is a job to keep them up-to-date, run once every 24h.

Almost all of the VSTS builds I maintain clone or update one or both of these repositories.

And so will also the Coverity job.

I still have to find the time to figure out one more detail: how to download and extract the Coverity tool (the .zip archive has a variable name for the top-level directory), and doing that only every once in a while, say, only when there is no previously unpacked tool, or it is already 4 weeks old.

And then I should probably try to figure out a way how to delay subsequent runs of that job so that we run it at most once every twenty-four hours.

Ciao, Dscho

Stefan Beller· Apr 28, 2017, 18:05 UTC · re: Johannes Schindelin · lore

Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Hi Johannes,
thanks for the reply.

On Thu, Apr 27, 2017 at 3:50 PM, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:

Show 5 quoted lines
> I still have to find the time to figure out one more detail: how to
> download and extract the Coverity tool (the .zip archive has a variable
> name for the top-level directory), and doing that only every once
> in a while, say, only when there is no previously unpacked tool, or it is
> already 4 weeks old.

That is an interesting problem, which I ignored as the older versions of their tools still works once they release new versions. So I just manually check every once in a while if they have new versions out there.

So if you find a nice solution to that problem, let me know, please.

Thanks, Stefan

Johannes Schindelin· Apr 28, 2017, 20:29 UTC · re: Stefan Beller · lore

Automating Coverity, was Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Hi Stefan,
On Fri, 28 Apr 2017, Stefan Beller wrote:
Show 15 quoted lines
> On Thu, Apr 27, 2017 at 3:50 PM, Johannes Schindelin
> <Johannes.Schindelin@gmx.de> wrote:
> 
> > I still have to find the time to figure out one more detail: how to
> > download and extract the Coverity tool (the .zip archive has a
> > variable name for the top-level directory), and doing that only every
> > once in a while, say, only when there is no previously unpacked tool,
> > or it is already 4 weeks old.
> 
> That is an interesting problem, which I ignored as the older versions of
> their tools still works once they release new versions. So I just
> manually check every once in a while if they have new versions out
> there.
> 
> So if you find a nice solution to that problem, let me know, please.
I think I have a working idea (jotting it down in the editor, untested):
	init_or_update_coverity_tool () {
		# check once per week whether there is a new version
		coverity_tool=.git/coverity-tool/
		test ! -d $coverity_tool ||
		test $(($(date +%s)-$(stat -c %Y $coverity_tool))) -gt
			$((7*24*60*60)) ||
		return
		curl --form "token=$(COVERITY.TOKEN)" \
			--form "project=git-for-windows" \
			--time-cond .git/coverity_tool.zip \
			-o .git/coverity_tool.zip.new \
			https://scan.coverity.com/download/win64 &&
		test -f .git/coverity_tool.zip.new || {
			# Try again in a week
			touch $coverity_tool
			return
		}
		mv -f .git/coverity_tool.zip.new .git/coverity_tool.zip ||
		die "Could not overwrite coverity_tool.zip"
		mkdir $coverity_tool.new &&
		(cd $coverity_tool.new &&
		 unzip ../coverity_tool.zip) ||
		die "Could not unpack coverity_tool.zip"
		rm -rf $coverity_tool &&
		mv $coverity_tool.new $coverity_tool ||
		die "Could not switch to new Coverity tool version"
	}
	init_or_update_coverity_tool
	PATH=$(echo $coverity_tool/*/bin):$PATH

I guess I will start from that snippet once I have time to work on that Coverity automation.

BTW I stumbled over an interesting tidbit today: if you define FLEX_ARRAY outside of git-compat-util.h, it will not be overridden by Git. That is, if you want to use 64kB flex arrays by default, you can call

	make CPPFLAGS=-DFLEX_ARRAY=65536
No need to patch the source code.

Ciao, Dscho

Lars Schneider· May 1, 2017, 11:22 UTC · re: Johannes Schindelin · lore

Re: Automating Coverity, was Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Show 69 quoted lines
> On 28 Apr 2017, at 22:29, Johannes Schindelin <johannes.schindelin@gmx.de> wrote:
> 
> Hi Stefan,
> 
> On Fri, 28 Apr 2017, Stefan Beller wrote:
> 
>> On Thu, Apr 27, 2017 at 3:50 PM, Johannes Schindelin
>> <Johannes.Schindelin@gmx.de> wrote:
>> 
>>> I still have to find the time to figure out one more detail: how to
>>> download and extract the Coverity tool (the .zip archive has a
>>> variable name for the top-level directory), and doing that only every
>>> once in a while, say, only when there is no previously unpacked tool,
>>> or it is already 4 weeks old.
>> 
>> That is an interesting problem, which I ignored as the older versions of
>> their tools still works once they release new versions. So I just
>> manually check every once in a while if they have new versions out
>> there.
>> 
>> So if you find a nice solution to that problem, let me know, please.
> 
> I think I have a working idea (jotting it down in the editor, untested):
> 
> 	init_or_update_coverity_tool () {
> 		# check once per week whether there is a new version
> 		coverity_tool=.git/coverity-tool/
> 		test ! -d $coverity_tool ||
> 		test $(($(date +%s)-$(stat -c %Y $coverity_tool))) -gt
> 			$((7*24*60*60)) ||
> 		return
> 
> 		curl --form "token=$(COVERITY.TOKEN)" \
> 			--form "project=git-for-windows" \
> 			--time-cond .git/coverity_tool.zip \
> 			-o .git/coverity_tool.zip.new \
> 			https://scan.coverity.com/download/win64 &&
> 		test -f .git/coverity_tool.zip.new || {
> 			# Try again in a week
> 			touch $coverity_tool
> 			return
> 		}
> 
> 		mv -f .git/coverity_tool.zip.new .git/coverity_tool.zip ||
> 		die "Could not overwrite coverity_tool.zip"
> 
> 		mkdir $coverity_tool.new &&
> 		(cd $coverity_tool.new &&
> 		 unzip ../coverity_tool.zip) ||
> 		die "Could not unpack coverity_tool.zip"
> 
> 		rm -rf $coverity_tool &&
> 		mv $coverity_tool.new $coverity_tool ||
> 		die "Could not switch to new Coverity tool version"
> 	}
> 
> 	init_or_update_coverity_tool
> 	PATH=$(echo $coverity_tool/*/bin):$PATH
> 
> I guess I will start from that snippet once I have time to work on that
> Coverity automation.
> 
> BTW I stumbled over an interesting tidbit today: if you define FLEX_ARRAY
> outside of git-compat-util.h, it will not be overridden by Git. That is,
> if you want to use 64kB flex arrays by default, you can call
> 
> 	make CPPFLAGS=-DFLEX_ARRAY=65536
> 
> No need to patch the source code.

Looks like Coverity has TravisCI integration and I assume you wouldn't need to worry about downloading the tool in that setup: https://scan.coverity.com/travis_ci

I think we should be able to enable it without trouble for the 'master' branch?

Cheers, Lars

Johannes Schindelin· May 2, 2017, 11:46 UTC · re: Lars Schneider · lore

Re: Automating Coverity, was Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Hi Lars,
On Mon, 1 May 2017, Lars Schneider wrote:
> Looks like Coverity has TravisCI integration and I assume you wouldn't
> need to worry about downloading the tool in that setup:
> https://scan.coverity.com/travis_ci

Except for that tiny little fact that Travis CI does not support Windows backends (nor would they even respond to my offer to work with them).

Ciao, Dscho

Johannes Schindelin· May 5, 2017, 20:30 UTC · re: Johannes Schindelin · lore

Re: Automating Coverity, was Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Hi Stefan,
On Fri, 28 Apr 2017, Johannes Schindelin wrote:
Show 21 quoted lines
> On Fri, 28 Apr 2017, Stefan Beller wrote:
> 
> > On Thu, Apr 27, 2017 at 3:50 PM, Johannes Schindelin
> > <Johannes.Schindelin@gmx.de> wrote:
> > 
> > > I still have to find the time to figure out one more detail: how to
> > > download and extract the Coverity tool (the .zip archive has a
> > > variable name for the top-level directory), and doing that only
> > > every once in a while, say, only when there is no previously
> > > unpacked tool, or it is already 4 weeks old.
> > 
> > That is an interesting problem, which I ignored as the older versions
> > of their tools still works once they release new versions. So I just
> > manually check every once in a while if they have new versions out
> > there.
> > 
> > So if you find a nice solution to that problem, let me know, please.
> 
> I think I have a working idea (jotting it down in the editor, untested):
> 
> [... totally untested snippet ...]

And now I edited it and tested it. The code is now part of the script I use for pretty much all administrative (i.e. recurring and boring) tasks in the Git for Windows project:

	https://github.com/git-for-windows/build-extra/commit/05b5342128

May it be useful to you, too, at least as a starting point, Dscho

Johannes Schindelin· May 10, 2017, 19:48 UTC · re: Johannes Schindelin · lore

Re: Automating Coverity, was Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Hi Stefan,
On Fri, 5 May 2017, Johannes Schindelin wrote:
Show 30 quoted lines
> On Fri, 28 Apr 2017, Johannes Schindelin wrote:
> 
> > On Fri, 28 Apr 2017, Stefan Beller wrote:
> > 
> > > On Thu, Apr 27, 2017 at 3:50 PM, Johannes Schindelin
> > > <Johannes.Schindelin@gmx.de> wrote:
> > > 
> > > > I still have to find the time to figure out one more detail: how
> > > > to download and extract the Coverity tool (the .zip archive has a
> > > > variable name for the top-level directory), and doing that only
> > > > every once in a while, say, only when there is no previously
> > > > unpacked tool, or it is already 4 weeks old.
> > > 
> > > That is an interesting problem, which I ignored as the older
> > > versions of their tools still works once they release new versions.
> > > So I just manually check every once in a while if they have new
> > > versions out there.
> > > 
> > > So if you find a nice solution to that problem, let me know, please.
> > 
> > I think I have a working idea (jotting it down in the editor,
> > untested):
> > 
> > [... totally untested snippet ...]
> 
> And now I edited it and tested it. The code is now part of the script I
> use for pretty much all administrative (i.e. recurring and boring) tasks
> in the Git for Windows project:
> 
> 	https://github.com/git-for-windows/build-extra/commit/05b5342128

Oh, I completely forgot to mention that I tried to set the FLEX_ARRAY constant to something quite large (I used 64k), but apparently that does not work as expected, Coverity still insists on complaining about strbufs.

On a second thought, it is actually quite obvious why it does not fix those reports: STRBUF_INIT has nothing to do with FLEX_ARRAY. D'oh.

My next attempt to work around these bogus claims was to modify the "model file" by adding a line saying "char strbuf_slopbuf[64];", but that was sadly not picked up by Coverity either.

My current thinking is that I will simply patch strbuf.c via `sed 's/^\(char struct_slopbuf\[\)1\[/&64[/'`.

Ciao, Dscho

Stefan Beller· May 10, 2017, 19:54 UTC · re: Johannes Schindelin · lore

Re: Automating Coverity, was Re: [PATCH 00/26] Address a couple of issues identified by Coverity

On Wed, May 10, 2017 at 12:48 PM, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:

Show 41 quoted lines
> Hi Stefan,
>
> On Fri, 5 May 2017, Johannes Schindelin wrote:
>
>> On Fri, 28 Apr 2017, Johannes Schindelin wrote:
>>
>> > On Fri, 28 Apr 2017, Stefan Beller wrote:
>> >
>> > > On Thu, Apr 27, 2017 at 3:50 PM, Johannes Schindelin
>> > > <Johannes.Schindelin@gmx.de> wrote:
>> > >
>> > > > I still have to find the time to figure out one more detail: how
>> > > > to download and extract the Coverity tool (the .zip archive has a
>> > > > variable name for the top-level directory), and doing that only
>> > > > every once in a while, say, only when there is no previously
>> > > > unpacked tool, or it is already 4 weeks old.
>> > >
>> > > That is an interesting problem, which I ignored as the older
>> > > versions of their tools still works once they release new versions.
>> > > So I just manually check every once in a while if they have new
>> > > versions out there.
>> > >
>> > > So if you find a nice solution to that problem, let me know, please.
>> >
>> > I think I have a working idea (jotting it down in the editor,
>> > untested):
>> >
>> > [... totally untested snippet ...]
>>
>> And now I edited it and tested it. The code is now part of the script I
>> use for pretty much all administrative (i.e. recurring and boring) tasks
>> in the Git for Windows project:
>>
>>       https://github.com/git-for-windows/build-extra/commit/05b5342128
>
> Oh, I completely forgot to mention that I tried to set the FLEX_ARRAY
> constant to something quite large (I used 64k), but apparently that does
> not work as expected, Coverity still insists on complaining about strbufs.
>
> On a second thought, it is actually quite obvious why it does not fix
> those reports: STRBUF_INIT has nothing to do with FLEX_ARRAY. D'oh.

D'oh. I must have been living in an alternate universe for quite some time as I seemed to have confused different things here.

Checkout this commit, https://github.com/stefanbeller/git/commit/977f81d6dec4461a1a12da2df6c5c919b41129b4 that is cherry-picked for the coverity build. That fixes it.

That is about the only patch I apply before sending it off to coverity. I am still contemplating a nice solution for FLEX_ARRAYs in other cases.

Thanks, Stefan

Johannes Schindelin· May 11, 2017, 11:33 UTC · re: Stefan Beller · lore

Re: Automating Coverity, was Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Hi Stefan,
On Wed, 10 May 2017, Stefan Beller wrote:
Show 49 quoted lines
> On Wed, May 10, 2017 at 12:48 PM, Johannes Schindelin
> <Johannes.Schindelin@gmx.de> wrote:
> >
> > On Fri, 5 May 2017, Johannes Schindelin wrote:
> >
> >> On Fri, 28 Apr 2017, Johannes Schindelin wrote:
> >>
> >> > On Fri, 28 Apr 2017, Stefan Beller wrote:
> >> >
> >> > > On Thu, Apr 27, 2017 at 3:50 PM, Johannes Schindelin
> >> > > <Johannes.Schindelin@gmx.de> wrote:
> >> > >
> >> > > > I still have to find the time to figure out one more detail: how
> >> > > > to download and extract the Coverity tool (the .zip archive has a
> >> > > > variable name for the top-level directory), and doing that only
> >> > > > every once in a while, say, only when there is no previously
> >> > > > unpacked tool, or it is already 4 weeks old.
> >> > >
> >> > > That is an interesting problem, which I ignored as the older
> >> > > versions of their tools still works once they release new versions.
> >> > > So I just manually check every once in a while if they have new
> >> > > versions out there.
> >> > >
> >> > > So if you find a nice solution to that problem, let me know, please.
> >> >
> >> > I think I have a working idea (jotting it down in the editor,
> >> > untested):
> >> >
> >> > [... totally untested snippet ...]
> >>
> >> And now I edited it and tested it. The code is now part of the script I
> >> use for pretty much all administrative (i.e. recurring and boring) tasks
> >> in the Git for Windows project:
> >>
> >>       https://github.com/git-for-windows/build-extra/commit/05b5342128
> >
> > Oh, I completely forgot to mention that I tried to set the FLEX_ARRAY
> > constant to something quite large (I used 64k), but apparently that does
> > not work as expected, Coverity still insists on complaining about strbufs.
> >
> > On a second thought, it is actually quite obvious why it does not fix
> > those reports: STRBUF_INIT has nothing to do with FLEX_ARRAY. D'oh.
> 
> D'oh. I must have been living in an alternate universe for quite some time
> as I seemed to have confused different things here.
> 
> Checkout this commit,
> https://github.com/stefanbeller/git/commit/977f81d6dec4461a1a12da2df6c5c919b41129b4
> that is cherry-picked for the coverity build. That fixes it.

I saw that patch, and since Junio did not pick it up, I figured that it won't make it into git.git's source code. That's why I went with the `sed` approach, as the #ifndef __COVERITY__ guard is not even necessary if I have to patch the code before running the Coverity tool anyway.

> That is about the only patch I apply before sending it off to coverity.
> I am still contemplating a nice solution for FLEX_ARRAYs in other cases.
For FLEX_ARRAYs, I use this:
	cov-build --dir cov-int \
                make -j15 DEVELOPER=1 CPPFLAGS=-DFLEX_ARRAY=65536

I have not had time to go over more than half a dozen CIDs, but I *think* it helps.

Ciao, Dscho

Johannes Sixt· Apr 27, 2017, 17:36 UTC · re: Johannes Schindelin · lore

Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Am 26.04.2017 um 22:19 schrieb Johannes Schindelin:
Show 5 quoted lines
> I recently registered the git-for-windows fork with Coverity to ensure
> that even the Windows-specific patches get some static analysis love.
>
> While at it, I squashed a couple of obvious issues in the part that is
> not Windows-specific.
Thanks for the fish. I'd looked at the series and had a few comments.

Hunting memory leaks is the way to insanity. Never again am I going to help with this. I prefer to rewrite this codebase to C++ and have leak-free code by design.

Thanks, -- Hannes

Johannes Schindelin· Apr 28, 2017, 11:36 UTC · re: Johannes Sixt · lore

Re: [PATCH 00/26] Address a couple of issues identified by Coverity

Hi Hannes,
On Thu, 27 Apr 2017, Johannes Sixt wrote:
Show 10 quoted lines
> Am 26.04.2017 um 22:19 schrieb Johannes Schindelin:
> > I recently registered the git-for-windows fork with Coverity to ensure
> > that even the Windows-specific patches get some static analysis love.
> >
> > While at it, I squashed a couple of obvious issues in the part that is
> > not Windows-specific.
> 
> Thanks for the fish. I'd looked at the series and had a few comments.
> 
> Hunting memory leaks is the way to insanity.
I hear you. Loud and clear.
> Never again am I going to help with this.
Awww? And here I thought I had your attention... *sniffle*
;-)
> I prefer to rewrite this codebase to C++ and have leak-free code by
> design.

I had the pleasure of working with some software developers in 2004 who were experts at introducing memory leaks into C++ code.

The same bunch of people later produced Java code that sorted a string list in cubic time (carefully avoiding java.util.Collections.sort(), of course).

For every fool-proof system invented, somebody invents a better fool.

Ciao, Dscho

Johannes Schindelin· Apr 28, 2017, 13:49 UTC · re: Johannes Schindelin · lore

[PATCH v2 00/25] Address a couple of issues identified by Coverity

I recently registered the git-for-windows fork with Coverity to ensure that even the Windows-specific patches get some static analysis love.

While at it, I squashed a couple of obvious issues in the part that is not Windows-specific.

Note: while this patch series squashes some of those issues, the
remaining issues are not necessarily all false positives (e.g. Coverity
getting fooled by our FLEX_ARRAY trick into believing that the last
member of the struct is indeed a 0 or 1 size array) or intentional (e.g.
builtins not releasing memory because exit() is called right after
returning from the function that leaks memory).
Notable examples of the remaining issues are:
- a couple of callers of shorten_unambiguous_ref() assume that they do
  not have to release the memory returned from that function, often
  assigning the pointer to a `const` variable that typically does not
  hold a pointer that needs to be free()d. My hunch is that we will want
  to convert that function to have a fixed number of static buffers and
  use those in a round robin fashion à la sha1_to_hex().
- pack-redundant.c seems to have hard-to-reason-about code paths that
  may eventually leak memory. Essentially, the custody of the allocated
  memory is not clear at all.
- fast-import.c calls strbuf_detach() on the command_buf without any
  obvious rationale. Turns out that *some* code paths assign
  command_buf.buf to a `recent_command` which releases the buffer later.
  However, from a cursory look it appears to me as if there are some
  other code paths that skip that assignment, effectively causing a memory
  leak once strbuf_detach() is called.
Sadly, I lack the time to pursue those remaining issues further.
Changes since v1:
- clarified in the commit messages for the setup_*git_dir() functions
  that we are not really plugging a memory leak, but marking singletons
  as `static` to help Coverity not to complain about this again
- dropped the patch to http-backend, as it is supposedly a one-shot
  program using exit() as "garbage collector".
- the difftool patch does a more thorough job of fixing leaks now
- reworded the commit subject of the mailinfo/mailsplit patch to sport
  a prefix indicating the overall area of the fix
- changed the mailinfo/mailsplit patch to *really* handle EOF correctly
- simplified the patch to get_mail_commit_oid(), and now it even returns
  the correct error value!
- adjusted the comment in builtin/checkout.c that talked about leaking
  the cache_entry (which is not leaked anymore)
- add forgotten free(buf) in fast-export.c in an early return
- line-log data is now released properly
- a couple more memory leaks in add_reflog_for_walk() have been found
  and addressed (this one *really* needs a couple more eyeballs, though,
  it is just a much bigger change than I originally anticipated)
Johannes Schindelin (25):
  mingw: avoid memory leak when splitting PATH
  winansi: avoid use of uninitialized value
  winansi: avoid buffer overrun
  add_commit_patch_id(): avoid allocating memory unnecessarily
  git_config_rename_section_in_file(): avoid resource leak
  get_mail_commit_oid(): avoid resource leak
  difftool: address a couple of resource/memory leaks
  status: close file descriptor after reading git-rebase-todo
  mailinfo & mailsplit: check for EOF while parsing
  cat-file: fix memory leak
  checkout: fix memory leak
  split_commit_in_progress(): fix memory leak
  setup_bare_git_dir(): help static analysis
  setup_discovered_git_dir(): help static analysis
  pack-redundant: plug memory leak
  mktree: plug memory leaks reported by Coverity
  fast-export: avoid leaking memory in handle_tag()
  receive-pack: plug memory leak in update()
  line-log: avoid memory leak
  shallow: avoid memory leak
  add_reflog_for_walk: avoid memory leak
  remote: plug memory leak in match_explicit()
  name-rev: avoid leaking memory in the `deref` case
  show_worktree(): plug memory leak
  submodule_uses_worktrees(): plug memory leak
 builtin/am.c             | 15 ++++++---------
 builtin/cat-file.c       |  1 +
 builtin/checkout.c       | 17 +++++++++--------
 builtin/difftool.c       | 33 +++++++++++++++++++++++----------
 builtin/fast-export.c    |  2 ++
 builtin/mailsplit.c      |  3 ++-
 builtin/mktree.c         |  5 +++--
 builtin/name-rev.c       |  7 +++++--
 builtin/pack-redundant.c |  1 +
 builtin/receive-pack.c   |  4 +++-
 builtin/worktree.c       |  8 +++++---
 compat/mingw.c           |  4 +++-
 compat/winansi.c         |  7 +++++++
 config.c                 |  5 ++++-
 line-log.c               |  1 +
 mailinfo.c               | 15 +++++++++++----
 patch-ids.c              |  3 ++-
 reflog-walk.c            | 20 +++++++++++++++++---
 remote.c                 |  5 +++--
 setup.c                  | 11 ++++++++---
 shallow.c                |  8 ++++++--
 worktree.c               |  2 +-
 wt-status.c              |  8 +++++++-
 23 files changed, 130 insertions(+), 55 deletions(-)
base-commit: 027a3b943b444a3e3a76f9a89803fc10245b858f
Published-As: https://github.com/dscho/git/releases/tag/coverity-v2
Fetch-It-Via: git fetch https://github.com/dscho/git coverity-v2
Interdiff vs v1:
 diff --git a/builtin/am.c b/builtin/am.c
 index 067dd4fc20d..9c5c2c778e2 100644
 --- a/builtin/am.c
 +++ b/builtin/am.c
 @@ -1353,18 +1353,14 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
  	const char *x;
  	int ret = 0;
  
 -	if (strbuf_getline_lf(&sb, fp))
 -		ret = -1;
 -
 -	if (!ret && !skip_prefix(sb.buf, "From ", &x))
 -		ret = -1;
 -
 -	if (!ret && get_oid_hex(x, commit_id) < 0)
 +	if (strbuf_getline_lf(&sb, fp) ||
 +	    !skip_prefix(sb.buf, "From ", &x) ||
 +	    get_oid_hex(x, commit_id) < 0)
  		ret = -1;
  
  	strbuf_release(&sb);
  	fclose(fp);
 -	return 0;
 +	return ret;
  }
  
  /**
 diff --git a/builtin/checkout.c b/builtin/checkout.c
 index 98f98256608..5faea3a05fa 100644
 --- a/builtin/checkout.c
 +++ b/builtin/checkout.c
 @@ -235,14 +235,14 @@ static int checkout_merged(int pos, const struct checkout *state)
  	/*
  	 * NEEDSWORK:
  	 * There is absolutely no reason to write this as a blob object
 -	 * and create a phony cache entry just to leak.  This hack is
 -	 * primarily to get to the write_entry() machinery that massages
 -	 * the contents to work-tree format and writes out which only
 -	 * allows it for a cache entry.  The code in write_entry() needs
 -	 * to be refactored to allow us to feed a <buffer, size, mode>
 -	 * instead of a cache entry.  Such a refactoring would help
 -	 * merge_recursive as well (it also writes the merge result to the
 -	 * object database even when it may contain conflicts).
 +	 * and create a phony cache entry.  This hack is primarily to get
 +	 * to the write_entry() machinery that massages the contents to
 +	 * work-tree format and writes out which only allows it for a
 +	 * cache entry.  The code in write_entry() needs to be refactored
 +	 * to allow us to feed a <buffer, size, mode> instead of a cache
 +	 * entry.  Such a refactoring would help merge_recursive as well
 +	 * (it also writes the merge result to the object database even
 +	 * when it may contain conflicts).
  	 */
  	if (write_sha1_file(result_buf.ptr, result_buf.size,
  			    blob_type, oid.hash))
 diff --git a/builtin/difftool.c b/builtin/difftool.c
 index a4f1d117ef6..b9a892f2693 100644
 --- a/builtin/difftool.c
 +++ b/builtin/difftool.c
 @@ -440,8 +440,10 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
  		}
  
  		if (lmode && status != 'C') {
 -			if (checkout_path(lmode, &loid, src_path, &lstate))
 -				return error("could not write '%s'", src_path);
 +			if (checkout_path(lmode, &loid, src_path, &lstate)) {
 +				ret = error("could not write '%s'", src_path);
 +				goto finish;
 +			}
  		}
  
  		if (rmode && !S_ISLNK(rmode)) {
 @@ -457,9 +459,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
  			hashmap_add(&working_tree_dups, entry);
  
  			if (!use_wt_file(workdir, dst_path, &roid)) {
 -				if (checkout_path(rmode, &roid, dst_path, &rstate))
 -					return error("could not write '%s'",
 -						     dst_path);
 +				if (checkout_path(rmode, &roid, dst_path,
 +						  &rstate)) {
 +					ret = error("could not write '%s'",
 +						    dst_path);
 +					goto finish;
 +				}
  			} else if (!is_null_oid(&roid)) {
  				/*
  				 * Changes in the working tree need special
 @@ -474,10 +479,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
  						ADD_CACHE_JUST_APPEND);
  
  				add_path(&rdir, rdir_len, dst_path);
 -				if (ensure_leading_directories(rdir.buf))
 -					return error("could not create "
 -						     "directory for '%s'",
 -						     dst_path);
 +				if (ensure_leading_directories(rdir.buf)) {
 +					ret = error("could not create "
 +						    "directory for '%s'",
 +						    dst_path);
 +					goto finish;
 +				}
  				add_path(&wtdir, wtdir_len, dst_path);
  				if (symlinks) {
  					if (symlink(wtdir.buf, rdir.buf)) {
 @@ -499,13 +506,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
  	}
  
  	fclose(fp);
 +	fp = NULL;
  	if (finish_command(&child)) {
  		ret = error("error occurred running diff --raw");
  		goto finish;
  	}
  
  	if (!i)
 -		return 0;
 +		goto finish;
  
  	/*
  	 * Changes to submodules require special treatment.This loop writes a
 @@ -628,6 +636,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
  		exit_cleanup(tmpdir, rc);
  
  finish:
 +	if (fp)
 +		fclose(fp);
 +
  	free(lbase_dir);
  	free(rbase_dir);
  	strbuf_release(&ldir);
 diff --git a/builtin/fast-export.c b/builtin/fast-export.c
 index 828d41c0c11..64617ad8e36 100644
 --- a/builtin/fast-export.c
 +++ b/builtin/fast-export.c
 @@ -734,6 +734,7 @@ static void handle_tag(const char *name, struct tag *tag)
  			     oid_to_hex(&tag->object.oid));
  		case DROP:
  			/* Ignore this tag altogether */
 +			free(buf);
  			return;
  		case REWRITE:
  			if (tagged->type != OBJ_COMMIT) {
 diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
 index c0d88f97512..9b3efc8e987 100644
 --- a/builtin/mailsplit.c
 +++ b/builtin/mailsplit.c
 @@ -232,8 +232,9 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
  
  	do {
  		peek = fgetc(f);
 -	} while (peek >= 0 && isspace(peek));
 -	ungetc(peek, f);
 +	} while (isspace(peek));
 +	if (peek != EOF)
 +		ungetc(peek, f);
  
  	if (strbuf_getwholeline(&buf, f, '\n')) {
  		/* empty stdin is OK */
 diff --git a/http-backend.c b/http-backend.c
 index d12572fda10..eef0a361f4f 100644
 --- a/http-backend.c
 +++ b/http-backend.c
 @@ -681,10 +681,8 @@ int cmd_main(int argc, const char **argv)
  		if (!regexec(&re, dir, 1, out, 0)) {
  			size_t n;
  
 -			if (strcmp(method, c->method)) {
 -				free(dir);
 +			if (strcmp(method, c->method))
  				return bad_request(&hdr, c);
 -			}
  
  			cmd = c;
  			n = out[0].rm_eo - out[0].rm_so;
 @@ -710,7 +708,5 @@ int cmd_main(int argc, const char **argv)
  					   max_request_buffer);
  
  	cmd->imp(&hdr, cmd_arg);
 -	free(dir);
 -	free(cmd_arg);
  	return 0;
  }
 diff --git a/line-log.c b/line-log.c
 index 19d46e9ea2c..b9087814b8c 100644
 --- a/line-log.c
 +++ b/line-log.c
 @@ -1125,7 +1125,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
  	changed = process_all_files(&parent_range, rev, &queue, range);
  	if (parent)
  		add_line_range(rev, parent, parent_range);
 -	free(parent_range);
 +	free_line_log_data(parent_range);
  	return changed;
  }
  
 diff --git a/mailinfo.c b/mailinfo.c
 index 60dcad7b714..a319911b510 100644
 --- a/mailinfo.c
 +++ b/mailinfo.c
 @@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE *in)
  	for (;;) {
  		int peek;
  
 -		peek = fgetc(in); ungetc(peek, in);
 +		peek = fgetc(in);
 +		if (peek == EOF)
 +			break;
 +		ungetc(peek, in);
  		if (peek != ' ' && peek != '\t')
  			break;
  		if (strbuf_getline_lf(&continuation, in))
 @@ -1094,14 +1097,18 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
  		return -1;
  	}
  
 -	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
 -	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
 -
  	do {
  		peek = fgetc(mi->input);
 -	} while (peek >= 0 && isspace(peek));
 +		if (peek == EOF) {
 +			fclose(cmitmsg);
 +			return error("empty patch: '%s'", patch);
 +		}
 +	} while (isspace(peek));
  	ungetc(peek, mi->input);
  
 +	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
 +	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
 +
  	/* process the email header */
  	while (read_one_header_line(&line, mi->input))
  		check_header(mi, &line, mi->p_hdr_data, 1);
 diff --git a/reflog-walk.c b/reflog-walk.c
 index ec66f2b16e6..c63eb1a3fd7 100644
 --- a/reflog-walk.c
 +++ b/reflog-walk.c
 @@ -197,17 +197,27 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
  				reflogs = read_complete_reflog(branch);
  			}
  		}
 -		if (!reflogs || reflogs->nr == 0)
 +		if (!reflogs || reflogs->nr == 0) {
 +			if (reflogs) {
 +				free(reflogs->ref);
 +				free(reflogs);
 +			}
 +			free(branch);
  			return -1;
 +		}
  		string_list_insert(&info->complete_reflogs, branch)->util
  			= reflogs;
  	}
 +	free(branch);
  
  	commit_reflog = xcalloc(1, sizeof(struct commit_reflog));
  	if (recno < 0) {
  		commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
  		if (commit_reflog->recno < 0) {
 -			free(branch);
 +			if (reflogs) {
 +				free(reflogs->ref);
 +				free(reflogs);
 +			}
  			free(commit_reflog);
  			return -1;
  		}
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 13:49 UTC · re: Johannes Schindelin · lore

[PATCH v2 01/25] mingw: avoid memory leak when splitting PATH

In the (admittedly, concocted) case that PATH consists only of colons, we would leak the duplicated string.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/mingw.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
Show changes to compat/mingw.c +3 −1
diff --git a/compat/mingw.c b/compat/mingw.c
index 3fbfda5978b..fe0e3ccd248 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -961,8 +961,10 @@ static char **get_path_split(void)
 			++n;
 		}
 	}
-	if (!n)
+	if (!n) {
+		free(envpath);
 		return NULL;
+	}
 
 	ALLOC_ARRAY(path, n + 1);
 	p = envpath;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 13:49 UTC · re: Johannes Schindelin · lore

[PATCH v2 02/25] winansi: avoid use of uninitialized value

When stdout is not connected to a Win32 console, we incorrectly used an uninitialized value for the "plain" character attributes.

Detected by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 2 ++
 1 file changed, 2 insertions(+)
Show changes to compat/winansi.c +2 −0
diff --git a/compat/winansi.c b/compat/winansi.c
index 793420f9d0d..fd6910746c8 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -105,6 +105,8 @@ static int is_console(int fd)
 	if (!fd) {
 		if (!GetConsoleMode(hcon, &mode))
 			return 0;
+		sbi.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
+			FOREGROUND_RED;
 	} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 13:49 UTC · re: Johannes Schindelin · lore

[PATCH v2 03/25] winansi: avoid buffer overrun

When we could not convert the UTF-8 sequence into Unicode for writing to the Console, we should not try to write an insanely-long sequence of invalid wide characters (mistaking the negative return value for an unsigned length).

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 5 +++++
 1 file changed, 5 insertions(+)
Show changes to compat/winansi.c +5 −0
diff --git a/compat/winansi.c b/compat/winansi.c
index fd6910746c8..861b79d8c31 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -135,6 +135,11 @@ static void write_console(unsigned char *str, size_t len)
 
 	/* convert utf-8 to utf-16 */
 	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
+	if (wlen < 0) {
+		wchar_t *err = L"[invalid]";
+		WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
+		return;
+	}
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, &dummy, NULL);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 13:50 UTC · re: Johannes Schindelin · lore

[PATCH v2 04/25] add_commit_patch_id(): avoid allocating memory unnecessarily

It would appear that we allocate (and forget to release) memory if the patch ID is not even defined.

Reported by the Coverity tool.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 patch-ids.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
Show changes to patch-ids.c +2 −1
diff --git a/patch-ids.c b/patch-ids.c
index fa8f11de826..92eba7a059e 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -99,11 +99,12 @@ struct patch_id *has_commit_patch_id(struct commit *commit,
 struct patch_id *add_commit_patch_id(struct commit *commit,
 				     struct patch_ids *ids)
 {
-	struct patch_id *key = xcalloc(1, sizeof(*key));
+	struct patch_id *key;
 
 	if (!patch_id_defined(commit))
 		return NULL;
 
+	key = xcalloc(1, sizeof(*key));
 	if (init_patch_id_entry(key, commit, ids)) {
 		free(key);
 		return NULL;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 13:50 UTC · re: Johannes Schindelin · lore

[PATCH v2 05/25] git_config_rename_section_in_file(): avoid resource leak

In case of errors, we really want the file descriptor to be closed.
Discovered by a Coverity scan.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 config.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
Show changes to config.c +4 −1
diff --git a/config.c b/config.c
index b4a3205da32..a30056ec7e9 100644
--- a/config.c
+++ b/config.c
@@ -2621,7 +2621,7 @@ int git_config_rename_section_in_file(const char *config_filename,
 	struct lock_file *lock;
 	int out_fd;
 	char buf[1024];
-	FILE *config_file;
+	FILE *config_file = NULL;
 	struct stat st;
 
 	if (new_name && !section_name_is_ok(new_name)) {
@@ -2703,11 +2703,14 @@ int git_config_rename_section_in_file(const char *config_filename,
 		}
 	}
 	fclose(config_file);
+	config_file = NULL;
 commit_and_out:
 	if (commit_lock_file(lock) < 0)
 		ret = error_errno("could not write config file %s",
 				  config_filename);
 out:
+	if (config_file)
+		fclose(config_file);
 	rollback_lock_file(lock);
 out_no_rollback:
 	free(filename_buf);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 13:50 UTC · re: Johannes Schindelin · lore

[PATCH v2 07/25] difftool: address a couple of resource/memory leaks

This change plugs a couple of memory leaks and makes sure that the file descriptor is closed in run_dir_diff().

Spotted by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/difftool.c | 33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)
Show changes to builtin/difftool.c +23 −10
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 1354d0e4625..b9a892f2693 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -226,6 +226,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
 		hashmap_entry_init(entry, strhash(buf.buf));
 		hashmap_add(result, entry);
 	}
+	fclose(fp);
 	if (finish_command(&diff_files))
 		die("diff-files did not exit properly");
 	strbuf_release(&index_env);
@@ -439,8 +440,10 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		}
 
 		if (lmode && status != 'C') {
-			if (checkout_path(lmode, &loid, src_path, &lstate))
-				return error("could not write '%s'", src_path);
+			if (checkout_path(lmode, &loid, src_path, &lstate)) {
+				ret = error("could not write '%s'", src_path);
+				goto finish;
+			}
 		}
 
 		if (rmode && !S_ISLNK(rmode)) {
@@ -456,9 +459,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 			hashmap_add(&working_tree_dups, entry);
 
 			if (!use_wt_file(workdir, dst_path, &roid)) {
-				if (checkout_path(rmode, &roid, dst_path, &rstate))
-					return error("could not write '%s'",
-						     dst_path);
+				if (checkout_path(rmode, &roid, dst_path,
+						  &rstate)) {
+					ret = error("could not write '%s'",
+						    dst_path);
+					goto finish;
+				}
 			} else if (!is_null_oid(&roid)) {
 				/*
 				 * Changes in the working tree need special
@@ -473,10 +479,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 						ADD_CACHE_JUST_APPEND);
 
 				add_path(&rdir, rdir_len, dst_path);
-				if (ensure_leading_directories(rdir.buf))
-					return error("could not create "
-						     "directory for '%s'",
-						     dst_path);
+				if (ensure_leading_directories(rdir.buf)) {
+					ret = error("could not create "
+						    "directory for '%s'",
+						    dst_path);
+					goto finish;
+				}
 				add_path(&wtdir, wtdir_len, dst_path);
 				if (symlinks) {
 					if (symlink(wtdir.buf, rdir.buf)) {
@@ -497,13 +505,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		}
 	}
 
+	fclose(fp);
+	fp = NULL;
 	if (finish_command(&child)) {
 		ret = error("error occurred running diff --raw");
 		goto finish;
 	}
 
 	if (!i)
-		return 0;
+		goto finish;
 
 	/*
 	 * Changes to submodules require special treatment.This loop writes a
@@ -626,6 +636,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		exit_cleanup(tmpdir, rc);
 
 finish:
+	if (fp)
+		fclose(fp);
+
 	free(lbase_dir);
 	free(rbase_dir);
 	strbuf_release(&ldir);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 13:50 UTC · re: Johannes Schindelin · lore

[PATCH v2 06/25] get_mail_commit_oid(): avoid resource leak

When we fail to read, or parse, the file, we still want to close the file descriptor and release the strbuf.

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/am.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)
Show changes to builtin/am.c +6 −9
diff --git a/builtin/am.c b/builtin/am.c
index a95dd8b4e6c..9c5c2c778e2 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1351,19 +1351,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
 	struct strbuf sb = STRBUF_INIT;
 	FILE *fp = xfopen(mail, "r");
 	const char *x;
+	int ret = 0;
 
-	if (strbuf_getline_lf(&sb, fp))
-		return -1;
-
-	if (!skip_prefix(sb.buf, "From ", &x))
-		return -1;
-
-	if (get_oid_hex(x, commit_id) < 0)
-		return -1;
+	if (strbuf_getline_lf(&sb, fp) ||
+	    !skip_prefix(sb.buf, "From ", &x) ||
+	    get_oid_hex(x, commit_id) < 0)
+		ret = -1;
 
 	strbuf_release(&sb);
 	fclose(fp);
-	return 0;
+	return ret;
 }
 
 /**
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 13:50 UTC · re: Johannes Schindelin · lore

[PATCH v2 08/25] status: close file descriptor after reading git-rebase-todo

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to wt-status.c +1 −0
diff --git a/wt-status.c b/wt-status.c
index 03754849626..0a6e16dbe0f 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1168,6 +1168,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines)
 		abbrev_sha1_in_line(&line);
 		string_list_append(lines, line.buf);
 	}
+	fclose(f);
 	return 0;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:02 UTC · re: Johannes Schindelin · lore

[PATCH v2 09/25] mailinfo & mailsplit: check for EOF while parsing

While POSIX states that it is okay to pass EOF to isspace() (and it seems to be implied that EOF should *not* be treated as whitespace), and also to pass EOF to ungetc() (which seems to be intended to fail without buffering the character), it is much better to handle these cases explicitly. Not only does it reduce head-scratching (and helps static analysis avoid reporting false positives), it also lets us handle files containing nothing but whitespace by erroring out.

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/mailsplit.c |  3 ++-
 mailinfo.c          | 15 +++++++++++----
 2 files changed, 13 insertions(+), 5 deletions(-)
Show changes to 2 files +13 −5

builtin/mailsplit.c, mailinfo.c

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30681681c13..9b3efc8e987 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -233,7 +233,8 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
 	do {
 		peek = fgetc(f);
 	} while (isspace(peek));
-	ungetc(peek, f);
+	if (peek != EOF)
+		ungetc(peek, f);
 
 	if (strbuf_getwholeline(&buf, f, '\n')) {
 		/* empty stdin is OK */
diff --git a/mailinfo.c b/mailinfo.c
index 68037758f2f..a319911b510 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE *in)
 	for (;;) {
 		int peek;
 
-		peek = fgetc(in); ungetc(peek, in);
+		peek = fgetc(in);
+		if (peek == EOF)
+			break;
+		ungetc(peek, in);
 		if (peek != ' ' && peek != '\t')
 			break;
 		if (strbuf_getline_lf(&continuation, in))
@@ -1094,14 +1097,18 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
 		return -1;
 	}
 
-	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
-	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
-
 	do {
 		peek = fgetc(mi->input);
+		if (peek == EOF) {
+			fclose(cmitmsg);
+			return error("empty patch: '%s'", patch);
+		}
 	} while (isspace(peek));
 	ungetc(peek, mi->input);
 
+	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
+	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
+
 	/* process the email header */
 	while (read_one_header_line(&line, mi->input))
 		check_header(mi, &line, mi->p_hdr_data, 1);
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· May 2, 2017, 04:11 UTC · re: Johannes Schindelin · lore

Re: [PATCH v2 09/25] mailinfo & mailsplit: check for EOF while parsing

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 27 quoted lines
> While POSIX states that it is okay to pass EOF to isspace() (and it seems
> to be implied that EOF should *not* be treated as whitespace), and also to
> pass EOF to ungetc() (which seems to be intended to fail without buffering
> the character), it is much better to handle these cases explicitly. Not
> only does it reduce head-scratching (and helps static analysis avoid
> reporting false positives), it also lets us handle files containing
> nothing but whitespace by erroring out.
>
> Reported via Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/mailsplit.c |  3 ++-
>  mailinfo.c          | 15 +++++++++++----
>  2 files changed, 13 insertions(+), 5 deletions(-)
>
> diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> index 30681681c13..9b3efc8e987 100644
> --- a/builtin/mailsplit.c
> +++ b/builtin/mailsplit.c
> @@ -233,7 +233,8 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
>  	do {
>  		peek = fgetc(f);
>  	} while (isspace(peek));
> -	ungetc(peek, f);
> +	if (peek != EOF)
> +		ungetc(peek, f);

I agree more with the first sentence in the proposed log message than what this code actually does. I.e. breaking upon seeing an EOF explicitly would be nice, just like the change to mailinfo.c in this patch we see below.

Show 15 quoted lines
> @@ -1094,14 +1097,18 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
>  		return -1;
>  	}
>  
> -	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
> -	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
> -
>  	do {
>  		peek = fgetc(mi->input);
> +		if (peek == EOF) {
> +			fclose(cmitmsg);
> +			return error("empty patch: '%s'", patch);
> +		}
>  	} while (isspace(peek));
>  	ungetc(peek, mi->input);

The handling of EOF is improved, but is it correct to move the allocation of p/s_hdr_data down?

Among the two callers, builtin/am.c just dies when it sees mailinfo() returns an error, but builtin/mailinfo.c tries to be nicer and calls clear_mailinfo(). Wouldn't this make that codepath dereference a NULL pointer?

I think the moral of the story is that people tend to get sloppier when doing "while we are at it" than the main task, and a reviewer needs to be more careful while reviewing the "while we are at it" part of the change than the primary thing a patch wants to do ;-)

Show 6 quoted lines
> +	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
> +	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
> +
>  	/* process the email header */
>  	while (read_one_header_line(&line, mi->input))
>  		check_header(mi, &line, mi->p_hdr_data, 1);
Johannes Schindelin· May 2, 2017, 13:57 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 09/25] mailinfo & mailsplit: check for EOF while parsing

Hi Junio,
On Mon, 1 May 2017, Junio C Hamano wrote:
Show 18 quoted lines
> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> 
> > diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
> > index 30681681c13..9b3efc8e987 100644
> > --- a/builtin/mailsplit.c
> > +++ b/builtin/mailsplit.c
> > @@ -233,7 +233,8 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
> >  	do {
> >  		peek = fgetc(f);
> >  	} while (isspace(peek));
> > -	ungetc(peek, f);
> > +	if (peek != EOF)
> > +		ungetc(peek, f);
> 
> I agree more with the first sentence in the proposed log message
> than what this code actually does.  I.e. breaking upon seeing an EOF
> explicitly would be nice, just like the change to mailinfo.c in this
> patch we see below.

I changed it to error out with a (translated) "empty mbox: '%s'" as the other hunks.

Show 18 quoted lines
> > @@ -1094,14 +1097,18 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
> >  		return -1;
> >  	}
> >  
> > -	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
> > -	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
> > -
> >  	do {
> >  		peek = fgetc(mi->input);
> > +		if (peek == EOF) {
> > +			fclose(cmitmsg);
> > +			return error("empty patch: '%s'", patch);
> > +		}
> >  	} while (isspace(peek));
> >  	ungetc(peek, mi->input);
> 
> The handling of EOF is improved, but is it correct to move the
> allocation of p/s_hdr_data down?

Sorry, I *assumed* that the function was passed a zero-initialized mailinfo struct. And as you pointed out, that assumption was wrong.

My thinking was that I did not want to introduce another leakage by my patch, but as your careful analysis determined: the only caller that does not die() afterwards releases the data (and would not even be able to handle p_hdr_data == NULL...).

I reverted that move.

Ciao, Dscho

Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 10/25] cat-file: fix memory leak

Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/cat-file.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/cat-file.c +1 −0
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 1890d7a6390..9af863e7915 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 		die("git cat-file %s: bad file", obj_name);
 
 	write_or_die(1, buf, size);
+	free(buf);
 	return 0;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 11/25] checkout: fix memory leak

This change addresses part of the NEEDSWORK comment above the code, therefore the comment needs to be adjusted, too.

Discovered via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/checkout.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
Show changes to builtin/checkout.c +9 −8
diff --git a/builtin/checkout.c b/builtin/checkout.c
index bfa5419f335..5faea3a05fa 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -235,14 +235,14 @@ static int checkout_merged(int pos, const struct checkout *state)
 	/*
 	 * NEEDSWORK:
 	 * There is absolutely no reason to write this as a blob object
-	 * and create a phony cache entry just to leak.  This hack is
-	 * primarily to get to the write_entry() machinery that massages
-	 * the contents to work-tree format and writes out which only
-	 * allows it for a cache entry.  The code in write_entry() needs
-	 * to be refactored to allow us to feed a <buffer, size, mode>
-	 * instead of a cache entry.  Such a refactoring would help
-	 * merge_recursive as well (it also writes the merge result to the
-	 * object database even when it may contain conflicts).
+	 * and create a phony cache entry.  This hack is primarily to get
+	 * to the write_entry() machinery that massages the contents to
+	 * work-tree format and writes out which only allows it for a
+	 * cache entry.  The code in write_entry() needs to be refactored
+	 * to allow us to feed a <buffer, size, mode> instead of a cache
+	 * entry.  Such a refactoring would help merge_recursive as well
+	 * (it also writes the merge result to the object database even
+	 * when it may contain conflicts).
 	 */
 	if (write_sha1_file(result_buf.ptr, result_buf.size,
 			    blob_type, oid.hash))
@@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
 	if (!ce)
 		die(_("make_cache_entry failed for path '%s'"), path);
 	status = checkout_entry(ce, state, NULL);
+	free(ce);
 	return status;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 12/25] split_commit_in_progress(): fix memory leak

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
Show changes to wt-status.c +6 −1
diff --git a/wt-status.c b/wt-status.c
index 0a6e16dbe0f..1f3f6bcb980 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1088,8 +1088,13 @@ static int split_commit_in_progress(struct wt_status *s)
 	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
 
 	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
-	    !s->branch || strcmp(s->branch, "HEAD"))
+	    !s->branch || strcmp(s->branch, "HEAD")) {
+		free(head);
+		free(orig_head);
+		free(rebase_amend);
+		free(rebase_orig_head);
 		return split_in_progress;
+	}
 
 	if (!strcmp(rebase_amend, rebase_orig_head)) {
 		if (strcmp(head, rebase_amend))
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 13/25] setup_bare_git_dir(): help static analysis

Coverity reported a memory leak in this function. However, it can only be called once, as setup_git_directory() changes global state and hence is not reentrant.

Mark the variable as static to indicate that this is a singleton.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 setup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to setup.c +1 −1
diff --git a/setup.c b/setup.c
index 0309c278218..0320a9ad14c 100644
--- a/setup.c
+++ b/setup.c
@@ -748,7 +748,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
 
 	/* --work-tree is set without --git-dir; use discovered one */
 	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
-		const char *gitdir;
+		static const char *gitdir;
 
 		gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
 		if (chdir(cwd->buf))
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 14/25] setup_discovered_git_dir(): help static analysis

Coverity reported a memory leak in this function. However, it can only be called once, as setup_git_directory() changes global state and hence is not reentrant.

Mark the variable as static to indicate that this is a singleton.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 setup.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
Show changes to setup.c +7 −2
diff --git a/setup.c b/setup.c
index 0320a9ad14c..12efca85a41 100644
--- a/setup.c
+++ b/setup.c
@@ -703,11 +703,16 @@ static const char *setup_discovered_git_dir(const char *gitdir,
 
 	/* --work-tree is set without --git-dir; use discovered one */
 	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+		char *p = NULL;
+		const char *ret;
+
 		if (offset != cwd->len && !is_absolute_path(gitdir))
-			gitdir = real_pathdup(gitdir, 1);
+			gitdir = p = real_pathdup(gitdir, 1);
 		if (chdir(cwd->buf))
 			die_errno("Could not come back to cwd");
-		return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+		ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+		free(p);
+		return ret;
 	}
 
 	/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· May 2, 2017, 03:57 UTC · re: Johannes Schindelin · lore

Re: [PATCH v2 14/25] setup_discovered_git_dir(): help static analysis

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
Show 8 quoted lines
> Coverity reported a memory leak in this function. However, it can only
> be called once, as setup_git_directory() changes global state and hence
> is not reentrant.
>
> Mark the variable as static to indicate that this is a singleton.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
Does something different from what is explained above.  Rebase gotcha?
Show 26 quoted lines
>  setup.c | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/setup.c b/setup.c
> index 0320a9ad14c..12efca85a41 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -703,11 +703,16 @@ static const char *setup_discovered_git_dir(const char *gitdir,
>  
>  	/* --work-tree is set without --git-dir; use discovered one */
>  	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
> +		char *p = NULL;
> +		const char *ret;
> +
>  		if (offset != cwd->len && !is_absolute_path(gitdir))
> -			gitdir = real_pathdup(gitdir, 1);
> +			gitdir = p = real_pathdup(gitdir, 1);
>  		if (chdir(cwd->buf))
>  			die_errno("Could not come back to cwd");
> -		return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
> +		ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
> +		free(p);
> +		return ret;
>  	}
>  
>  	/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
Johannes Schindelin· May 2, 2017, 12:38 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 14/25] setup_discovered_git_dir(): help static analysis

Hi Junio,
On Mon, 1 May 2017, Junio C Hamano wrote:
Show 12 quoted lines
> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> 
> > Coverity reported a memory leak in this function. However, it can only
> > be called once, as setup_git_directory() changes global state and hence
> > is not reentrant.
> >
> > Mark the variable as static to indicate that this is a singleton.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> 
> Does something different from what is explained above.  Rebase gotcha?
That, or just a brain fart.
Thanks, will send an updated iteration.

Ciao, Dscho

Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 15/25] pack-redundant: plug memory leak

Identified via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/pack-redundant.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/pack-redundant.c +1 −0
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 72c815844dd..cb1df1c7614 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -442,6 +442,7 @@ static void minimize(struct pack_list **min)
 	/* return if there are no objects missing from the unique set */
 	if (missing->size == 0) {
 		*min = unique;
+		free(missing);
 		return;
 	}
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 16/25] mktree: plug memory leaks reported by Coverity

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/mktree.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to builtin/mktree.c +3 −2
diff --git a/builtin/mktree.c b/builtin/mktree.c
index de9b40fc63b..f0354bc9718 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -72,7 +72,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 	unsigned mode;
 	enum object_type mode_type; /* object type derived from mode */
 	enum object_type obj_type; /* object type derived from sha */
-	char *path;
+	char *path, *p = NULL;
 	unsigned char sha1[20];
 
 	ptr = buf;
@@ -102,7 +102,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 		struct strbuf p_uq = STRBUF_INIT;
 		if (unquote_c_style(&p_uq, path, NULL))
 			die("invalid quoting");
-		path = strbuf_detach(&p_uq, NULL);
+		path = p = strbuf_detach(&p_uq, NULL);
 	}
 
 	/*
@@ -136,6 +136,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 	}
 
 	append_to_tree(mode, sha1, path);
+	free(p);
 }
 
 int cmd_mktree(int ac, const char **av, const char *prefix)
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 17/25] fast-export: avoid leaking memory in handle_tag()

Reported by, you guessed it, Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/fast-export.c | 2 ++
 1 file changed, 2 insertions(+)
Show changes to builtin/fast-export.c +2 −0
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index e0220630d00..64617ad8e36 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -734,6 +734,7 @@ static void handle_tag(const char *name, struct tag *tag)
 			     oid_to_hex(&tag->object.oid));
 		case DROP:
 			/* Ignore this tag altogether */
+			free(buf);
 			return;
 		case REWRITE:
 			if (tagged->type != OBJ_COMMIT) {
@@ -765,6 +766,7 @@ static void handle_tag(const char *name, struct tag *tag)
 	       (int)(tagger_end - tagger), tagger,
 	       tagger == tagger_end ? "" : "\n",
 	       (int)message_size, (int)message_size, message ? message : "");
+	free(buf);
 }
 
 static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:03 UTC · re: Johannes Schindelin · lore

[PATCH v2 18/25] receive-pack: plug memory leak in update()

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/receive-pack.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
Show changes to builtin/receive-pack.c +3 −1
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index f96834f42c9..48c07ddb659 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -986,7 +986,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 {
 	const char *name = cmd->ref_name;
 	struct strbuf namespaced_name_buf = STRBUF_INIT;
-	const char *namespaced_name, *ret;
+	static char *namespaced_name;
+	const char *ret;
 	struct object_id *old_oid = &cmd->old_oid;
 	struct object_id *new_oid = &cmd->new_oid;
 
@@ -997,6 +998,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 	}
 
 	strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+	free(namespaced_name);
 	namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
 
 	if (is_ref_checked_out(namespaced_name)) {
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:04 UTC · re: Johannes Schindelin · lore

[PATCH v2 19/25] line-log: avoid memory leak

Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 line-log.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to line-log.c +1 −0
diff --git a/line-log.c b/line-log.c
index a23b910471b..b9087814b8c 100644
--- a/line-log.c
+++ b/line-log.c
@@ -1125,6 +1125,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
 	changed = process_all_files(&parent_range, rev, &queue, range);
 	if (parent)
 		add_line_range(rev, parent, parent_range);
+	free_line_log_data(parent_range);
 	return changed;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:04 UTC · re: Johannes Schindelin · lore

[PATCH v2 20/25] shallow: avoid memory leak

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 shallow.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
Show changes to shallow.c +6 −2
diff --git a/shallow.c b/shallow.c
index 25b6db989bf..f9370961f99 100644
--- a/shallow.c
+++ b/shallow.c
@@ -473,11 +473,15 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,
 	struct commit_list *head = NULL;
 	int bitmap_nr = (info->nr_bits + 31) / 32;
 	size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr);
-	uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */
-	uint32_t *bitmap = paint_alloc(info);
 	struct commit *c = lookup_commit_reference_gently(sha1, 1);
+	uint32_t *tmp; /* to be freed before return */
+	uint32_t *bitmap;
+
 	if (!c)
 		return;
+
+	tmp = xmalloc(bitmap_size);
+	bitmap = paint_alloc(info);
 	memset(bitmap, 0, bitmap_size);
 	bitmap[id / 32] |= (1U << (id % 32));
 	commit_list_insert(c, &head);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:04 UTC · re: Johannes Schindelin · lore

[PATCH v2 22/25] remote: plug memory leak in match_explicit()

The `guess_ref()` returns an allocated buffer of which `make_linked_ref()` does not take custody (`alloc_ref()` makes a copy), therefore we need to release the buffer afterwards.

Noticed via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 remote.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to remote.c +3 −2
diff --git a/remote.c b/remote.c
index 801137c72eb..72b4591b983 100644
--- a/remote.c
+++ b/remote.c
@@ -1191,9 +1191,10 @@ static int match_explicit(struct ref *src, struct ref *dst,
 		else if (is_null_oid(&matched_src->new_oid))
 			error("unable to delete '%s': remote ref does not exist",
 			      dst_value);
-		else if ((dst_guess = guess_ref(dst_value, matched_src)))
+		else if ((dst_guess = guess_ref(dst_value, matched_src))) {
 			matched_dst = make_linked_ref(dst_guess, dst_tail);
-		else
+			free(dst_guess);
+		} else
 			error("unable to push to unqualified destination: %s\n"
 			      "The destination refspec neither matches an "
 			      "existing ref on the remote nor\n"
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· Apr 28, 2017, 14:04 UTC · re: Johannes Schindelin · lore

[PATCH v2 23/25] name-rev: avoid leaking memory in the `deref` case

When the `name_rev()` function is asked to dereference the tip name, it allocates memory. But when it turns out that another tip already described the commit better than the current one, we forgot to release the memory.

Pointed out by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/name-rev.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
Show changes to builtin/name-rev.c +5 −2
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 92a5d8a5d26..a4ce73fb1e9 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
 	struct rev_name *name = (struct rev_name *)commit->util;
 	struct commit_list *parents;
 	int parent_number = 1;
+	char *p = NULL;
 
 	parse_commit(commit);
 
@@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
 		return;
 
 	if (deref) {
-		tip_name = xstrfmt("%s^0", tip_name);
+		tip_name = p = xstrfmt("%s^0", tip_name);
 
 		if (generation)
 			die("generation: %d, but deref?", generation);
@@ -53,8 +54,10 @@ static void name_rev(struct commit *commit,
 		name->taggerdate = taggerdate;
 		name->generation = generation;
 		name->distance = distance;
-	} else
+	} else {
+		free(p);
 		return;
+	}
 
 	for (parents = commit->parents;
 			parents;
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· May 2, 2017, 03:26 UTC · re: Johannes Schindelin · lore

Re: [PATCH v2 23/25] name-rev: avoid leaking memory in the `deref` case

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> When the `name_rev()` function is asked to dereference the tip name, it
> allocates memory. But when it turns out that another tip already
> described the commit better than the current one, we forgot to release
> the memory.
Very well explained.
Show 41 quoted lines
>
> Pointed out by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/name-rev.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/name-rev.c b/builtin/name-rev.c
> index 92a5d8a5d26..a4ce73fb1e9 100644
> --- a/builtin/name-rev.c
> +++ b/builtin/name-rev.c
> @@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
>  	struct rev_name *name = (struct rev_name *)commit->util;
>  	struct commit_list *parents;
>  	int parent_number = 1;
> +	char *p = NULL;
>  
>  	parse_commit(commit);
>  
> @@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
>  		return;
>  
>  	if (deref) {
> -		tip_name = xstrfmt("%s^0", tip_name);
> +		tip_name = p = xstrfmt("%s^0", tip_name);
>  
>  		if (generation)
>  			die("generation: %d, but deref?", generation);
> @@ -53,8 +54,10 @@ static void name_rev(struct commit *commit,
>  		name->taggerdate = taggerdate;
>  		name->generation = generation;
>  		name->distance = distance;
> -	} else
> +	} else {
> +		free(p);
>  		return;
> +	}
>  
>  	for (parents = commit->parents;
>  			parents;
Junio C Hamano· May 2, 2017, 03:42 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 23/25] name-rev: avoid leaking memory in the `deref` case

Junio C Hamano <gitster@pobox.com> writes:
Show 27 quoted lines
> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
>
>> When the `name_rev()` function is asked to dereference the tip name, it
>> allocates memory. But when it turns out that another tip already
>> described the commit better than the current one, we forgot to release
>> the memory.
>
> Very well explained.
>>
>> diff --git a/builtin/name-rev.c b/builtin/name-rev.c
>> index 92a5d8a5d26..a4ce73fb1e9 100644
>> --- a/builtin/name-rev.c
>> +++ b/builtin/name-rev.c
>> @@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
>>  	struct rev_name *name = (struct rev_name *)commit->util;
>>  	struct commit_list *parents;
>>  	int parent_number = 1;
>> +	char *p = NULL;
>>  
>>  	parse_commit(commit);
>>  
>> @@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
>>  		return;
>>  
>>  	if (deref) {
>> -		tip_name = xstrfmt("%s^0", tip_name);
>> +		tip_name = p = xstrfmt("%s^0", tip_name);

I'll rename 'p' to 'to_free' while queuing, though. Without a descriptive name, it was confusing to view while resolving conflicts with another in-flight topic.

Johannes Schindelin· May 2, 2017, 14:00 UTC · re: Junio C Hamano · lore

Re: [PATCH v2 23/25] name-rev: avoid leaking memory in the `deref` case

Hi Junio,
On Mon, 1 May 2017, Junio C Hamano wrote:
Show 26 quoted lines
> Junio C Hamano <gitster@pobox.com> writes:
> 
> > Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> >
> >> diff --git a/builtin/name-rev.c b/builtin/name-rev.c
> >> index 92a5d8a5d26..a4ce73fb1e9 100644
> >> --- a/builtin/name-rev.c
> >> +++ b/builtin/name-rev.c
> >> @@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
> >>  	struct rev_name *name = (struct rev_name *)commit->util;
> >>  	struct commit_list *parents;
> >>  	int parent_number = 1;
> >> +	char *p = NULL;
> >>  
> >>  	parse_commit(commit);
> >>  
> >> @@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
> >>  		return;
> >>  
> >>  	if (deref) {
> >> -		tip_name = xstrfmt("%s^0", tip_name);
> >> +		tip_name = p = xstrfmt("%s^0", tip_name);
> 
> I'll rename 'p' to 'to_free' while queuing, though.  Without a
> descriptive name, it was confusing to view while resolving conflicts
> with another in-flight topic.

Good point. I also used `p` in builtin/mktree.c and setup.c. While you seem to have renamed it in builtin/mktree.c, I think setup.c also needs the same fixup.

Ciao, Dscho

Junio C Hamano· May 4, 2017, 04:22 UTC · re: Johannes Schindelin · lore

Re: [PATCH v2 23/25] name-rev: avoid leaking memory in the `deref` case

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 34 quoted lines
> Hi Junio,
>
> On Mon, 1 May 2017, Junio C Hamano wrote:
>
>> Junio C Hamano <gitster@pobox.com> writes:
>> 
>> > Johannes Schindelin <johannes.schindelin@gmx.de> writes:
>> >
>> >> diff --git a/builtin/name-rev.c b/builtin/name-rev.c
>> >> index 92a5d8a5d26..a4ce73fb1e9 100644
>> >> --- a/builtin/name-rev.c
>> >> +++ b/builtin/name-rev.c
>> >> @@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
>> >>  	struct rev_name *name = (struct rev_name *)commit->util;
>> >>  	struct commit_list *parents;
>> >>  	int parent_number = 1;
>> >> +	char *p = NULL;
>> >>  
>> >>  	parse_commit(commit);
>> >>  
>> >> @@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
>> >>  		return;
>> >>  
>> >>  	if (deref) {
>> >> -		tip_name = xstrfmt("%s^0", tip_name);
>> >> +		tip_name = p = xstrfmt("%s^0", tip_name);
>> 
>> I'll rename 'p' to 'to_free' while queuing, though.  Without a
>> descriptive name, it was confusing to view while resolving conflicts
>> with another in-flight topic.
>
> Good point. I also used `p` in builtin/mktree.c and setup.c. While you
> seem to have renamed it in builtin/mktree.c, I think setup.c also needs
> the same fixup.

Yes, no question about it. I just left it as-is as I saw it is likely to be rerolled anyway due to other issues ;-)

Johannes Schindelin· Apr 28, 2017, 14:04 UTC · re: Johannes Schindelin · lore

[PATCH v2 24/25] show_worktree(): plug memory leak

The buffer allocated by shorten_unambiguous_ref() needs to be released.
Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/worktree.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Show changes to builtin/worktree.c +5 −3
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 1722a9bdc2a..ff5dfd2b102 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -414,9 +414,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
 				find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
 		if (wt->is_detached)
 			strbuf_addstr(&sb, "(detached HEAD)");
-		else if (wt->head_ref)
-			strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
-		else
+		else if (wt->head_ref) {
+			char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
+			strbuf_addf(&sb, "[%s]", ref);
+			free(ref);
+		} else
 			strbuf_addstr(&sb, "(error)");
 	}
 	printf("%s\n", sb.buf);
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· May 2, 2017, 03:22 UTC · re: Johannes Schindelin · lore

Re: [PATCH v2 24/25] show_worktree(): plug memory leak

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> The buffer allocated by shorten_unambiguous_ref() needs to be released.
Yes.  Looks good.
Show 27 quoted lines
>
> Discovered by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  builtin/worktree.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/builtin/worktree.c b/builtin/worktree.c
> index 1722a9bdc2a..ff5dfd2b102 100644
> --- a/builtin/worktree.c
> +++ b/builtin/worktree.c
> @@ -414,9 +414,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
>  				find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
>  		if (wt->is_detached)
>  			strbuf_addstr(&sb, "(detached HEAD)");
> -		else if (wt->head_ref)
> -			strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
> -		else
> +		else if (wt->head_ref) {
> +			char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
> +			strbuf_addf(&sb, "[%s]", ref);
> +			free(ref);
> +		} else
>  			strbuf_addstr(&sb, "(error)");
>  	}
>  	printf("%s\n", sb.buf);
Johannes Schindelin· Apr 28, 2017, 14:04 UTC · re: Johannes Schindelin · lore

[PATCH v2 25/25] submodule_uses_worktrees(): plug memory leak

There is really no reason why we would need to hold onto the allocated string longer than necessary.

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 worktree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to worktree.c +1 −1
diff --git a/worktree.c b/worktree.c
index bae787cf8d7..89a81b13de3 100644
--- a/worktree.c
+++ b/worktree.c
@@ -399,6 +399,7 @@ int submodule_uses_worktrees(const char *path)
 
 	/* The env would be set for the superproject. */
 	get_common_dir_noenv(&sb, submodule_gitdir);
+	free(submodule_gitdir);
 
 	/*
 	 * The check below is only known to be good for repository format
@@ -418,7 +419,6 @@ int submodule_uses_worktrees(const char *path)
 	/* See if there is any file inside the worktrees directory. */
 	dir = opendir(sb.buf);
 	strbuf_release(&sb);
-	free(submodule_gitdir);
 
 	if (!dir)
 		return 0;
-- 
2.12.2.windows.2.800.gede8f145e06
Junio C Hamano· May 2, 2017, 03:17 UTC · re: Johannes Schindelin · lore

Re: [PATCH v2 25/25] submodule_uses_worktrees(): plug memory leak

Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> There is really no reason why we would need to hold onto the allocated
> string longer than necessary.

Yup. The longer we make the duration between the allocation and the standard release, the more likely future code would add early returns that forget to release the memory.

Looks correct; will queue.
Show 27 quoted lines
> Reported by Coverity.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  worktree.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/worktree.c b/worktree.c
> index bae787cf8d7..89a81b13de3 100644
> --- a/worktree.c
> +++ b/worktree.c
> @@ -399,6 +399,7 @@ int submodule_uses_worktrees(const char *path)
>  
>  	/* The env would be set for the superproject. */
>  	get_common_dir_noenv(&sb, submodule_gitdir);
> +	free(submodule_gitdir);
>  
>  	/*
>  	 * The check below is only known to be good for repository format
> @@ -418,7 +419,6 @@ int submodule_uses_worktrees(const char *path)
>  	/* See if there is any file inside the worktrees directory. */
>  	dir = opendir(sb.buf);
>  	strbuf_release(&sb);
> -	free(submodule_gitdir);
>  
>  	if (!dir)
>  		return 0;
Johannes Schindelin· Apr 28, 2017, 14:04 UTC · re: Johannes Schindelin · lore

[PATCH v2 21/25] add_reflog_for_walk: avoid memory leak

We free()d the `log` buffer when dwim_log() returned 1, but not when it returned a larger value (which meant that it still allocated the buffer but we simply ignored it).

While in the vicinity, make sure that the `reflogs` structure as well as the `branch` variable are released properly, too.

Identified by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 reflog-walk.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
Show changes to reflog-walk.c +17 −3
diff --git a/reflog-walk.c b/reflog-walk.c
index 99679f58255..c63eb1a3fd7 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -183,7 +183,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 		if (!reflogs || reflogs->nr == 0) {
 			struct object_id oid;
 			char *b;
-			if (dwim_log(branch, strlen(branch), oid.hash, &b) == 1) {
+			int ret = dwim_log(branch, strlen(branch),
+					   oid.hash, &b);
+			if (ret > 1)
+				free(b);
+			else if (ret == 1) {
 				if (reflogs) {
 					free(reflogs->ref);
 					free(reflogs);
@@ -193,17 +197,27 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 				reflogs = read_complete_reflog(branch);
 			}
 		}
-		if (!reflogs || reflogs->nr == 0)
+		if (!reflogs || reflogs->nr == 0) {
+			if (reflogs) {
+				free(reflogs->ref);
+				free(reflogs);
+			}
+			free(branch);
 			return -1;
+		}
 		string_list_insert(&info->complete_reflogs, branch)->util
 			= reflogs;
 	}
+	free(branch);
 
 	commit_reflog = xcalloc(1, sizeof(struct commit_reflog));
 	if (recno < 0) {
 		commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
 		if (commit_reflog->recno < 0) {
-			free(branch);
+			if (reflogs) {
+				free(reflogs->ref);
+				free(reflogs);
+			}
 			free(commit_reflog);
 			return -1;
 		}
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:00 UTC · re: Johannes Schindelin · lore

[PATCH v3 00/25] Address a couple of issues identified by Coverity

I recently registered the git-for-windows fork with Coverity to ensure that even the Windows-specific patches get some static analysis love.

While at it, I squashed a couple of obvious issues in the part that is not Windows-specific.

Note: while this patch series squashes some of those issues, the
remaining issues are not necessarily all false positives (e.g. Coverity
getting fooled by our FLEX_ARRAY trick into believing that the last
member of the struct is indeed a 0 or 1 size array) or intentional (e.g.
builtins not releasing memory because exit() is called right after
returning from the function that leaks memory).
Notable examples of the remaining issues are:
- a couple of callers of shorten_unambiguous_ref() assume that they do
  not have to release the memory returned from that function, often
  assigning the pointer to a `const` variable that typically does not
  hold a pointer that needs to be free()d. My hunch is that we will want
  to convert that function to have a fixed number of static buffers and
  use those in a round robin fashion à la sha1_to_hex().
- pack-redundant.c seems to have hard-to-reason-about code paths that
  may eventually leak memory. Essentially, the custody of the allocated
  memory is not clear at all.
- fast-import.c calls strbuf_detach() on the command_buf without any
  obvious rationale. Turns out that *some* code paths assign
  command_buf.buf to a `recent_command` which releases the buffer later.
  However, from a cursory look it appears to me as if there are some
  other code paths that skip that assignment, effectively causing a memory
  leak once strbuf_detach() is called.
Sadly, I lack the time to pursue those remaining issues further.
Changes since v2:
- renamed the `p` variables introduced by the patch series to the more
  explanatory `to_free`.
- reworded incorrect commit message claiming that
  setup_discovered_git_dir() was using a static variable that is
  actually a singleton
- reverted a code move that would have resulted in accessing
  uninitialized data of callers of mailinfo() that do not die() right
  away but clean up faithfully
Johannes Schindelin (25):
  mingw: avoid memory leak when splitting PATH
  winansi: avoid use of uninitialized value
  winansi: avoid buffer overrun
  add_commit_patch_id(): avoid allocating memory unnecessarily
  git_config_rename_section_in_file(): avoid resource leak
  get_mail_commit_oid(): avoid resource leak
  difftool: address a couple of resource/memory leaks
  status: close file descriptor after reading git-rebase-todo
  mailinfo & mailsplit: check for EOF while parsing
  cat-file: fix memory leak
  checkout: fix memory leak
  split_commit_in_progress(): fix memory leak
  setup_bare_git_dir(): help static analysis
  setup_discovered_git_dir(): plug memory leak
  pack-redundant: plug memory leak
  mktree: plug memory leaks reported by Coverity
  fast-export: avoid leaking memory in handle_tag()
  receive-pack: plug memory leak in update()
  line-log: avoid memory leak
  shallow: avoid memory leak
  add_reflog_for_walk: avoid memory leak
  remote: plug memory leak in match_explicit()
  name-rev: avoid leaking memory in the `deref` case
  show_worktree(): plug memory leak
  submodule_uses_worktrees(): plug memory leak
 builtin/am.c             | 15 ++++++---------
 builtin/cat-file.c       |  1 +
 builtin/checkout.c       | 17 +++++++++--------
 builtin/difftool.c       | 33 +++++++++++++++++++++++----------
 builtin/fast-export.c    |  2 ++
 builtin/mailsplit.c      | 10 ++++++++++
 builtin/mktree.c         |  5 +++--
 builtin/name-rev.c       |  7 +++++--
 builtin/pack-redundant.c |  1 +
 builtin/receive-pack.c   |  4 +++-
 builtin/worktree.c       |  8 +++++---
 compat/mingw.c           |  4 +++-
 compat/winansi.c         |  7 +++++++
 config.c                 |  5 ++++-
 line-log.c               |  1 +
 mailinfo.c               |  9 ++++++++-
 patch-ids.c              |  3 ++-
 reflog-walk.c            | 20 +++++++++++++++++---
 remote.c                 |  5 +++--
 setup.c                  | 11 ++++++++---
 shallow.c                |  8 ++++++--
 worktree.c               |  2 +-
 wt-status.c              |  8 +++++++-
 23 files changed, 135 insertions(+), 51 deletions(-)
base-commit: d2bbb7c2bcf6e77ebfcabf4e12110fe6d5c91de6
Published-As: https://github.com/dscho/git/releases/tag/coverity-v3
Fetch-It-Via: git fetch https://github.com/dscho/git coverity-v3
Interdiff vs v2:
 diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
 index 9b3efc8e987..664400b8169 100644
 --- a/builtin/mailsplit.c
 +++ b/builtin/mailsplit.c
 @@ -232,9 +232,18 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
  
  	do {
  		peek = fgetc(f);
 +		if (peek == EOF) {
 +			if (f == stdin)
 +				/* empty stdin is OK */
 +				ret = skip;
 +			else {
 +				fclose(f);
 +				error(_("empty mbox: '%s'"), file);
 +			}
 +			goto out;
 +		}
  	} while (isspace(peek));
 -	if (peek != EOF)
 -		ungetc(peek, f);
 +	ungetc(peek, f);
  
  	if (strbuf_getwholeline(&buf, f, '\n')) {
  		/* empty stdin is OK */
 diff --git a/builtin/mktree.c b/builtin/mktree.c
 index f0354bc9718..da0fd8cd706 100644
 --- a/builtin/mktree.c
 +++ b/builtin/mktree.c
 @@ -72,7 +72,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
  	unsigned mode;
  	enum object_type mode_type; /* object type derived from mode */
  	enum object_type obj_type; /* object type derived from sha */
 -	char *path, *p = NULL;
 +	char *path, *to_free = NULL;
  	unsigned char sha1[20];
  
  	ptr = buf;
 @@ -102,7 +102,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
  		struct strbuf p_uq = STRBUF_INIT;
  		if (unquote_c_style(&p_uq, path, NULL))
  			die("invalid quoting");
 -		path = p = strbuf_detach(&p_uq, NULL);
 +		path = to_free = strbuf_detach(&p_uq, NULL);
  	}
  
  	/*
 @@ -136,7 +136,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
  	}
  
  	append_to_tree(mode, sha1, path);
 -	free(p);
 +	free(to_free);
  }
  
  int cmd_mktree(int ac, const char **av, const char *prefix)
 diff --git a/builtin/name-rev.c b/builtin/name-rev.c
 index a4ce73fb1e9..e7a3fe7ee70 100644
 --- a/builtin/name-rev.c
 +++ b/builtin/name-rev.c
 @@ -28,7 +28,7 @@ static void name_rev(struct commit *commit,
  	struct rev_name *name = (struct rev_name *)commit->util;
  	struct commit_list *parents;
  	int parent_number = 1;
 -	char *p = NULL;
 +	char *to_free = NULL;
  
  	parse_commit(commit);
  
 @@ -36,7 +36,7 @@ static void name_rev(struct commit *commit,
  		return;
  
  	if (deref) {
 -		tip_name = p = xstrfmt("%s^0", tip_name);
 +		tip_name = to_free = xstrfmt("%s^0", tip_name);
  
  		if (generation)
  			die("generation: %d, but deref?", generation);
 @@ -55,7 +55,7 @@ static void name_rev(struct commit *commit,
  		name->generation = generation;
  		name->distance = distance;
  	} else {
 -		free(p);
 +		free(to_free);
  		return;
  	}
  
 diff --git a/mailinfo.c b/mailinfo.c
 index a319911b510..f92cb9f729c 100644
 --- a/mailinfo.c
 +++ b/mailinfo.c
 @@ -1097,6 +1097,9 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
  		return -1;
  	}
  
 +	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
 +	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
 +
  	do {
  		peek = fgetc(mi->input);
  		if (peek == EOF) {
 @@ -1106,9 +1109,6 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
  	} while (isspace(peek));
  	ungetc(peek, mi->input);
  
 -	mi->p_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->p_hdr_data)));
 -	mi->s_hdr_data = xcalloc(MAX_HDR_PARSED, sizeof(*(mi->s_hdr_data)));
 -
  	/* process the email header */
  	while (read_one_header_line(&line, mi->input))
  		check_header(mi, &line, mi->p_hdr_data, 1);
 diff --git a/setup.c b/setup.c
 index 12efca85a41..e3f7699a902 100644
 --- a/setup.c
 +++ b/setup.c
 @@ -703,15 +703,15 @@ static const char *setup_discovered_git_dir(const char *gitdir,
  
  	/* --work-tree is set without --git-dir; use discovered one */
  	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
 -		char *p = NULL;
 +		char *to_free = NULL;
  		const char *ret;
  
  		if (offset != cwd->len && !is_absolute_path(gitdir))
 -			gitdir = p = real_pathdup(gitdir, 1);
 +			gitdir = to_free = real_pathdup(gitdir, 1);
  		if (chdir(cwd->buf))
  			die_errno("Could not come back to cwd");
  		ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
 -		free(p);
 +		free(to_free);
  		return ret;
  	}
  
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:00 UTC · re: Johannes Schindelin · lore

[PATCH v3 01/25] mingw: avoid memory leak when splitting PATH

In the (admittedly, concocted) case that PATH consists only of colons, we would leak the duplicated string.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/mingw.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
Show changes to compat/mingw.c +3 −1
diff --git a/compat/mingw.c b/compat/mingw.c
index 3fbfda5978b..fe0e3ccd248 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -961,8 +961,10 @@ static char **get_path_split(void)
 			++n;
 		}
 	}
-	if (!n)
+	if (!n) {
+		free(envpath);
 		return NULL;
+	}
 
 	ALLOC_ARRAY(path, n + 1);
 	p = envpath;
-- 
2.12.2.windows.2.800.gede8f145e06
René Scharfe· May 3, 2017, 19:48 UTC · re: Johannes Schindelin · lore

Re: [PATCH v3 01/25] mingw: avoid memory leak when splitting PATH

Am 02.05.2017 um 18:00 schrieb Johannes Schindelin:
> In the (admittedly, concocted) case that PATH consists only of colons, we
> would leak the duplicated string.
Nit: It's about semicolons, right?  At least that's what get_path_split
is searching for.  Or is there some kind of translation going on?
René
Johannes Schindelin· May 4, 2017, 10:29 UTC · re: René Scharfe · lore

Re: [PATCH v3 01/25] mingw: avoid memory leak when splitting PATH

Hi René,
On Wed, 3 May 2017, René Scharfe wrote:
Show 6 quoted lines
> Am 02.05.2017 um 18:00 schrieb Johannes Schindelin:
> > In the (admittedly, concocted) case that PATH consists only of colons, we
> > would leak the duplicated string.
> 
> Nit: It's about semicolons, right?  At least that's what get_path_split
> is searching for.  Or is there some kind of translation going on?
True, it is semicolons.

I'll reword the commit message to actually use `path delimiters`, to make it more understandable to the Unix folk (who would most likely be puzzled that PATH is separated by semicolons).

Thanks, Dscho

Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 02/25] winansi: avoid use of uninitialized value

When stdout is not connected to a Win32 console, we incorrectly used an uninitialized value for the "plain" character attributes.

Detected by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 2 ++
 1 file changed, 2 insertions(+)
Show changes to compat/winansi.c +2 −0
diff --git a/compat/winansi.c b/compat/winansi.c
index 793420f9d0d..fd6910746c8 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -105,6 +105,8 @@ static int is_console(int fd)
 	if (!fd) {
 		if (!GetConsoleMode(hcon, &mode))
 			return 0;
+		sbi.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
+			FOREGROUND_RED;
 	} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
-- 
2.12.2.windows.2.800.gede8f145e06
René Scharfe· May 3, 2017, 19:48 UTC · re: Johannes Schindelin · lore

Re: [PATCH v3 02/25] winansi: avoid use of uninitialized value

Am 02.05.2017 um 18:01 schrieb Johannes Schindelin:
Show 23 quoted lines
> When stdout is not connected to a Win32 console, we incorrectly used an
> uninitialized value for the "plain" character attributes.
> 
> Detected by Coverity.
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>   compat/winansi.c | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/compat/winansi.c b/compat/winansi.c
> index 793420f9d0d..fd6910746c8 100644
> --- a/compat/winansi.c
> +++ b/compat/winansi.c
> @@ -105,6 +105,8 @@ static int is_console(int fd)
>   	if (!fd) {
>   		if (!GetConsoleMode(hcon, &mode))
>   			return 0;
> +		sbi.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
> +			FOREGROUND_RED;
>   	} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
>   		return 0;
>   

So is_console is called with fd being 1 (stdout), 2 (stderr) and 0 (stdin), in that order. If the first two calls abort early for some reason we may end up here. The added code is for white text on black background. An alias for that combination, FOREGROUND_ALL, is defined a few lines down; for a minimal fix it's not worth moving it up. attr and plain_attr are both initialized to sbi.wAttributes.

That as a bit more complicated than it looked initially. The order of calls is important, "stdout" in the commit message includes stderr as well and it doesn't just affect plain_attr.

Would a value of 0 (black text on black background) suffice if only stdin is connected to a console? Colors don't matter if there is nothing to see, right?

Anyway, the change makes sense as is, but it took me a while to get it.
René
Johannes Schindelin· May 4, 2017, 10:23 UTC · re: René Scharfe · lore

Re: [PATCH v3 02/25] winansi: avoid use of uninitialized value

Hi René,
On Wed, 3 May 2017, René Scharfe wrote:
Show 18 quoted lines
> Am 02.05.2017 um 18:01 schrieb Johannes Schindelin:
> > 
> > diff --git a/compat/winansi.c b/compat/winansi.c
> > index 793420f9d0d..fd6910746c8 100644
> > --- a/compat/winansi.c
> > +++ b/compat/winansi.c
> > @@ -105,6 +105,8 @@ static int is_console(int fd)
> >    if (!fd) {
> >     if (!GetConsoleMode(hcon, &mode))
> >   			return 0;
> > +		sbi.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
> > +			FOREGROUND_RED;
> >    } else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
> >     return 0;
> >   
> 
> So is_console is called with fd being 1 (stdout), 2 (stderr) and 0
> (stdin), in that order.

Correct. I guess this is the important part missing from the commit message.

Oh, I also saw that I talked about stdout in the commit message, but !fd tests for stdin!

> If the first two calls abort early for some reason we may end up here.

Yep. "some reason" being: there is no console attached to stdout nor stderr.

> The added code is for white text on black background.  An alias for that
> combination, FOREGROUND_ALL, is defined a few lines down; for a minimal
> fix it's not worth moving it up.  attr and plain_attr are both
> initialized to sbi.wAttributes.
Exactly.
> That as a bit more complicated than it looked initially.  The order of
> calls is important, "stdout" in the commit message includes stderr as
> well and it doesn't just affect plain_attr.
Right, it also affects the "current" attributes.
> Would a value of 0 (black text on black background) suffice if only
> stdin is connected to a console?  Colors don't matter if there is
> nothing to see, right?

I think that would make it both easier to understand the patch and to catch regressions in case anybody feels the order of the is_console() calls should be changed...

This is my current squash! commit (the original commit message will be replaced by the commit message body of this commit):

-- snipsnap --
Subject: [PATCH] squash! winansi: avoid use of uninitialized value
winansi: avoid use of uninitialized value

To initialize the foreground color attributes of "plain text", our ANSI emulation tries to infer them from the currently attached console while running the is_console() function. This function first tries to detect any console attached to stdout, then it is called with stderr.

If neither stdout nor stderr has any console attached, it does not actually matter what we use for "plain text" attributes, as we never need to output any text to any console in that case.

However, after working on stdout and stderr, is_console() is called with stdin, and it still tries to initialize the "plain text" attributes if they had not been initialized earlier. In this case, we cannot detect any attributes, and we used an uninitialized value for them.

Naturally, Coverity complained about this use case because it could not reason about the code deeply enough to figure out that we do not even use those attributes in that case.

Let's just initialize the value to 0 in that case, both to avoid future Coverity reports, and to help catch future regressions in case anybody changes the order of the is_console() calls (which would make the text black on black).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
Show changes to compat/winansi.c +7 −2
diff --git a/compat/winansi.c b/compat/winansi.c
index 861b79d8c31..a11a0f16d27 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -105,8 +105,13 @@ static int is_console(int fd)
 	if (!fd) {
 		if (!GetConsoleMode(hcon, &mode))
 			return 0;
-		sbi.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
-			FOREGROUND_RED;
+		/*
+		 * This code path is only reached if there is no console
+		 * attached to stdout/stderr, i.e. we will not need to output
+		 * any text to any console, therefore we might just as well
+		 * use black as foreground color.
+		 */
+		sbi.wAttributes = 0;
 	} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 03/25] winansi: avoid buffer overrun

When we could not convert the UTF-8 sequence into Unicode for writing to the Console, we should not try to write an insanely-long sequence of invalid wide characters (mistaking the negative return value for an unsigned length).

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 5 +++++
 1 file changed, 5 insertions(+)
Show changes to compat/winansi.c +5 −0
diff --git a/compat/winansi.c b/compat/winansi.c
index fd6910746c8..861b79d8c31 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -135,6 +135,11 @@ static void write_console(unsigned char *str, size_t len)
 
 	/* convert utf-8 to utf-16 */
 	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
+	if (wlen < 0) {
+		wchar_t *err = L"[invalid]";
+		WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
+		return;
+	}
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, &dummy, NULL);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 04/25] add_commit_patch_id(): avoid allocating memory unnecessarily

It would appear that we allocate (and forget to release) memory if the patch ID is not even defined.

Reported by the Coverity tool.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 patch-ids.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
Show changes to patch-ids.c +2 −1
diff --git a/patch-ids.c b/patch-ids.c
index fa8f11de826..92eba7a059e 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -99,11 +99,12 @@ struct patch_id *has_commit_patch_id(struct commit *commit,
 struct patch_id *add_commit_patch_id(struct commit *commit,
 				     struct patch_ids *ids)
 {
-	struct patch_id *key = xcalloc(1, sizeof(*key));
+	struct patch_id *key;
 
 	if (!patch_id_defined(commit))
 		return NULL;
 
+	key = xcalloc(1, sizeof(*key));
 	if (init_patch_id_entry(key, commit, ids)) {
 		free(key);
 		return NULL;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 06/25] get_mail_commit_oid(): avoid resource leak

When we fail to read, or parse, the file, we still want to close the file descriptor and release the strbuf.

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/am.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)
Show changes to builtin/am.c +6 −9
diff --git a/builtin/am.c b/builtin/am.c
index a95dd8b4e6c..9c5c2c778e2 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1351,19 +1351,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
 	struct strbuf sb = STRBUF_INIT;
 	FILE *fp = xfopen(mail, "r");
 	const char *x;
+	int ret = 0;
 
-	if (strbuf_getline_lf(&sb, fp))
-		return -1;
-
-	if (!skip_prefix(sb.buf, "From ", &x))
-		return -1;
-
-	if (get_oid_hex(x, commit_id) < 0)
-		return -1;
+	if (strbuf_getline_lf(&sb, fp) ||
+	    !skip_prefix(sb.buf, "From ", &x) ||
+	    get_oid_hex(x, commit_id) < 0)
+		ret = -1;
 
 	strbuf_release(&sb);
 	fclose(fp);
-	return 0;
+	return ret;
 }
 
 /**
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 07/25] difftool: address a couple of resource/memory leaks

This change plugs a couple of memory leaks and makes sure that the file descriptor is closed in run_dir_diff().

Spotted by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/difftool.c | 33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)
Show changes to builtin/difftool.c +23 −10
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 1354d0e4625..b9a892f2693 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -226,6 +226,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
 		hashmap_entry_init(entry, strhash(buf.buf));
 		hashmap_add(result, entry);
 	}
+	fclose(fp);
 	if (finish_command(&diff_files))
 		die("diff-files did not exit properly");
 	strbuf_release(&index_env);
@@ -439,8 +440,10 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		}
 
 		if (lmode && status != 'C') {
-			if (checkout_path(lmode, &loid, src_path, &lstate))
-				return error("could not write '%s'", src_path);
+			if (checkout_path(lmode, &loid, src_path, &lstate)) {
+				ret = error("could not write '%s'", src_path);
+				goto finish;
+			}
 		}
 
 		if (rmode && !S_ISLNK(rmode)) {
@@ -456,9 +459,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 			hashmap_add(&working_tree_dups, entry);
 
 			if (!use_wt_file(workdir, dst_path, &roid)) {
-				if (checkout_path(rmode, &roid, dst_path, &rstate))
-					return error("could not write '%s'",
-						     dst_path);
+				if (checkout_path(rmode, &roid, dst_path,
+						  &rstate)) {
+					ret = error("could not write '%s'",
+						    dst_path);
+					goto finish;
+				}
 			} else if (!is_null_oid(&roid)) {
 				/*
 				 * Changes in the working tree need special
@@ -473,10 +479,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 						ADD_CACHE_JUST_APPEND);
 
 				add_path(&rdir, rdir_len, dst_path);
-				if (ensure_leading_directories(rdir.buf))
-					return error("could not create "
-						     "directory for '%s'",
-						     dst_path);
+				if (ensure_leading_directories(rdir.buf)) {
+					ret = error("could not create "
+						    "directory for '%s'",
+						    dst_path);
+					goto finish;
+				}
 				add_path(&wtdir, wtdir_len, dst_path);
 				if (symlinks) {
 					if (symlink(wtdir.buf, rdir.buf)) {
@@ -497,13 +505,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		}
 	}
 
+	fclose(fp);
+	fp = NULL;
 	if (finish_command(&child)) {
 		ret = error("error occurred running diff --raw");
 		goto finish;
 	}
 
 	if (!i)
-		return 0;
+		goto finish;
 
 	/*
 	 * Changes to submodules require special treatment.This loop writes a
@@ -626,6 +636,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		exit_cleanup(tmpdir, rc);
 
 finish:
+	if (fp)
+		fclose(fp);
+
 	free(lbase_dir);
 	free(rbase_dir);
 	strbuf_release(&ldir);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 05/25] git_config_rename_section_in_file(): avoid resource leak

In case of errors, we really want the file descriptor to be closed.
Discovered by a Coverity scan.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 config.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
Show changes to config.c +4 −1
diff --git a/config.c b/config.c
index b4a3205da32..a30056ec7e9 100644
--- a/config.c
+++ b/config.c
@@ -2621,7 +2621,7 @@ int git_config_rename_section_in_file(const char *config_filename,
 	struct lock_file *lock;
 	int out_fd;
 	char buf[1024];
-	FILE *config_file;
+	FILE *config_file = NULL;
 	struct stat st;
 
 	if (new_name && !section_name_is_ok(new_name)) {
@@ -2703,11 +2703,14 @@ int git_config_rename_section_in_file(const char *config_filename,
 		}
 	}
 	fclose(config_file);
+	config_file = NULL;
 commit_and_out:
 	if (commit_lock_file(lock) < 0)
 		ret = error_errno("could not write config file %s",
 				  config_filename);
 out:
+	if (config_file)
+		fclose(config_file);
 	rollback_lock_file(lock);
 out_no_rollback:
 	free(filename_buf);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 08/25] status: close file descriptor after reading git-rebase-todo

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to wt-status.c +1 −0
diff --git a/wt-status.c b/wt-status.c
index 03754849626..0a6e16dbe0f 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1168,6 +1168,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines)
 		abbrev_sha1_in_line(&line);
 		string_list_append(lines, line.buf);
 	}
+	fclose(f);
 	return 0;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 09/25] mailinfo & mailsplit: check for EOF while parsing

While POSIX states that it is okay to pass EOF to isspace() (and it seems to be implied that EOF should *not* be treated as whitespace), and also to pass EOF to ungetc() (which seems to be intended to fail without buffering the character), it is much better to handle these cases explicitly. Not only does it reduce head-scratching (and helps static analysis avoid reporting false positives), it also lets us handle files containing nothing but whitespace by erroring out.

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/mailsplit.c | 10 ++++++++++
 mailinfo.c          |  9 ++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)
Show changes to 2 files +18 −1

builtin/mailsplit.c, mailinfo.c

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30681681c13..664400b8169 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -232,6 +232,16 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
 
 	do {
 		peek = fgetc(f);
+		if (peek == EOF) {
+			if (f == stdin)
+				/* empty stdin is OK */
+				ret = skip;
+			else {
+				fclose(f);
+				error(_("empty mbox: '%s'"), file);
+			}
+			goto out;
+		}
 	} while (isspace(peek));
 	ungetc(peek, f);
 
diff --git a/mailinfo.c b/mailinfo.c
index 68037758f2f..f92cb9f729c 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE *in)
 	for (;;) {
 		int peek;
 
-		peek = fgetc(in); ungetc(peek, in);
+		peek = fgetc(in);
+		if (peek == EOF)
+			break;
+		ungetc(peek, in);
 		if (peek != ' ' && peek != '\t')
 			break;
 		if (strbuf_getline_lf(&continuation, in))
@@ -1099,6 +1102,10 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
 
 	do {
 		peek = fgetc(mi->input);
+		if (peek == EOF) {
+			fclose(cmitmsg);
+			return error("empty patch: '%s'", patch);
+		}
 	} while (isspace(peek));
 	ungetc(peek, mi->input);
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:01 UTC · re: Johannes Schindelin · lore

[PATCH v3 10/25] cat-file: fix memory leak

Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/cat-file.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/cat-file.c +1 −0
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 1890d7a6390..9af863e7915 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 		die("git cat-file %s: bad file", obj_name);
 
 	write_or_die(1, buf, size);
+	free(buf);
 	return 0;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 12/25] split_commit_in_progress(): fix memory leak

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
Show changes to wt-status.c +6 −1
diff --git a/wt-status.c b/wt-status.c
index 0a6e16dbe0f..1f3f6bcb980 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1088,8 +1088,13 @@ static int split_commit_in_progress(struct wt_status *s)
 	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
 
 	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
-	    !s->branch || strcmp(s->branch, "HEAD"))
+	    !s->branch || strcmp(s->branch, "HEAD")) {
+		free(head);
+		free(orig_head);
+		free(rebase_amend);
+		free(rebase_orig_head);
 		return split_in_progress;
+	}
 
 	if (!strcmp(rebase_amend, rebase_orig_head)) {
 		if (strcmp(head, rebase_amend))
-- 
2.12.2.windows.2.800.gede8f145e06
René Scharfe· May 3, 2017, 20:59 UTC · re: Johannes Schindelin · lore

Re: [PATCH v3 12/25] split_commit_in_progress(): fix memory leak

Am 02.05.2017 um 18:02 schrieb Johannes Schindelin:
Show 27 quoted lines
> Reported via Coverity.
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>   wt-status.c | 7 ++++++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/wt-status.c b/wt-status.c
> index 0a6e16dbe0f..1f3f6bcb980 100644
> --- a/wt-status.c
> +++ b/wt-status.c
> @@ -1088,8 +1088,13 @@ static int split_commit_in_progress(struct wt_status *s)
>   	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
>   
>   	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
> -	    !s->branch || strcmp(s->branch, "HEAD"))
> +	    !s->branch || strcmp(s->branch, "HEAD")) {
> +		free(head);
> +		free(orig_head);
> +		free(rebase_amend);
> +		free(rebase_orig_head);
>   		return split_in_progress;
> +	}
>   
>   	if (!strcmp(rebase_amend, rebase_orig_head)) {
>   		if (strcmp(head, rebase_amend))
> 

The return line could be replaced by "; else" to achieve the same result, without duplicating the free calls.

René
Johannes Schindelin· May 4, 2017, 10:59 UTC · re: René Scharfe · lore

Re: [PATCH v3 12/25] split_commit_in_progress(): fix memory leak

Hi René,
On Wed, 3 May 2017, René Scharfe wrote:
Show 33 quoted lines
> Am 02.05.2017 um 18:02 schrieb Johannes Schindelin:
> > Reported via Coverity.
> > 
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> >   wt-status.c | 7 ++++++-
> >   1 file changed, 6 insertions(+), 1 deletion(-)
> > 
> > diff --git a/wt-status.c b/wt-status.c
> > index 0a6e16dbe0f..1f3f6bcb980 100644
> > --- a/wt-status.c
> > +++ b/wt-status.c
> > @@ -1088,8 +1088,13 @@ static int split_commit_in_progress(struct wt_status
> > *s)
> >    char *rebase_orig_head =
> >    read_line_from_git_path("rebase-merge/orig-head");
> >   
> >   	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
> > -	    !s->branch || strcmp(s->branch, "HEAD"))
> > +	    !s->branch || strcmp(s->branch, "HEAD")) {
> > +		free(head);
> > +		free(orig_head);
> > +		free(rebase_amend);
> > +		free(rebase_orig_head);
> >   		return split_in_progress;
> > +	}
> >   
> >    if (!strcmp(rebase_amend, rebase_orig_head)) {
> >     if (strcmp(head, rebase_amend))
> > 
> 
> The return line could be replaced by "; else" to achieve the same
> result, without duplicating the free calls.

True. It is much harder to explain it that way, though: the context looks like this:

static int split_commit_in_progress(struct wt_status *s)
 {
        int split_in_progress = 0;
        char *head = read_line_from_git_path("HEAD");
        char *orig_head = read_line_from_git_path("ORIG_HEAD");
        char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
        char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
        if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
-           !s->branch || strcmp(s->branch, "HEAD"))
+           !s->branch || strcmp(s->branch, "HEAD")) {
+               free(head);
+               free(orig_head);
+               free(rebase_amend);
+               free(rebase_orig_head);
                return split_in_progress;
+       }
        if (!strcmp(rebase_amend, rebase_orig_head)) {
                if (strcmp(head, rebase_amend))
                        split_in_progress = 1;
        } else if (strcmp(orig_head, rebase_orig_head)) {
                split_in_progress = 1;
        }
        if (!s->amend && !s->nowarn && !s->workdir_dirty)
                split_in_progress = 0;
        free(head);
        free(orig_head);
        free(rebase_amend);
        free(rebase_orig_head);
        return split_in_progress;
 }

So as you see, if we make the change you suggested, the next if() is hit which possibly sets split_in_progress = 0.

The thing is: this variable has been initialized to 0 in the beginning! So this conditional assignment would be a noop, unless any of the code paths before this conditional modified split_in_progress.

After you fully wrapped your head around this code, I am sure you agree that the code is unnecessarily confusing to begin with: why do we go out of our way to allocate and read all those strings, compare them to figure out whether there is a split in progress, just to look at bits in the wt_status struct (that we had available from the beginning) to potentially undo all of that.

What's worse, I cannot even find a logical explanation why the code is so confusing, as it has been added as it is today in commit 2d1ccebae41 (status: better advices when splitting a commit (during rebase -i), 2012-06-10).

So I think this function really wants to be fixed more fully (although I feel bad for inserting such a non-trivial fix into a patch series otherwise populated by trivial memory/resource leak plugs):

-- snipsnap --
Subject: [PATCH] squash! split_commit_in_progress(): fix memory leak
split_commit_in_progress(): simplify & fix memory leak

This function did a whole lot of unnecessary work, such as reading in four files just to figure out that, oh, hey, we do not need to look at them after all because the HEAD is not detached.

Simplify the entire function to return early when possible, to read in the files only when necessary, and to release the allocated memory always (there was a leak, reported via Coverity, where we failed to release the allocated strings if the HEAD is not detached).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 39 +++++++++++++++++----------------------
 1 file changed, 17 insertions(+), 22 deletions(-)
Show changes to wt-status.c +17 −22
diff --git a/wt-status.c b/wt-status.c
index 1f3f6bcb980..117ac8cfb01 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1082,34 +1082,29 @@ static char *read_line_from_git_path(const char *filename)
 static int split_commit_in_progress(struct wt_status *s)
 {
 	int split_in_progress = 0;
-	char *head = read_line_from_git_path("HEAD");
-	char *orig_head = read_line_from_git_path("ORIG_HEAD");
-	char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
-	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
-
-	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
-	    !s->branch || strcmp(s->branch, "HEAD")) {
-		free(head);
-		free(orig_head);
-		free(rebase_amend);
-		free(rebase_orig_head);
-		return split_in_progress;
-	}
-
-	if (!strcmp(rebase_amend, rebase_orig_head)) {
-		if (strcmp(head, rebase_amend))
-			split_in_progress = 1;
-	} else if (strcmp(orig_head, rebase_orig_head)) {
-		split_in_progress = 1;
-	}
+	char *head, *orig_head, *rebase_amend, *rebase_orig_head;
+
+	if ((!s->amend && !s->nowarn && !s->workdir_dirty) ||
+	    !s->branch || strcmp(s->branch, "HEAD"))
+		return 0;
 
-	if (!s->amend && !s->nowarn && !s->workdir_dirty)
-		split_in_progress = 0;
+	head = read_line_from_git_path("HEAD");
+	orig_head = read_line_from_git_path("ORIG_HEAD");
+	rebase_amend = read_line_from_git_path("rebase-merge/amend");
+	rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
+
+	if (!head || !orig_head || !rebase_amend || !rebase_orig_head)
+		; /* fall through, no split in progress */
+	else if (!strcmp(rebase_amend, rebase_orig_head))
+		split_in_progress = !!strcmp(head, rebase_amend);
+	else if (strcmp(orig_head, rebase_orig_head))
+		split_in_progress = 1;
 
 	free(head);
 	free(orig_head);
 	free(rebase_amend);
 	free(rebase_orig_head);
+
 	return split_in_progress;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
René Scharfe· May 6, 2017, 17:13 UTC · re: Johannes Schindelin · lore

Re: [PATCH v3 12/25] split_commit_in_progress(): fix memory leak

Am 04.05.2017 um 12:59 schrieb Johannes Schindelin:
Show 82 quoted lines
> Hi René,
> 
> On Wed, 3 May 2017, René Scharfe wrote:
> 
>> Am 02.05.2017 um 18:02 schrieb Johannes Schindelin:
>>> Reported via Coverity.
>>>
>>> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
>>> ---
>>>    wt-status.c | 7 ++++++-
>>>    1 file changed, 6 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/wt-status.c b/wt-status.c
>>> index 0a6e16dbe0f..1f3f6bcb980 100644
>>> --- a/wt-status.c
>>> +++ b/wt-status.c
>>> @@ -1088,8 +1088,13 @@ static int split_commit_in_progress(struct wt_status
>>> *s)
>>>     char *rebase_orig_head =
>>>     read_line_from_git_path("rebase-merge/orig-head");
>>>    
>>>    	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
>>> -	    !s->branch || strcmp(s->branch, "HEAD"))
>>> +	    !s->branch || strcmp(s->branch, "HEAD")) {
>>> +		free(head);
>>> +		free(orig_head);
>>> +		free(rebase_amend);
>>> +		free(rebase_orig_head);
>>>    		return split_in_progress;
>>> +	}
>>>    
>>>     if (!strcmp(rebase_amend, rebase_orig_head)) {
>>>      if (strcmp(head, rebase_amend))
>>>
>>
>> The return line could be replaced by "; else" to achieve the same
>> result, without duplicating the free calls.
> 
> True. It is much harder to explain it that way, though: the context looks
> like this:
> 
> static int split_commit_in_progress(struct wt_status *s)
>   {
>          int split_in_progress = 0;
>          char *head = read_line_from_git_path("HEAD");
>          char *orig_head = read_line_from_git_path("ORIG_HEAD");
>          char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
>          char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
> 
>          if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
> -           !s->branch || strcmp(s->branch, "HEAD"))
> +           !s->branch || strcmp(s->branch, "HEAD")) {
> +               free(head);
> +               free(orig_head);
> +               free(rebase_amend);
> +               free(rebase_orig_head);
>                  return split_in_progress;
> +       }
> 
>          if (!strcmp(rebase_amend, rebase_orig_head)) {
>                  if (strcmp(head, rebase_amend))
>                          split_in_progress = 1;
>          } else if (strcmp(orig_head, rebase_orig_head)) {
>                  split_in_progress = 1;
>          }
> 
>          if (!s->amend && !s->nowarn && !s->workdir_dirty)
>                  split_in_progress = 0;
> 
>          free(head);
>          free(orig_head);
>          free(rebase_amend);
>          free(rebase_orig_head);
>          return split_in_progress;
>   }
> 
> So as you see, if we make the change you suggested, the next if() is hit
> which possibly sets split_in_progress = 0.
> 
> The thing is: this variable has been initialized to 0 in the beginning! So
> this conditional assignment would be a noop, unless any of the code paths
> before this conditional modified split_in_progress.
Right. It could have been used as a quick two-line fix.
Show 6 quoted lines
> After you fully wrapped your head around this code, I am sure you agree
> that the code is unnecessarily confusing to begin with: why do we go out
> of our way to allocate and read all those strings, compare them to figure
> out whether there is a split in progress, just to look at bits in the
> wt_status struct (that we had available from the beginning) to potentially
> undo all of that.

The only function with a higher cyclomatic complexity in this file is wt_longstatus_print(), which spans more than 100 lines. Amazing.

> What's worse, I cannot even find a logical explanation why the code is so
> confusing, as it has been added as it is today in commit 2d1ccebae41
> (status: better advices when splitting a commit (during rebase -i),
> 2012-06-10).

Repeatedly I get the impression that defects or shortcomings tend to cluster. It pays to take a good look at the code surrounding a find of an automatic checker for other possible improvements.

> So I think this function really wants to be fixed more fully (although I
> feel bad for inserting such a non-trivial fix into a patch series
> otherwise populated by trivial memory/resource leak plugs):
It could be done in two steps.  Doing it in one is probably OK as well.
Show 59 quoted lines
> -- snipsnap --
> Subject: [PATCH] squash! split_commit_in_progress(): fix memory leak
> 
> split_commit_in_progress(): simplify & fix memory leak
> 
> This function did a whole lot of unnecessary work, such as reading in
> four files just to figure out that, oh, hey, we do not need to look at
> them after all because the HEAD is not detached.
> 
> Simplify the entire function to return early when possible, to read in
> the files only when necessary, and to release the allocated memory
> always (there was a leak, reported via Coverity, where we failed to
> release the allocated strings if the HEAD is not detached).
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>   wt-status.c | 39 +++++++++++++++++----------------------
>   1 file changed, 17 insertions(+), 22 deletions(-)
> 
> diff --git a/wt-status.c b/wt-status.c
> index 1f3f6bcb980..117ac8cfb01 100644
> --- a/wt-status.c
> +++ b/wt-status.c
> @@ -1082,34 +1082,29 @@ static char *read_line_from_git_path(const char *filename)
>   static int split_commit_in_progress(struct wt_status *s)
>   {
>   	int split_in_progress = 0;
> -	char *head = read_line_from_git_path("HEAD");
> -	char *orig_head = read_line_from_git_path("ORIG_HEAD");
> -	char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
> -	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
> -
> -	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
> -	    !s->branch || strcmp(s->branch, "HEAD")) {
> -		free(head);
> -		free(orig_head);
> -		free(rebase_amend);
> -		free(rebase_orig_head);
> -		return split_in_progress;
> -	}
> -
> -	if (!strcmp(rebase_amend, rebase_orig_head)) {
> -		if (strcmp(head, rebase_amend))
> -			split_in_progress = 1;
> -	} else if (strcmp(orig_head, rebase_orig_head)) {
> -		split_in_progress = 1;
> -	}
> +	char *head, *orig_head, *rebase_amend, *rebase_orig_head;
> +
> +	if ((!s->amend && !s->nowarn && !s->workdir_dirty) ||
> +	    !s->branch || strcmp(s->branch, "HEAD"))
> +		return 0;
>   
> -	if (!s->amend && !s->nowarn && !s->workdir_dirty)
> -		split_in_progress = 0;
> +	head = read_line_from_git_path("HEAD");
> +	orig_head = read_line_from_git_path("ORIG_HEAD");
> +	rebase_amend = read_line_from_git_path("rebase-merge/amend");
> +	rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");

Further improvement idea (for a later series): Use rebase_path_amend() and rebase_path_orig_head() somehow, to build each path only once.

Accessing the files HEAD and ORIG_HEAD directly seems odd.
The second part of the function should probably be moved to sequencer.c.
> +
> +	if (!head || !orig_head || !rebase_amend || !rebase_orig_head)
> +		; /* fall through, no split in progress */

You could set split_in_progress to zero here. Would save a comment without losing readability.

Show 10 quoted lines
> +	else if (!strcmp(rebase_amend, rebase_orig_head))
> +		split_in_progress = !!strcmp(head, rebase_amend);
> +	else if (strcmp(orig_head, rebase_orig_head))
> +		split_in_progress = 1;
>   
>   	free(head);
>   	free(orig_head);
>   	free(rebase_amend);
>   	free(rebase_orig_head);
> +

Isn't the patch big enough already without rearranging the else blocks and adding that blank line? :)

>   	return split_in_progress;
>   }
>   
> 
Johannes Schindelin· May 9, 2017, 13:39 UTC · re: René Scharfe · lore

Re: [PATCH v3 12/25] split_commit_in_progress(): fix memory leak

Hi René,
On Sat, 6 May 2017, René Scharfe wrote:
Show 49 quoted lines
> Am 04.05.2017 um 12:59 schrieb Johannes Schindelin:
>
> > diff --git a/wt-status.c b/wt-status.c
> > index 1f3f6bcb980..117ac8cfb01 100644
> > --- a/wt-status.c
> > +++ b/wt-status.c
> > @@ -1082,34 +1082,29 @@ static char *read_line_from_git_path(const char
> > *filename)
> >   static int split_commit_in_progress(struct wt_status *s)
> >   {
> >   	int split_in_progress = 0;
> > -	char *head = read_line_from_git_path("HEAD");
> > -	char *orig_head = read_line_from_git_path("ORIG_HEAD");
> > -	char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
> > -	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
> > -
> > -	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
> > -	    !s->branch || strcmp(s->branch, "HEAD")) {
> > -		free(head);
> > -		free(orig_head);
> > -		free(rebase_amend);
> > -		free(rebase_orig_head);
> > -		return split_in_progress;
> > -	}
> > -
> > -	if (!strcmp(rebase_amend, rebase_orig_head)) {
> > -		if (strcmp(head, rebase_amend))
> > -			split_in_progress = 1;
> > -	} else if (strcmp(orig_head, rebase_orig_head)) {
> > -		split_in_progress = 1;
> > -	}
> > +	char *head, *orig_head, *rebase_amend, *rebase_orig_head;
> > +
> > +	if ((!s->amend && !s->nowarn && !s->workdir_dirty) ||
> > +	    !s->branch || strcmp(s->branch, "HEAD"))
> > +		return 0;
> >   -	if (!s->amend && !s->nowarn && !s->workdir_dirty)
> > -		split_in_progress = 0;
> > +	head = read_line_from_git_path("HEAD");
> > +	orig_head = read_line_from_git_path("ORIG_HEAD");
> > +	rebase_amend = read_line_from_git_path("rebase-merge/amend");
> > +	rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
> 
> Further improvement idea (for a later series): Use rebase_path_amend()
> and rebase_path_orig_head() somehow, to build each path only once.
> 
> Accessing the files HEAD and ORIG_HEAD directly seems odd.
> 
> The second part of the function should probably be moved to sequencer.c.
Sure. On all four accounts.
Show 6 quoted lines
> > +
> > +	if (!head || !orig_head || !rebase_amend || !rebase_orig_head)
> > +		; /* fall through, no split in progress */
> 
> You could set split_in_progress to zero here.  Would save a comment
> without losing readability.

But that would confuse e.g. myself, 6 months down the road: why assign that variable when it already has been assigned? (And we have to assign it because there is still a code path entering none of these if/else if's arms).

Show 13 quoted lines
> > +	else if (!strcmp(rebase_amend, rebase_orig_head))
> > +		split_in_progress = !!strcmp(head, rebase_amend);
> > +	else if (strcmp(orig_head, rebase_orig_head))
> > +		split_in_progress = 1;
> >   
> >    free(head);
> >    free(orig_head);
> >    free(rebase_amend);
> >    free(rebase_orig_head);
> > +
> 
> Isn't the patch big enough already without rearranging the else blocks
> and adding that blank line? :)

The else blocks are not really rearranged; apart from the early return, the rest of the logic has been painstakingly kept in the same order.

Ciao, Dscho

Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 11/25] checkout: fix memory leak

This change addresses part of the NEEDSWORK comment above the code, therefore the comment needs to be adjusted, too.

Discovered via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/checkout.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
Show changes to builtin/checkout.c +9 −8
diff --git a/builtin/checkout.c b/builtin/checkout.c
index bfa5419f335..5faea3a05fa 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -235,14 +235,14 @@ static int checkout_merged(int pos, const struct checkout *state)
 	/*
 	 * NEEDSWORK:
 	 * There is absolutely no reason to write this as a blob object
-	 * and create a phony cache entry just to leak.  This hack is
-	 * primarily to get to the write_entry() machinery that massages
-	 * the contents to work-tree format and writes out which only
-	 * allows it for a cache entry.  The code in write_entry() needs
-	 * to be refactored to allow us to feed a <buffer, size, mode>
-	 * instead of a cache entry.  Such a refactoring would help
-	 * merge_recursive as well (it also writes the merge result to the
-	 * object database even when it may contain conflicts).
+	 * and create a phony cache entry.  This hack is primarily to get
+	 * to the write_entry() machinery that massages the contents to
+	 * work-tree format and writes out which only allows it for a
+	 * cache entry.  The code in write_entry() needs to be refactored
+	 * to allow us to feed a <buffer, size, mode> instead of a cache
+	 * entry.  Such a refactoring would help merge_recursive as well
+	 * (it also writes the merge result to the object database even
+	 * when it may contain conflicts).
 	 */
 	if (write_sha1_file(result_buf.ptr, result_buf.size,
 			    blob_type, oid.hash))
@@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
 	if (!ce)
 		die(_("make_cache_entry failed for path '%s'"), path);
 	status = checkout_entry(ce, state, NULL);
+	free(ce);
 	return status;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 16/25] mktree: plug memory leaks reported by Coverity

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/mktree.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to builtin/mktree.c +3 −2
diff --git a/builtin/mktree.c b/builtin/mktree.c
index de9b40fc63b..da0fd8cd706 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -72,7 +72,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 	unsigned mode;
 	enum object_type mode_type; /* object type derived from mode */
 	enum object_type obj_type; /* object type derived from sha */
-	char *path;
+	char *path, *to_free = NULL;
 	unsigned char sha1[20];
 
 	ptr = buf;
@@ -102,7 +102,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 		struct strbuf p_uq = STRBUF_INIT;
 		if (unquote_c_style(&p_uq, path, NULL))
 			die("invalid quoting");
-		path = strbuf_detach(&p_uq, NULL);
+		path = to_free = strbuf_detach(&p_uq, NULL);
 	}
 
 	/*
@@ -136,6 +136,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 	}
 
 	append_to_tree(mode, sha1, path);
+	free(to_free);
 }
 
 int cmd_mktree(int ac, const char **av, const char *prefix)
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 13/25] setup_bare_git_dir(): help static analysis

Coverity reported a memory leak in this function. However, it can only be called once, as setup_git_directory() changes global state and hence is not reentrant.

Mark the variable as static to indicate that this is a singleton.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 setup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to setup.c +1 −1
diff --git a/setup.c b/setup.c
index 0309c278218..0320a9ad14c 100644
--- a/setup.c
+++ b/setup.c
@@ -748,7 +748,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
 
 	/* --work-tree is set without --git-dir; use discovered one */
 	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
-		const char *gitdir;
+		static const char *gitdir;
 
 		gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
 		if (chdir(cwd->buf))
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 15/25] pack-redundant: plug memory leak

Identified via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/pack-redundant.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/pack-redundant.c +1 −0
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 72c815844dd..cb1df1c7614 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -442,6 +442,7 @@ static void minimize(struct pack_list **min)
 	/* return if there are no objects missing from the unique set */
 	if (missing->size == 0) {
 		*min = unique;
+		free(missing);
 		return;
 	}
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 17/25] fast-export: avoid leaking memory in handle_tag()

Reported by, you guessed it, Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/fast-export.c | 2 ++
 1 file changed, 2 insertions(+)
Show changes to builtin/fast-export.c +2 −0
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index e0220630d00..64617ad8e36 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -734,6 +734,7 @@ static void handle_tag(const char *name, struct tag *tag)
 			     oid_to_hex(&tag->object.oid));
 		case DROP:
 			/* Ignore this tag altogether */
+			free(buf);
 			return;
 		case REWRITE:
 			if (tagged->type != OBJ_COMMIT) {
@@ -765,6 +766,7 @@ static void handle_tag(const char *name, struct tag *tag)
 	       (int)(tagger_end - tagger), tagger,
 	       tagger == tagger_end ? "" : "\n",
 	       (int)message_size, (int)message_size, message ? message : "");
+	free(buf);
 }
 
 static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 14/25] setup_discovered_git_dir(): plug memory leak

The setup_explicit_git_dir() function does not take custody of the string passed as first parameter; we have to release it if we turned the value of git_dir into an absolute path.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 setup.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
Show changes to setup.c +7 −2
diff --git a/setup.c b/setup.c
index 0320a9ad14c..e3f7699a902 100644
--- a/setup.c
+++ b/setup.c
@@ -703,11 +703,16 @@ static const char *setup_discovered_git_dir(const char *gitdir,
 
 	/* --work-tree is set without --git-dir; use discovered one */
 	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+		char *to_free = NULL;
+		const char *ret;
+
 		if (offset != cwd->len && !is_absolute_path(gitdir))
-			gitdir = real_pathdup(gitdir, 1);
+			gitdir = to_free = real_pathdup(gitdir, 1);
 		if (chdir(cwd->buf))
 			die_errno("Could not come back to cwd");
-		return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+		ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+		free(to_free);
+		return ret;
 	}
 
 	/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
-- 
2.12.2.windows.2.800.gede8f145e06
Stefan Beller· May 2, 2017, 17:20 UTC · re: Johannes Schindelin · lore

Re: [PATCH v3 14/25] setup_discovered_git_dir(): plug memory leak

On Tue, May 2, 2017 at 9:02 AM, Johannes Schindelin <johannes.schindelin@gmx.de> wrote:

Show 25 quoted lines
> The setup_explicit_git_dir() function does not take custody of the string
> passed as first parameter; we have to release it if we turned the value of
> git_dir into an absolute path.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>  setup.c | 9 +++++++--
>  1 file changed, 7 insertions(+), 2 deletions(-)
>
> diff --git a/setup.c b/setup.c
> index 0320a9ad14c..e3f7699a902 100644
> --- a/setup.c
> +++ b/setup.c
> @@ -703,11 +703,16 @@ static const char *setup_discovered_git_dir(const char *gitdir,
>
>         /* --work-tree is set without --git-dir; use discovered one */
>         if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
> +               char *to_free = NULL;
> +               const char *ret;
> +
>                 if (offset != cwd->len && !is_absolute_path(gitdir))
> -                       gitdir = real_pathdup(gitdir, 1);
> +                       gitdir = to_free = real_pathdup(gitdir, 1);
>                 if (chdir(cwd->buf))
>                         die_errno("Could not come back to cwd");

As the original motivation was to shut up Coverity, this may not accomplish that goal, as in the path of taking the die_errno, we do not free `to_free`. But that is ok as the actual goal is to hav no memleaks in the good case. A memleak just before a die is no big deal.

> -               return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
> +               ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
> +               free(to_free);
> +               return ret;
And we free our pathdup from above, makes sense.

Thanks, Stefan

Jeff King· May 2, 2017, 18:15 UTC · re: Stefan Beller · lore

Re: [PATCH v3 14/25] setup_discovered_git_dir(): plug memory leak

On Tue, May 02, 2017 at 10:20:29AM -0700, Stefan Beller wrote:
Show 9 quoted lines
> > -                       gitdir = real_pathdup(gitdir, 1);
> > +                       gitdir = to_free = real_pathdup(gitdir, 1);
> >                 if (chdir(cwd->buf))
> >                         die_errno("Could not come back to cwd");
> 
> As the original motivation was to shut up Coverity, this may not
> accomplish that goal, as in the path of taking the die_errno, we do not
> free `to_free`. But that is ok as the actual goal is to hav no memleaks
> in the good case. A memleak just before a die is no big deal.

I think Coverity understands our NORETURN attributes, so this should be fine (and if it doesn't, then we should fix that in the model file; but from the general results I've seen, it does).

-Peff
Johannes Schindelin· May 3, 2017, 09:35 UTC · re: Jeff King · lore

Re: [PATCH v3 14/25] setup_discovered_git_dir(): plug memory leak

Hi Peff,
On Tue, 2 May 2017, Jeff King wrote:
Show 15 quoted lines
> On Tue, May 02, 2017 at 10:20:29AM -0700, Stefan Beller wrote:
> 
> > > -                       gitdir = real_pathdup(gitdir, 1);
> > > +                       gitdir = to_free = real_pathdup(gitdir, 1);
> > >                 if (chdir(cwd->buf))
> > >                         die_errno("Could not come back to cwd");
> > 
> > As the original motivation was to shut up Coverity, this may not
> > accomplish that goal, as in the path of taking the die_errno, we do not
> > free `to_free`. But that is ok as the actual goal is to hav no memleaks
> > in the good case. A memleak just before a die is no big deal.
> 
> I think Coverity understands our NORETURN attributes, so this should be
> fine (and if it doesn't, then we should fix that in the model file; but
> from the general results I've seen, it does).
That matches my impression.

Note that Coverity cannot figure out that all of our cmd_*() functions are called in code paths that exit() with their return value. Otherwise we would not see reports about those tons of intentional "let's abuse exit() as our garbage collector" instances.

Ciao, Dscho

Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 18/25] receive-pack: plug memory leak in update()

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/receive-pack.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
Show changes to builtin/receive-pack.c +3 −1
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index f96834f42c9..48c07ddb659 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -986,7 +986,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 {
 	const char *name = cmd->ref_name;
 	struct strbuf namespaced_name_buf = STRBUF_INIT;
-	const char *namespaced_name, *ret;
+	static char *namespaced_name;
+	const char *ret;
 	struct object_id *old_oid = &cmd->old_oid;
 	struct object_id *new_oid = &cmd->new_oid;
 
@@ -997,6 +998,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 	}
 
 	strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+	free(namespaced_name);
 	namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
 
 	if (is_ref_checked_out(namespaced_name)) {
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 21/25] add_reflog_for_walk: avoid memory leak

We free()d the `log` buffer when dwim_log() returned 1, but not when it returned a larger value (which meant that it still allocated the buffer but we simply ignored it).

While in the vicinity, make sure that the `reflogs` structure as well as the `branch` variable are released properly, too.

Identified by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 reflog-walk.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
Show changes to reflog-walk.c +17 −3
diff --git a/reflog-walk.c b/reflog-walk.c
index 99679f58255..c63eb1a3fd7 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -183,7 +183,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 		if (!reflogs || reflogs->nr == 0) {
 			struct object_id oid;
 			char *b;
-			if (dwim_log(branch, strlen(branch), oid.hash, &b) == 1) {
+			int ret = dwim_log(branch, strlen(branch),
+					   oid.hash, &b);
+			if (ret > 1)
+				free(b);
+			else if (ret == 1) {
 				if (reflogs) {
 					free(reflogs->ref);
 					free(reflogs);
@@ -193,17 +197,27 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 				reflogs = read_complete_reflog(branch);
 			}
 		}
-		if (!reflogs || reflogs->nr == 0)
+		if (!reflogs || reflogs->nr == 0) {
+			if (reflogs) {
+				free(reflogs->ref);
+				free(reflogs);
+			}
+			free(branch);
 			return -1;
+		}
 		string_list_insert(&info->complete_reflogs, branch)->util
 			= reflogs;
 	}
+	free(branch);
 
 	commit_reflog = xcalloc(1, sizeof(struct commit_reflog));
 	if (recno < 0) {
 		commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
 		if (commit_reflog->recno < 0) {
-			free(branch);
+			if (reflogs) {
+				free(reflogs->ref);
+				free(reflogs);
+			}
 			free(commit_reflog);
 			return -1;
 		}
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 22/25] remote: plug memory leak in match_explicit()

The `guess_ref()` returns an allocated buffer of which `make_linked_ref()` does not take custody (`alloc_ref()` makes a copy), therefore we need to release the buffer afterwards.

Noticed via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 remote.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to remote.c +3 −2
diff --git a/remote.c b/remote.c
index 801137c72eb..72b4591b983 100644
--- a/remote.c
+++ b/remote.c
@@ -1191,9 +1191,10 @@ static int match_explicit(struct ref *src, struct ref *dst,
 		else if (is_null_oid(&matched_src->new_oid))
 			error("unable to delete '%s': remote ref does not exist",
 			      dst_value);
-		else if ((dst_guess = guess_ref(dst_value, matched_src)))
+		else if ((dst_guess = guess_ref(dst_value, matched_src))) {
 			matched_dst = make_linked_ref(dst_guess, dst_tail);
-		else
+			free(dst_guess);
+		} else
 			error("unable to push to unqualified destination: %s\n"
 			      "The destination refspec neither matches an "
 			      "existing ref on the remote nor\n"
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 20/25] shallow: avoid memory leak

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 shallow.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
Show changes to shallow.c +6 −2
diff --git a/shallow.c b/shallow.c
index 25b6db989bf..f9370961f99 100644
--- a/shallow.c
+++ b/shallow.c
@@ -473,11 +473,15 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,
 	struct commit_list *head = NULL;
 	int bitmap_nr = (info->nr_bits + 31) / 32;
 	size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr);
-	uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */
-	uint32_t *bitmap = paint_alloc(info);
 	struct commit *c = lookup_commit_reference_gently(sha1, 1);
+	uint32_t *tmp; /* to be freed before return */
+	uint32_t *bitmap;
+
 	if (!c)
 		return;
+
+	tmp = xmalloc(bitmap_size);
+	bitmap = paint_alloc(info);
 	memset(bitmap, 0, bitmap_size);
 	bitmap[id / 32] |= (1U << (id % 32));
 	commit_list_insert(c, &head);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 19/25] line-log: avoid memory leak

Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 line-log.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to line-log.c +1 −0
diff --git a/line-log.c b/line-log.c
index a23b910471b..b9087814b8c 100644
--- a/line-log.c
+++ b/line-log.c
@@ -1125,6 +1125,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
 	changed = process_all_files(&parent_range, rev, &queue, range);
 	if (parent)
 		add_line_range(rev, parent, parent_range);
+	free_line_log_data(parent_range);
 	return changed;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:03 UTC · re: Johannes Schindelin · lore

[PATCH v3 24/25] show_worktree(): plug memory leak

The buffer allocated by shorten_unambiguous_ref() needs to be released.
Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/worktree.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Show changes to builtin/worktree.c +5 −3
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 1722a9bdc2a..ff5dfd2b102 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -414,9 +414,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
 				find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
 		if (wt->is_detached)
 			strbuf_addstr(&sb, "(detached HEAD)");
-		else if (wt->head_ref)
-			strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
-		else
+		else if (wt->head_ref) {
+			char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
+			strbuf_addf(&sb, "[%s]", ref);
+			free(ref);
+		} else
 			strbuf_addstr(&sb, "(error)");
 	}
 	printf("%s\n", sb.buf);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:03 UTC · re: Johannes Schindelin · lore

[PATCH v3 25/25] submodule_uses_worktrees(): plug memory leak

There is really no reason why we would need to hold onto the allocated string longer than necessary.

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 worktree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to worktree.c +1 −1
diff --git a/worktree.c b/worktree.c
index bae787cf8d7..89a81b13de3 100644
--- a/worktree.c
+++ b/worktree.c
@@ -399,6 +399,7 @@ int submodule_uses_worktrees(const char *path)
 
 	/* The env would be set for the superproject. */
 	get_common_dir_noenv(&sb, submodule_gitdir);
+	free(submodule_gitdir);
 
 	/*
 	 * The check below is only known to be good for repository format
@@ -418,7 +419,6 @@ int submodule_uses_worktrees(const char *path)
 	/* See if there is any file inside the worktrees directory. */
 	dir = opendir(sb.buf);
 	strbuf_release(&sb);
-	free(submodule_gitdir);
 
 	if (!dir)
 		return 0;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 2, 2017, 16:02 UTC · re: Johannes Schindelin · lore

[PATCH v3 23/25] name-rev: avoid leaking memory in the `deref` case

When the `name_rev()` function is asked to dereference the tip name, it allocates memory. But when it turns out that another tip already described the commit better than the current one, we forgot to release the memory.

Pointed out by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/name-rev.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
Show changes to builtin/name-rev.c +5 −2
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 92a5d8a5d26..e7a3fe7ee70 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
 	struct rev_name *name = (struct rev_name *)commit->util;
 	struct commit_list *parents;
 	int parent_number = 1;
+	char *to_free = NULL;
 
 	parse_commit(commit);
 
@@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
 		return;
 
 	if (deref) {
-		tip_name = xstrfmt("%s^0", tip_name);
+		tip_name = to_free = xstrfmt("%s^0", tip_name);
 
 		if (generation)
 			die("generation: %d, but deref?", generation);
@@ -53,8 +54,10 @@ static void name_rev(struct commit *commit,
 		name->taggerdate = taggerdate;
 		name->generation = generation;
 		name->distance = distance;
-	} else
+	} else {
+		free(to_free);
 		return;
+	}
 
 	for (parents = commit->parents;
 			parents;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:54 UTC · re: Johannes Schindelin · lore

[PATCH v4 00/25] Address a couple of issues identified by Coverity

I recently registered the git-for-windows fork with Coverity to ensure that even the Windows-specific patches get some static analysis love.

While at it, I squashed a couple of obvious issues in the part that is not Windows-specific.

Note: while this patch series squashes some of those issues, the
remaining issues are not necessarily all false positives (e.g. Coverity
getting fooled by our FLEX_ARRAY trick into believing that the last
member of the struct is indeed a 0 or 1 size array) or intentional (e.g.
builtins not releasing memory because exit() is called right after
returning from the function that leaks memory).
Notable examples of the remaining issues are:
- a couple of callers of shorten_unambiguous_ref() assume that they do
  not have to release the memory returned from that function, often
  assigning the pointer to a `const` variable that typically does not
  hold a pointer that needs to be free()d. My hunch is that we will want
  to convert that function to have a fixed number of static buffers and
  use those in a round robin fashion à la sha1_to_hex().
- pack-redundant.c seems to have hard-to-reason-about code paths that
  may eventually leak memory. Essentially, the custody of the allocated
  memory is not clear at all.
- fast-import.c calls strbuf_detach() on the command_buf without any
  obvious rationale. Turns out that *some* code paths assign
  command_buf.buf to a `recent_command` which releases the buffer later.
  However, from a cursory look it appears to me as if there are some
  other code paths that skip that assignment, effectively causing a memory
  leak once strbuf_detach() is called.
Sadly, I lack the time to pursue those remaining issues further.
Changes since v3:
- used 0 (black) for the foreground color attributes in winansi when we
  have no console to print to, anyway.
- clarified in the commit message when we hit the path, and why, where
  we set the foreground color attributes to "all black".
- reworded the commit message talking about splitting the PATH (on
  Windows, it is delimited by semicolons, not colons, but it is even
  better to just talk about the path delimiters because it does not
  really happen which character is used, but it is important which role
  it plays).
- rewrote the split_commit_in_progress() function to have a more natural
  flow while still fixing the memory leak.
Johannes Schindelin (25):
  mingw: avoid memory leak when splitting PATH
  winansi: avoid use of uninitialized value
  winansi: avoid buffer overrun
  add_commit_patch_id(): avoid allocating memory unnecessarily
  git_config_rename_section_in_file(): avoid resource leak
  get_mail_commit_oid(): avoid resource leak
  difftool: address a couple of resource/memory leaks
  status: close file descriptor after reading git-rebase-todo
  mailinfo & mailsplit: check for EOF while parsing
  cat-file: fix memory leak
  checkout: fix memory leak
  split_commit_in_progress(): simplify & fix memory leak
  setup_bare_git_dir(): help static analysis
  setup_discovered_git_dir(): plug memory leak
  pack-redundant: plug memory leak
  mktree: plug memory leaks reported by Coverity
  fast-export: avoid leaking memory in handle_tag()
  receive-pack: plug memory leak in update()
  line-log: avoid memory leak
  shallow: avoid memory leak
  add_reflog_for_walk: avoid memory leak
  remote: plug memory leak in match_explicit()
  name-rev: avoid leaking memory in the `deref` case
  show_worktree(): plug memory leak
  submodule_uses_worktrees(): plug memory leak
 builtin/am.c             | 15 ++++++---------
 builtin/cat-file.c       |  1 +
 builtin/checkout.c       | 17 +++++++++--------
 builtin/difftool.c       | 33 +++++++++++++++++++++++----------
 builtin/fast-export.c    |  2 ++
 builtin/mailsplit.c      | 10 ++++++++++
 builtin/mktree.c         |  5 +++--
 builtin/name-rev.c       |  7 +++++--
 builtin/pack-redundant.c |  1 +
 builtin/receive-pack.c   |  4 +++-
 builtin/worktree.c       |  8 +++++---
 compat/mingw.c           |  4 +++-
 compat/winansi.c         | 12 ++++++++++++
 config.c                 |  5 ++++-
 line-log.c               |  1 +
 mailinfo.c               |  9 ++++++++-
 patch-ids.c              |  3 ++-
 reflog-walk.c            | 20 +++++++++++++++++---
 remote.c                 |  5 +++--
 setup.c                  | 11 ++++++++---
 shallow.c                |  8 ++++++--
 worktree.c               |  2 +-
 wt-status.c              | 29 +++++++++++++++--------------
 23 files changed, 148 insertions(+), 64 deletions(-)
base-commit: d2bbb7c2bcf6e77ebfcabf4e12110fe6d5c91de6
Published-As: https://github.com/dscho/git/releases/tag/coverity-v4
Fetch-It-Via: git fetch https://github.com/dscho/git coverity-v4
Interdiff vs v3:
 diff --git a/compat/winansi.c b/compat/winansi.c
 index 861b79d8c31..a11a0f16d27 100644
 --- a/compat/winansi.c
 +++ b/compat/winansi.c
 @@ -105,8 +105,13 @@ static int is_console(int fd)
  	if (!fd) {
  		if (!GetConsoleMode(hcon, &mode))
  			return 0;
 -		sbi.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
 -			FOREGROUND_RED;
 +		/*
 +		 * This code path is only reached if there is no console
 +		 * attached to stdout/stderr, i.e. we will not need to output
 +		 * any text to any console, therefore we might just as well
 +		 * use black as foreground color.
 +		 */
 +		sbi.wAttributes = 0;
  	} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
  		return 0;
  
 diff --git a/wt-status.c b/wt-status.c
 index 1f3f6bcb980..117ac8cfb01 100644
 --- a/wt-status.c
 +++ b/wt-status.c
 @@ -1082,34 +1082,29 @@ static char *read_line_from_git_path(const char *filename)
  static int split_commit_in_progress(struct wt_status *s)
  {
  	int split_in_progress = 0;
 -	char *head = read_line_from_git_path("HEAD");
 -	char *orig_head = read_line_from_git_path("ORIG_HEAD");
 -	char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
 -	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
 -
 -	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
 -	    !s->branch || strcmp(s->branch, "HEAD")) {
 -		free(head);
 -		free(orig_head);
 -		free(rebase_amend);
 -		free(rebase_orig_head);
 -		return split_in_progress;
 -	}
 -
 -	if (!strcmp(rebase_amend, rebase_orig_head)) {
 -		if (strcmp(head, rebase_amend))
 -			split_in_progress = 1;
 -	} else if (strcmp(orig_head, rebase_orig_head)) {
 -		split_in_progress = 1;
 -	}
 +	char *head, *orig_head, *rebase_amend, *rebase_orig_head;
 +
 +	if ((!s->amend && !s->nowarn && !s->workdir_dirty) ||
 +	    !s->branch || strcmp(s->branch, "HEAD"))
 +		return 0;
  
 -	if (!s->amend && !s->nowarn && !s->workdir_dirty)
 -		split_in_progress = 0;
 +	head = read_line_from_git_path("HEAD");
 +	orig_head = read_line_from_git_path("ORIG_HEAD");
 +	rebase_amend = read_line_from_git_path("rebase-merge/amend");
 +	rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
 +
 +	if (!head || !orig_head || !rebase_amend || !rebase_orig_head)
 +		; /* fall through, no split in progress */
 +	else if (!strcmp(rebase_amend, rebase_orig_head))
 +		split_in_progress = !!strcmp(head, rebase_amend);
 +	else if (strcmp(orig_head, rebase_orig_head))
 +		split_in_progress = 1;
  
  	free(head);
  	free(orig_head);
  	free(rebase_amend);
  	free(rebase_orig_head);
 +
  	return split_in_progress;
  }
  
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:55 UTC · re: Johannes Schindelin · lore

[PATCH v4 04/25] add_commit_patch_id(): avoid allocating memory unnecessarily

It would appear that we allocate (and forget to release) memory if the patch ID is not even defined.

Reported by the Coverity tool.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 patch-ids.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
Show changes to patch-ids.c +2 −1
diff --git a/patch-ids.c b/patch-ids.c
index fa8f11de826..92eba7a059e 100644
--- a/patch-ids.c
+++ b/patch-ids.c
@@ -99,11 +99,12 @@ struct patch_id *has_commit_patch_id(struct commit *commit,
 struct patch_id *add_commit_patch_id(struct commit *commit,
 				     struct patch_ids *ids)
 {
-	struct patch_id *key = xcalloc(1, sizeof(*key));
+	struct patch_id *key;
 
 	if (!patch_id_defined(commit))
 		return NULL;
 
+	key = xcalloc(1, sizeof(*key));
 	if (init_patch_id_entry(key, commit, ids)) {
 		free(key);
 		return NULL;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:55 UTC · re: Johannes Schindelin · lore

[PATCH v4 07/25] difftool: address a couple of resource/memory leaks

This change plugs a couple of memory leaks and makes sure that the file descriptor is closed in run_dir_diff().

Spotted by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/difftool.c | 33 +++++++++++++++++++++++----------
 1 file changed, 23 insertions(+), 10 deletions(-)
Show changes to builtin/difftool.c +23 −10
diff --git a/builtin/difftool.c b/builtin/difftool.c
index 1354d0e4625..b9a892f2693 100644
--- a/builtin/difftool.c
+++ b/builtin/difftool.c
@@ -226,6 +226,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
 		hashmap_entry_init(entry, strhash(buf.buf));
 		hashmap_add(result, entry);
 	}
+	fclose(fp);
 	if (finish_command(&diff_files))
 		die("diff-files did not exit properly");
 	strbuf_release(&index_env);
@@ -439,8 +440,10 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		}
 
 		if (lmode && status != 'C') {
-			if (checkout_path(lmode, &loid, src_path, &lstate))
-				return error("could not write '%s'", src_path);
+			if (checkout_path(lmode, &loid, src_path, &lstate)) {
+				ret = error("could not write '%s'", src_path);
+				goto finish;
+			}
 		}
 
 		if (rmode && !S_ISLNK(rmode)) {
@@ -456,9 +459,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 			hashmap_add(&working_tree_dups, entry);
 
 			if (!use_wt_file(workdir, dst_path, &roid)) {
-				if (checkout_path(rmode, &roid, dst_path, &rstate))
-					return error("could not write '%s'",
-						     dst_path);
+				if (checkout_path(rmode, &roid, dst_path,
+						  &rstate)) {
+					ret = error("could not write '%s'",
+						    dst_path);
+					goto finish;
+				}
 			} else if (!is_null_oid(&roid)) {
 				/*
 				 * Changes in the working tree need special
@@ -473,10 +479,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 						ADD_CACHE_JUST_APPEND);
 
 				add_path(&rdir, rdir_len, dst_path);
-				if (ensure_leading_directories(rdir.buf))
-					return error("could not create "
-						     "directory for '%s'",
-						     dst_path);
+				if (ensure_leading_directories(rdir.buf)) {
+					ret = error("could not create "
+						    "directory for '%s'",
+						    dst_path);
+					goto finish;
+				}
 				add_path(&wtdir, wtdir_len, dst_path);
 				if (symlinks) {
 					if (symlink(wtdir.buf, rdir.buf)) {
@@ -497,13 +505,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		}
 	}
 
+	fclose(fp);
+	fp = NULL;
 	if (finish_command(&child)) {
 		ret = error("error occurred running diff --raw");
 		goto finish;
 	}
 
 	if (!i)
-		return 0;
+		goto finish;
 
 	/*
 	 * Changes to submodules require special treatment.This loop writes a
@@ -626,6 +636,9 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
 		exit_cleanup(tmpdir, rc);
 
 finish:
+	if (fp)
+		fclose(fp);
+
 	free(lbase_dir);
 	free(rbase_dir);
 	strbuf_release(&ldir);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:55 UTC · re: Johannes Schindelin · lore

[PATCH v4 06/25] get_mail_commit_oid(): avoid resource leak

When we fail to read, or parse, the file, we still want to close the file descriptor and release the strbuf.

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/am.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)
Show changes to builtin/am.c +6 −9
diff --git a/builtin/am.c b/builtin/am.c
index a95dd8b4e6c..9c5c2c778e2 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -1351,19 +1351,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
 	struct strbuf sb = STRBUF_INIT;
 	FILE *fp = xfopen(mail, "r");
 	const char *x;
+	int ret = 0;
 
-	if (strbuf_getline_lf(&sb, fp))
-		return -1;
-
-	if (!skip_prefix(sb.buf, "From ", &x))
-		return -1;
-
-	if (get_oid_hex(x, commit_id) < 0)
-		return -1;
+	if (strbuf_getline_lf(&sb, fp) ||
+	    !skip_prefix(sb.buf, "From ", &x) ||
+	    get_oid_hex(x, commit_id) < 0)
+		ret = -1;
 
 	strbuf_release(&sb);
 	fclose(fp);
-	return 0;
+	return ret;
 }
 
 /**
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:55 UTC · re: Johannes Schindelin · lore

[PATCH v4 05/25] git_config_rename_section_in_file(): avoid resource leak

In case of errors, we really want the file descriptor to be closed.
Discovered by a Coverity scan.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 config.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
Show changes to config.c +4 −1
diff --git a/config.c b/config.c
index b4a3205da32..a30056ec7e9 100644
--- a/config.c
+++ b/config.c
@@ -2621,7 +2621,7 @@ int git_config_rename_section_in_file(const char *config_filename,
 	struct lock_file *lock;
 	int out_fd;
 	char buf[1024];
-	FILE *config_file;
+	FILE *config_file = NULL;
 	struct stat st;
 
 	if (new_name && !section_name_is_ok(new_name)) {
@@ -2703,11 +2703,14 @@ int git_config_rename_section_in_file(const char *config_filename,
 		}
 	}
 	fclose(config_file);
+	config_file = NULL;
 commit_and_out:
 	if (commit_lock_file(lock) < 0)
 		ret = error_errno("could not write config file %s",
 				  config_filename);
 out:
+	if (config_file)
+		fclose(config_file);
 	rollback_lock_file(lock);
 out_no_rollback:
 	free(filename_buf);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:56 UTC · re: Johannes Schindelin · lore

[PATCH v4 09/25] mailinfo & mailsplit: check for EOF while parsing

While POSIX states that it is okay to pass EOF to isspace() (and it seems to be implied that EOF should *not* be treated as whitespace), and also to pass EOF to ungetc() (which seems to be intended to fail without buffering the character), it is much better to handle these cases explicitly. Not only does it reduce head-scratching (and helps static analysis avoid reporting false positives), it also lets us handle files containing nothing but whitespace by erroring out.

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/mailsplit.c | 10 ++++++++++
 mailinfo.c          |  9 ++++++++-
 2 files changed, 18 insertions(+), 1 deletion(-)
Show changes to 2 files +18 −1

builtin/mailsplit.c, mailinfo.c

diff --git a/builtin/mailsplit.c b/builtin/mailsplit.c
index 30681681c13..664400b8169 100644
--- a/builtin/mailsplit.c
+++ b/builtin/mailsplit.c
@@ -232,6 +232,16 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
 
 	do {
 		peek = fgetc(f);
+		if (peek == EOF) {
+			if (f == stdin)
+				/* empty stdin is OK */
+				ret = skip;
+			else {
+				fclose(f);
+				error(_("empty mbox: '%s'"), file);
+			}
+			goto out;
+		}
 	} while (isspace(peek));
 	ungetc(peek, f);
 
diff --git a/mailinfo.c b/mailinfo.c
index 68037758f2f..f92cb9f729c 100644
--- a/mailinfo.c
+++ b/mailinfo.c
@@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE *in)
 	for (;;) {
 		int peek;
 
-		peek = fgetc(in); ungetc(peek, in);
+		peek = fgetc(in);
+		if (peek == EOF)
+			break;
+		ungetc(peek, in);
 		if (peek != ' ' && peek != '\t')
 			break;
 		if (strbuf_getline_lf(&continuation, in))
@@ -1099,6 +1102,10 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
 
 	do {
 		peek = fgetc(mi->input);
+		if (peek == EOF) {
+			fclose(cmitmsg);
+			return error("empty patch: '%s'", patch);
+		}
 	} while (isspace(peek));
 	ungetc(peek, mi->input);
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:55 UTC · re: Johannes Schindelin · lore

[PATCH v4 08/25] status: close file descriptor after reading git-rebase-todo

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to wt-status.c +1 −0
diff --git a/wt-status.c b/wt-status.c
index 03754849626..0a6e16dbe0f 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1168,6 +1168,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines)
 		abbrev_sha1_in_line(&line);
 		string_list_append(lines, line.buf);
 	}
+	fclose(f);
 	return 0;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:55 UTC · re: Johannes Schindelin · lore

[PATCH v4 02/25] winansi: avoid use of uninitialized value

To initialize the foreground color attributes of "plain text", our ANSI emulation tries to infer them from the currently attached console while running the is_console() function. This function first tries to detect any console attached to stdout, then it is called with stderr.

If neither stdout nor stderr has any console attached, it does not actually matter what we use for "plain text" attributes, as we never need to output any text to any console in that case.

However, after working on stdout and stderr, is_console() is called with stdin, and it still tries to initialize the "plain text" attributes if they had not been initialized earlier. In this case, we cannot detect any attributes, and we used an uninitialized value for them.

Naturally, Coverity complained about this use case because it could not reason about the code deeply enough to figure out that we do not even use those attributes in that case.

Let's just initialize the value to 0 in that case, both to avoid future Coverity reports, and to help catch future regressions in case anybody changes the order of the is_console() calls (which would make the text black on black).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 7 +++++++
 1 file changed, 7 insertions(+)
Show changes to compat/winansi.c +7 −0
diff --git a/compat/winansi.c b/compat/winansi.c
index 793420f9d0d..a551de90eb0 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -105,6 +105,13 @@ static int is_console(int fd)
 	if (!fd) {
 		if (!GetConsoleMode(hcon, &mode))
 			return 0;
+		/*
+		 * This code path is only reached if there is no console
+		 * attached to stdout/stderr, i.e. we will not need to output
+		 * any text to any console, therefore we might just as well
+		 * use black as foreground color.
+		 */
+		sbi.wAttributes = 0;
 	} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
 		return 0;
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:55 UTC · re: Johannes Schindelin · lore

[PATCH v4 01/25] mingw: avoid memory leak when splitting PATH

In the (admittedly, concocted) case that PATH consists only of path delimiters, we would leak the duplicated string.

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/mingw.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
Show changes to compat/mingw.c +3 −1
diff --git a/compat/mingw.c b/compat/mingw.c
index 3fbfda5978b..fe0e3ccd248 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -961,8 +961,10 @@ static char **get_path_split(void)
 			++n;
 		}
 	}
-	if (!n)
+	if (!n) {
+		free(envpath);
 		return NULL;
+	}
 
 	ALLOC_ARRAY(path, n + 1);
 	p = envpath;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:55 UTC · re: Johannes Schindelin · lore

[PATCH v4 03/25] winansi: avoid buffer overrun

When we could not convert the UTF-8 sequence into Unicode for writing to the Console, we should not try to write an insanely-long sequence of invalid wide characters (mistaking the negative return value for an unsigned length).

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 compat/winansi.c | 5 +++++
 1 file changed, 5 insertions(+)
Show changes to compat/winansi.c +5 −0
diff --git a/compat/winansi.c b/compat/winansi.c
index a551de90eb0..a11a0f16d27 100644
--- a/compat/winansi.c
+++ b/compat/winansi.c
@@ -140,6 +140,11 @@ static void write_console(unsigned char *str, size_t len)
 
 	/* convert utf-8 to utf-16 */
 	int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
+	if (wlen < 0) {
+		wchar_t *err = L"[invalid]";
+		WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
+		return;
+	}
 
 	/* write directly to console */
 	WriteConsoleW(console, wbuf, wlen, &dummy, NULL);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:56 UTC · re: Johannes Schindelin · lore

[PATCH v4 10/25] cat-file: fix memory leak

Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/cat-file.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/cat-file.c +1 −0
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 1890d7a6390..9af863e7915 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
 		die("git cat-file %s: bad file", obj_name);
 
 	write_or_die(1, buf, size);
+	free(buf);
 	return 0;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:56 UTC · re: Johannes Schindelin · lore

[PATCH v4 11/25] checkout: fix memory leak

This change addresses part of the NEEDSWORK comment above the code, therefore the comment needs to be adjusted, too.

Discovered via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/checkout.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)
Show changes to builtin/checkout.c +9 −8
diff --git a/builtin/checkout.c b/builtin/checkout.c
index bfa5419f335..5faea3a05fa 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -235,14 +235,14 @@ static int checkout_merged(int pos, const struct checkout *state)
 	/*
 	 * NEEDSWORK:
 	 * There is absolutely no reason to write this as a blob object
-	 * and create a phony cache entry just to leak.  This hack is
-	 * primarily to get to the write_entry() machinery that massages
-	 * the contents to work-tree format and writes out which only
-	 * allows it for a cache entry.  The code in write_entry() needs
-	 * to be refactored to allow us to feed a <buffer, size, mode>
-	 * instead of a cache entry.  Such a refactoring would help
-	 * merge_recursive as well (it also writes the merge result to the
-	 * object database even when it may contain conflicts).
+	 * and create a phony cache entry.  This hack is primarily to get
+	 * to the write_entry() machinery that massages the contents to
+	 * work-tree format and writes out which only allows it for a
+	 * cache entry.  The code in write_entry() needs to be refactored
+	 * to allow us to feed a <buffer, size, mode> instead of a cache
+	 * entry.  Such a refactoring would help merge_recursive as well
+	 * (it also writes the merge result to the object database even
+	 * when it may contain conflicts).
 	 */
 	if (write_sha1_file(result_buf.ptr, result_buf.size,
 			    blob_type, oid.hash))
@@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
 	if (!ce)
 		die(_("make_cache_entry failed for path '%s'"), path);
 	status = checkout_entry(ce, state, NULL);
+	free(ce);
 	return status;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
René Scharfe· May 6, 2017, 17:14 UTC · re: Johannes Schindelin · lore

Re: [PATCH v4 11/25] checkout: fix memory leak

Am 04.05.2017 um 15:56 schrieb Johannes Schindelin:
Show 37 quoted lines
> This change addresses part of the NEEDSWORK comment above the code,
> therefore the comment needs to be adjusted, too.
> 
> Discovered via Coverity.
> 
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
>   builtin/checkout.c | 17 +++++++++--------
>   1 file changed, 9 insertions(+), 8 deletions(-)
> 
> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index bfa5419f335..5faea3a05fa 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -235,14 +235,14 @@ static int checkout_merged(int pos, const struct checkout *state)
>   	/*
>   	 * NEEDSWORK:
>   	 * There is absolutely no reason to write this as a blob object
> -	 * and create a phony cache entry just to leak.  This hack is
> -	 * primarily to get to the write_entry() machinery that massages
> -	 * the contents to work-tree format and writes out which only
> -	 * allows it for a cache entry.  The code in write_entry() needs
> -	 * to be refactored to allow us to feed a <buffer, size, mode>
> -	 * instead of a cache entry.  Such a refactoring would help
> -	 * merge_recursive as well (it also writes the merge result to the
> -	 * object database even when it may contain conflicts).
> +	 * and create a phony cache entry.  This hack is primarily to get
> +	 * to the write_entry() machinery that massages the contents to
> +	 * work-tree format and writes out which only allows it for a
> +	 * cache entry.  The code in write_entry() needs to be refactored
> +	 * to allow us to feed a <buffer, size, mode> instead of a cache
> +	 * entry.  Such a refactoring would help merge_recursive as well
> +	 * (it also writes the merge result to the object database even
> +	 * when it may contain conflicts).
>   	 */
>   	if (write_sha1_file(result_buf.ptr, result_buf.size,
>   			    blob_type, oid.hash))

Random observation: Using pretend_sha1_file here would at least avoid writing the blob.

Show 7 quoted lines
> @@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
>   	if (!ce)
>   		die(_("make_cache_entry failed for path '%s'"), path);
>   	status = checkout_entry(ce, state, NULL);
> +	free(ce);
>   	return status;
>   }

I wonder if that's safe. Why document a leak when it could have been plugged this easily instead? A leak is better than a use after free, so let's be extra careful here. Would it leave the index inconsistent? Or perhaps freeing it has become safe in the meantime?

@Junio: Do you remember the reason for the leaks in 0cf8581e330 (checkout -m: recreate merge when checking out of unmerged index).

And result_buf is still leaked here, right?

FWIW, after fixing a different issue (patch just sent separately) t*checkout*.sh complete successfully for me with --valgrind, with and without freeing both ce and result_buf.ptr. So it *seems* safe..

René
Junio C Hamano· May 8, 2017, 00:41 UTC · re: René Scharfe · lore

Re: [PATCH v4 11/25] checkout: fix memory leak

René Scharfe <l.s.r@web.de> writes:
Show 25 quoted lines
>>   	/*
>>   	 * NEEDSWORK:
>>   	 * There is absolutely no reason to write this as a blob object
>> -	 * and create a phony cache entry just to leak.  This hack is
>> -	 * primarily to get to the write_entry() machinery that massages
>> -	 * the contents to work-tree format and writes out which only
>> -	 * allows it for a cache entry.  The code in write_entry() needs
>> -	 * to be refactored to allow us to feed a <buffer, size, mode>
>> -	 * instead of a cache entry.  Such a refactoring would help
>> -	 * merge_recursive as well (it also writes the merge result to the
>> -	 * object database even when it may contain conflicts).
>> +	 * and create a phony cache entry.  This hack is primarily to get
>> +	 * to the write_entry() machinery that massages the contents to
>> +	 * work-tree format and writes out which only allows it for a
>> +	 * cache entry.  The code in write_entry() needs to be refactored
>> +	 * to allow us to feed a <buffer, size, mode> instead of a cache
>> +	 * entry.  Such a refactoring would help merge_recursive as well
>> +	 * (it also writes the merge result to the object database even
>> +	 * when it may contain conflicts).
>>   	 */
>>   	if (write_sha1_file(result_buf.ptr, result_buf.size,
>>   			    blob_type, oid.hash))
>
> Random observation: Using pretend_sha1_file here would at least avoid
> writing the blob.

Yup, you should have told that to me back in Aug 2008 ;-) when I did 0cf8581e ("checkout -m: recreate merge when checking out of unmerged index", 2008-08-30); pretend_sha1_file() was available since early 2007, and there is no excuse that this codepath did not use it.

Show 18 quoted lines
>
>> @@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
>>   	if (!ce)
>>   		die(_("make_cache_entry failed for path '%s'"), path);
>>   	status = checkout_entry(ce, state, NULL);
>> +	free(ce);
>>   	return status;
>>   }
>
> I wonder if that's safe.  Why document a leak when it could have been
> plugged this easily instead?
>
> A leak is better than a use after free, so
> let's be extra careful here.  Would it leave the index inconsistent?  Or
> perhaps freeing it has become safe in the meantime?
>
> @Junio: Do you remember the reason for the leaks in 0cf8581e330
> (checkout -m: recreate merge when checking out of unmerged index).
Yes.

In the very old days it was not allowed to free(3) contents of active_cache[] and this was an old brain fart that came out of inertia. We are manufacturing a brand new ce, only to feed it to checkout_entry() without even registering it to the active_cache[] array, and the ancient rule doesn't even apply to such a case.

So I think it was safe to free(3) even back then.
> And result_buf is still leaked here, right?

Good spotting. It typically would make a larger leak than a single ce, I would suppose ;-)

Johannes Schindelin· May 9, 2017, 13:42 UTC · re: Junio C Hamano · lore

Re: [PATCH v4 11/25] checkout: fix memory leak

Hi Junio & René,
On Mon, 8 May 2017, Junio C Hamano wrote:
Show 32 quoted lines
> René Scharfe <l.s.r@web.de> writes:
> 
> >>   	/*
> >>   	 * NEEDSWORK:
> >>   	 * There is absolutely no reason to write this as a blob object
> >> -	 * and create a phony cache entry just to leak.  This hack is
> >> -	 * primarily to get to the write_entry() machinery that massages
> >> -	 * the contents to work-tree format and writes out which only
> >> -	 * allows it for a cache entry.  The code in write_entry() needs
> >> -	 * to be refactored to allow us to feed a <buffer, size, mode>
> >> -	 * instead of a cache entry.  Such a refactoring would help
> >> -	 * merge_recursive as well (it also writes the merge result to the
> >> -	 * object database even when it may contain conflicts).
> >> +	 * and create a phony cache entry.  This hack is primarily to get
> >> +	 * to the write_entry() machinery that massages the contents to
> >> +	 * work-tree format and writes out which only allows it for a
> >> +	 * cache entry.  The code in write_entry() needs to be refactored
> >> +	 * to allow us to feed a <buffer, size, mode> instead of a cache
> >> +	 * entry.  Such a refactoring would help merge_recursive as well
> >> +	 * (it also writes the merge result to the object database even
> >> +	 * when it may contain conflicts).
> >>   	 */
> >>   	if (write_sha1_file(result_buf.ptr, result_buf.size,
> >>   			    blob_type, oid.hash))
> >
> > Random observation: Using pretend_sha1_file here would at least avoid
> > writing the blob.
> 
> Yup, you should have told that to me back in Aug 2008 ;-) when I did
> 0cf8581e ("checkout -m: recreate merge when checking out of unmerged
> index", 2008-08-30); pretend_sha1_file() was available since early
> 2007, and there is no excuse that this codepath did not use it.
I hope y'all agree that this is outside the scope of my patch series...
Show 27 quoted lines
> >> @@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
> >>   	if (!ce)
> >>   		die(_("make_cache_entry failed for path '%s'"), path);
> >>   	status = checkout_entry(ce, state, NULL);
> >> +	free(ce);
> >>   	return status;
> >>   }
> >
> > I wonder if that's safe.  Why document a leak when it could have been
> > plugged this easily instead?
> >
> > A leak is better than a use after free, so
> > let's be extra careful here.  Would it leave the index inconsistent?  Or
> > perhaps freeing it has become safe in the meantime?
> >
> > @Junio: Do you remember the reason for the leaks in 0cf8581e330
> > (checkout -m: recreate merge when checking out of unmerged index).
> 
> Yes.
> 
> In the very old days it was not allowed to free(3) contents of
> active_cache[] and this was an old brain fart that came out of
> inertia.  We are manufacturing a brand new ce, only to feed it to
> checkout_entry() without even registering it to the active_cache[]
> array, and the ancient rule doesn't even apply to such a case.
> 
> So I think it was safe to free(3) even back then.
So this patch is good, then?
> > And result_buf is still leaked here, right?
> 
> Good spotting.  It typically would make a larger leak than a single
> ce, I would suppose ;-)

I saw you added this as a fixup! commit. If you don't mind, and if no other changes are requested, would you mind rebase'ing this yourself?

Thanks, Dscho

Junio C Hamano· May 9, 2017, 22:51 UTC · re: Johannes Schindelin · lore

Re: [PATCH v4 11/25] checkout: fix memory leak

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
Show 18 quoted lines
>> > A leak is better than a use after free, so
>> > let's be extra careful here.  Would it leave the index inconsistent?  Or
>> > perhaps freeing it has become safe in the meantime?
>> >
>> > @Junio: Do you remember the reason for the leaks in 0cf8581e330
>> > (checkout -m: recreate merge when checking out of unmerged index).
>> 
>> Yes.
>> 
>> In the very old days it was not allowed to free(3) contents of
>> active_cache[] and this was an old brain fart that came out of
>> inertia.  We are manufacturing a brand new ce, only to feed it to
>> checkout_entry() without even registering it to the active_cache[]
>> array, and the ancient rule doesn't even apply to such a case.
>> 
>> So I think it was safe to free(3) even back then.
>
> So this patch is good, then?

Unless I from this year is failing to spot a breakage that will be caused in the codepath that I from year 2008 and René spotted, I think freeing ce after we are done updating the working tree file with it is safe. I'd need to find time to make sure, though.

Show 7 quoted lines
>> > And result_buf is still leaked here, right?
>> 
>> Good spotting.  It typically would make a larger leak than a single
>> ce, I would suppose ;-)
>
> I saw you added this as a fixup! commit. If you don't mind, and if no
> other changes are requested, would you mind rebase'ing this yourself?

I think it would be better to leave the fix as a separate patch. It wasn't spotted by Coverity in the first place ;-)

Johannes Schindelin· May 4, 2017, 13:57 UTC · re: Johannes Schindelin · lore

[PATCH v4 18/25] receive-pack: plug memory leak in update()

Reported via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/receive-pack.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
Show changes to builtin/receive-pack.c +3 −1
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index f96834f42c9..48c07ddb659 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -986,7 +986,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 {
 	const char *name = cmd->ref_name;
 	struct strbuf namespaced_name_buf = STRBUF_INIT;
-	const char *namespaced_name, *ret;
+	static char *namespaced_name;
+	const char *ret;
 	struct object_id *old_oid = &cmd->old_oid;
 	struct object_id *new_oid = &cmd->new_oid;
 
@@ -997,6 +998,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
 	}
 
 	strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
+	free(namespaced_name);
 	namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
 
 	if (is_ref_checked_out(namespaced_name)) {
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:58 UTC · re: Johannes Schindelin · lore

[PATCH v4 19/25] line-log: avoid memory leak

Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 line-log.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to line-log.c +1 −0
diff --git a/line-log.c b/line-log.c
index a23b910471b..b9087814b8c 100644
--- a/line-log.c
+++ b/line-log.c
@@ -1125,6 +1125,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
 	changed = process_all_files(&parent_range, rev, &queue, range);
 	if (parent)
 		add_line_range(rev, parent, parent_range);
+	free_line_log_data(parent_range);
 	return changed;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:58 UTC · re: Johannes Schindelin · lore

[PATCH v4 20/25] shallow: avoid memory leak

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 shallow.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
Show changes to shallow.c +6 −2
diff --git a/shallow.c b/shallow.c
index 25b6db989bf..f9370961f99 100644
--- a/shallow.c
+++ b/shallow.c
@@ -473,11 +473,15 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,
 	struct commit_list *head = NULL;
 	int bitmap_nr = (info->nr_bits + 31) / 32;
 	size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr);
-	uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */
-	uint32_t *bitmap = paint_alloc(info);
 	struct commit *c = lookup_commit_reference_gently(sha1, 1);
+	uint32_t *tmp; /* to be freed before return */
+	uint32_t *bitmap;
+
 	if (!c)
 		return;
+
+	tmp = xmalloc(bitmap_size);
+	bitmap = paint_alloc(info);
 	memset(bitmap, 0, bitmap_size);
 	bitmap[id / 32] |= (1U << (id % 32));
 	commit_list_insert(c, &head);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:56 UTC · re: Johannes Schindelin · lore

[PATCH v4 12/25] split_commit_in_progress(): simplify & fix memory leak

This function did a whole lot of unnecessary work, such as reading in four files just to figure out that, oh, hey, we do not need to look at them after all because the HEAD is not detached.

Simplify the entire function to return early when possible, to read in the files only when necessary, and to release the allocated memory always (there was a leak, reported via Coverity, where we failed to release the allocated strings if the HEAD is not detached).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 wt-status.c | 28 ++++++++++++++--------------
 1 file changed, 14 insertions(+), 14 deletions(-)
Show changes to wt-status.c +14 −14
diff --git a/wt-status.c b/wt-status.c
index 0a6e16dbe0f..117ac8cfb01 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -1082,29 +1082,29 @@ static char *read_line_from_git_path(const char *filename)
 static int split_commit_in_progress(struct wt_status *s)
 {
 	int split_in_progress = 0;
-	char *head = read_line_from_git_path("HEAD");
-	char *orig_head = read_line_from_git_path("ORIG_HEAD");
-	char *rebase_amend = read_line_from_git_path("rebase-merge/amend");
-	char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
+	char *head, *orig_head, *rebase_amend, *rebase_orig_head;
 
-	if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
+	if ((!s->amend && !s->nowarn && !s->workdir_dirty) ||
 	    !s->branch || strcmp(s->branch, "HEAD"))
-		return split_in_progress;
+		return 0;
 
-	if (!strcmp(rebase_amend, rebase_orig_head)) {
-		if (strcmp(head, rebase_amend))
-			split_in_progress = 1;
-	} else if (strcmp(orig_head, rebase_orig_head)) {
-		split_in_progress = 1;
-	}
+	head = read_line_from_git_path("HEAD");
+	orig_head = read_line_from_git_path("ORIG_HEAD");
+	rebase_amend = read_line_from_git_path("rebase-merge/amend");
+	rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
 
-	if (!s->amend && !s->nowarn && !s->workdir_dirty)
-		split_in_progress = 0;
+	if (!head || !orig_head || !rebase_amend || !rebase_orig_head)
+		; /* fall through, no split in progress */
+	else if (!strcmp(rebase_amend, rebase_orig_head))
+		split_in_progress = !!strcmp(head, rebase_amend);
+	else if (strcmp(orig_head, rebase_orig_head))
+		split_in_progress = 1;
 
 	free(head);
 	free(orig_head);
 	free(rebase_amend);
 	free(rebase_orig_head);
+
 	return split_in_progress;
 }
 
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:56 UTC · re: Johannes Schindelin · lore

[PATCH v4 14/25] setup_discovered_git_dir(): plug memory leak

The setup_explicit_git_dir() function does not take custody of the string passed as first parameter; we have to release it if we turned the value of git_dir into an absolute path.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 setup.c | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
Show changes to setup.c +7 −2
diff --git a/setup.c b/setup.c
index 0320a9ad14c..e3f7699a902 100644
--- a/setup.c
+++ b/setup.c
@@ -703,11 +703,16 @@ static const char *setup_discovered_git_dir(const char *gitdir,
 
 	/* --work-tree is set without --git-dir; use discovered one */
 	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
+		char *to_free = NULL;
+		const char *ret;
+
 		if (offset != cwd->len && !is_absolute_path(gitdir))
-			gitdir = real_pathdup(gitdir, 1);
+			gitdir = to_free = real_pathdup(gitdir, 1);
 		if (chdir(cwd->buf))
 			die_errno("Could not come back to cwd");
-		return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+		ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
+		free(to_free);
+		return ret;
 	}
 
 	/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:57 UTC · re: Johannes Schindelin · lore

[PATCH v4 17/25] fast-export: avoid leaking memory in handle_tag()

Reported by, you guessed it, Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/fast-export.c | 2 ++
 1 file changed, 2 insertions(+)
Show changes to builtin/fast-export.c +2 −0
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index e0220630d00..64617ad8e36 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -734,6 +734,7 @@ static void handle_tag(const char *name, struct tag *tag)
 			     oid_to_hex(&tag->object.oid));
 		case DROP:
 			/* Ignore this tag altogether */
+			free(buf);
 			return;
 		case REWRITE:
 			if (tagged->type != OBJ_COMMIT) {
@@ -765,6 +766,7 @@ static void handle_tag(const char *name, struct tag *tag)
 	       (int)(tagger_end - tagger), tagger,
 	       tagger == tagger_end ? "" : "\n",
 	       (int)message_size, (int)message_size, message ? message : "");
+	free(buf);
 }
 
 static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:57 UTC · re: Johannes Schindelin · lore

[PATCH v4 16/25] mktree: plug memory leaks reported by Coverity

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/mktree.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to builtin/mktree.c +3 −2
diff --git a/builtin/mktree.c b/builtin/mktree.c
index de9b40fc63b..da0fd8cd706 100644
--- a/builtin/mktree.c
+++ b/builtin/mktree.c
@@ -72,7 +72,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 	unsigned mode;
 	enum object_type mode_type; /* object type derived from mode */
 	enum object_type obj_type; /* object type derived from sha */
-	char *path;
+	char *path, *to_free = NULL;
 	unsigned char sha1[20];
 
 	ptr = buf;
@@ -102,7 +102,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 		struct strbuf p_uq = STRBUF_INIT;
 		if (unquote_c_style(&p_uq, path, NULL))
 			die("invalid quoting");
-		path = strbuf_detach(&p_uq, NULL);
+		path = to_free = strbuf_detach(&p_uq, NULL);
 	}
 
 	/*
@@ -136,6 +136,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
 	}
 
 	append_to_tree(mode, sha1, path);
+	free(to_free);
 }
 
 int cmd_mktree(int ac, const char **av, const char *prefix)
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:56 UTC · re: Johannes Schindelin · lore

[PATCH v4 13/25] setup_bare_git_dir(): help static analysis

Coverity reported a memory leak in this function. However, it can only be called once, as setup_git_directory() changes global state and hence is not reentrant.

Mark the variable as static to indicate that this is a singleton.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 setup.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to setup.c +1 −1
diff --git a/setup.c b/setup.c
index 0309c278218..0320a9ad14c 100644
--- a/setup.c
+++ b/setup.c
@@ -748,7 +748,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
 
 	/* --work-tree is set without --git-dir; use discovered one */
 	if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
-		const char *gitdir;
+		static const char *gitdir;
 
 		gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
 		if (chdir(cwd->buf))
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:58 UTC · re: Johannes Schindelin · lore

[PATCH v4 21/25] add_reflog_for_walk: avoid memory leak

We free()d the `log` buffer when dwim_log() returned 1, but not when it returned a larger value (which meant that it still allocated the buffer but we simply ignored it).

While in the vicinity, make sure that the `reflogs` structure as well as the `branch` variable are released properly, too.

Identified by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 reflog-walk.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
Show changes to reflog-walk.c +17 −3
diff --git a/reflog-walk.c b/reflog-walk.c
index 99679f58255..c63eb1a3fd7 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -183,7 +183,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 		if (!reflogs || reflogs->nr == 0) {
 			struct object_id oid;
 			char *b;
-			if (dwim_log(branch, strlen(branch), oid.hash, &b) == 1) {
+			int ret = dwim_log(branch, strlen(branch),
+					   oid.hash, &b);
+			if (ret > 1)
+				free(b);
+			else if (ret == 1) {
 				if (reflogs) {
 					free(reflogs->ref);
 					free(reflogs);
@@ -193,17 +197,27 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
 				reflogs = read_complete_reflog(branch);
 			}
 		}
-		if (!reflogs || reflogs->nr == 0)
+		if (!reflogs || reflogs->nr == 0) {
+			if (reflogs) {
+				free(reflogs->ref);
+				free(reflogs);
+			}
+			free(branch);
 			return -1;
+		}
 		string_list_insert(&info->complete_reflogs, branch)->util
 			= reflogs;
 	}
+	free(branch);
 
 	commit_reflog = xcalloc(1, sizeof(struct commit_reflog));
 	if (recno < 0) {
 		commit_reflog->recno = get_reflog_recno_by_time(reflogs, timestamp);
 		if (commit_reflog->recno < 0) {
-			free(branch);
+			if (reflogs) {
+				free(reflogs->ref);
+				free(reflogs);
+			}
 			free(commit_reflog);
 			return -1;
 		}
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:59 UTC · re: Johannes Schindelin · lore

[PATCH v4 22/25] remote: plug memory leak in match_explicit()

The `guess_ref()` returns an allocated buffer of which `make_linked_ref()` does not take custody (`alloc_ref()` makes a copy), therefore we need to release the buffer afterwards.

Noticed via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 remote.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
Show changes to remote.c +3 −2
diff --git a/remote.c b/remote.c
index 801137c72eb..72b4591b983 100644
--- a/remote.c
+++ b/remote.c
@@ -1191,9 +1191,10 @@ static int match_explicit(struct ref *src, struct ref *dst,
 		else if (is_null_oid(&matched_src->new_oid))
 			error("unable to delete '%s': remote ref does not exist",
 			      dst_value);
-		else if ((dst_guess = guess_ref(dst_value, matched_src)))
+		else if ((dst_guess = guess_ref(dst_value, matched_src))) {
 			matched_dst = make_linked_ref(dst_guess, dst_tail);
-		else
+			free(dst_guess);
+		} else
 			error("unable to push to unqualified destination: %s\n"
 			      "The destination refspec neither matches an "
 			      "existing ref on the remote nor\n"
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:59 UTC · re: Johannes Schindelin · lore

[PATCH v4 24/25] show_worktree(): plug memory leak

The buffer allocated by shorten_unambiguous_ref() needs to be released.
Discovered by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/worktree.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Show changes to builtin/worktree.c +5 −3
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 1722a9bdc2a..ff5dfd2b102 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -414,9 +414,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
 				find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
 		if (wt->is_detached)
 			strbuf_addstr(&sb, "(detached HEAD)");
-		else if (wt->head_ref)
-			strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
-		else
+		else if (wt->head_ref) {
+			char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
+			strbuf_addf(&sb, "[%s]", ref);
+			free(ref);
+		} else
 			strbuf_addstr(&sb, "(error)");
 	}
 	printf("%s\n", sb.buf);
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:59 UTC · re: Johannes Schindelin · lore

[PATCH v4 23/25] name-rev: avoid leaking memory in the `deref` case

When the `name_rev()` function is asked to dereference the tip name, it allocates memory. But when it turns out that another tip already described the commit better than the current one, we forgot to release the memory.

Pointed out by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/name-rev.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)
Show changes to builtin/name-rev.c +5 −2
diff --git a/builtin/name-rev.c b/builtin/name-rev.c
index 92a5d8a5d26..e7a3fe7ee70 100644
--- a/builtin/name-rev.c
+++ b/builtin/name-rev.c
@@ -28,6 +28,7 @@ static void name_rev(struct commit *commit,
 	struct rev_name *name = (struct rev_name *)commit->util;
 	struct commit_list *parents;
 	int parent_number = 1;
+	char *to_free = NULL;
 
 	parse_commit(commit);
 
@@ -35,7 +36,7 @@ static void name_rev(struct commit *commit,
 		return;
 
 	if (deref) {
-		tip_name = xstrfmt("%s^0", tip_name);
+		tip_name = to_free = xstrfmt("%s^0", tip_name);
 
 		if (generation)
 			die("generation: %d, but deref?", generation);
@@ -53,8 +54,10 @@ static void name_rev(struct commit *commit,
 		name->taggerdate = taggerdate;
 		name->generation = generation;
 		name->distance = distance;
-	} else
+	} else {
+		free(to_free);
 		return;
+	}
 
 	for (parents = commit->parents;
 			parents;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:59 UTC · re: Johannes Schindelin · lore

[PATCH v4 25/25] submodule_uses_worktrees(): plug memory leak

There is really no reason why we would need to hold onto the allocated string longer than necessary.

Reported by Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 worktree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Show changes to worktree.c +1 −1
diff --git a/worktree.c b/worktree.c
index bae787cf8d7..89a81b13de3 100644
--- a/worktree.c
+++ b/worktree.c
@@ -399,6 +399,7 @@ int submodule_uses_worktrees(const char *path)
 
 	/* The env would be set for the superproject. */
 	get_common_dir_noenv(&sb, submodule_gitdir);
+	free(submodule_gitdir);
 
 	/*
 	 * The check below is only known to be good for repository format
@@ -418,7 +419,6 @@ int submodule_uses_worktrees(const char *path)
 	/* See if there is any file inside the worktrees directory. */
 	dir = opendir(sb.buf);
 	strbuf_release(&sb);
-	free(submodule_gitdir);
 
 	if (!dir)
 		return 0;
-- 
2.12.2.windows.2.800.gede8f145e06
Johannes Schindelin· May 4, 2017, 13:56 UTC · re: Johannes Schindelin · lore

[PATCH v4 15/25] pack-redundant: plug memory leak

Identified via Coverity.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 builtin/pack-redundant.c | 1 +
 1 file changed, 1 insertion(+)
Show changes to builtin/pack-redundant.c +1 −0
diff --git a/builtin/pack-redundant.c b/builtin/pack-redundant.c
index 72c815844dd..cb1df1c7614 100644
--- a/builtin/pack-redundant.c
+++ b/builtin/pack-redundant.c
@@ -442,6 +442,7 @@ static void minimize(struct pack_list **min)
 	/* return if there are no objects missing from the unique set */
 	if (missing->size == 0) {
 		*min = unique;
+		free(missing);
 		return;
 	}
 
-- 
2.12.2.windows.2.800.gede8f145e06

← back to recent threads