Merge branch 'coverity'

Coverity is a tool to analyze code statically, trying to find common (or
not so common) problems before they occur in production.

Coverity offers its services to Open Source software, and just like
upstream Git, Git for Windows applied and was granted the use.

While Coverity reports a lot of false positives due to Git's (ab-)use of
the FLEX_ARRAY feature (where it declares a 0-byte or 1-byte array at the
end of a struct, and then allocates a variable-length data structure
holding a variable-length string at the end, so that the struct as well as
the string can be released with a single free()), there were a few issues
reported that are true positives, and not all of them were resource leaks
in builtins (for which it is considered kind of okay to not release memory
just before exit() is called anyway).

This topic branch tries to address a couple of those issues.

Note: there are a couple more issues left, either because they are tricky
to resolve (in some cases, the custody of occasionally-allocated memory is
very unclear) or because it is unclear whether they are false positives
(due to the hard-to-reason-about nature of the code). It's a start,
though.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2017-04-26 12:24:06 +02:00
27 changed files with 101 additions and 36 deletions

View File

@@ -762,9 +762,11 @@ static int split_mail_conv(mail_conv_fn fn, struct am_state *state,
mail = mkpath("%s/%0*d", state->dir, state->prec, i + 1);
out = fopen(mail, "w");
if (!out)
if (!out) {
fclose(in);
return error_errno(_("could not open '%s' for writing"),
mail);
}
ret = fn(out, in, keep_cr);
@@ -1355,15 +1357,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);

View File

@@ -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;
}

View File

@@ -232,6 +232,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;
}

View File

@@ -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);
@@ -456,6 +457,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;

View File

@@ -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)

View File

@@ -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')) {

View File

@@ -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)

View File

@@ -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 @@ copy_data:
name->taggerdate = taggerdate;
name->generation = generation;
name->distance = distance;
} else
} else {
free(p);
return;
}
for (parents = commit->parents;
parents;

View File

@@ -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;
}

View File

@@ -984,7 +984,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;
unsigned char *old_sha1 = cmd->old_sha1;
unsigned char *new_sha1 = cmd->new_sha1;
@@ -995,6 +996,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)) {

View File

@@ -408,9 +408,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);

View File

@@ -1172,8 +1172,10 @@ static char **get_path_split(void)
++n;
}
}
if (!n)
if (!n) {
free(envpath);
return NULL;
}
ALLOC_ARRAY(path, n + 1);
p = envpath;
@@ -1566,12 +1568,18 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
if (getenv("GIT_STRACE_COMMANDS")) {
char **path = get_path_split();
cmd = path_lookup("strace.exe", path, 1);
if (!cmd)
char *p = path_lookup("strace.exe", path, 1);
if (!p) {
free_path_split(path);
return error("strace not found!");
if (xutftowcs_path(wcmd, cmd) < 0)
}
free_path_split(path);
if (xutftowcs_path(wcmd, p) < 0) {
free(p);
return -1;
}
strbuf_insert(&args, 0, "strace ", 7);
free(p);
}
ALLOC_ARRAY(wargs, st_add(st_mult(2, args.len), 1));

View File

@@ -100,6 +100,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;
@@ -128,6 +130,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);

View File

@@ -2426,7 +2426,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)) {
@@ -2508,11 +2508,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);

View File

@@ -716,8 +716,10 @@ static int handle_ssh_variant(const char *ssh_command, int is_cmdline,
* any longer.
*/
free(ssh_argv);
} else
} else {
free(ssh_argv);
return 0;
}
}
if (!strcasecmp(variant, "plink") ||

View File

@@ -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;
}

View File

@@ -169,9 +169,10 @@ const char *ident_default_email(void)
strbuf_addstr(&git_default_email, email);
committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
} else if ((email = query_user_email()) && email[0])
} else if ((email = query_user_email()) && email[0]) {
strbuf_addstr(&git_default_email, email);
else
free((char *)email);
} else
copy_email(xgetpwuid_self(&default_email_is_bogus),
&git_default_email, &default_email_is_bogus);
strbuf_trim(&git_default_email);

View File

@@ -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;
}

View File

@@ -1094,7 +1094,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 */

View File

@@ -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;

View File

@@ -183,7 +183,10 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
if (!reflogs || reflogs->nr == 0) {
unsigned char sha1[20];
char *b;
if (dwim_log(branch, strlen(branch), sha1, &b) == 1) {
int ret = dwim_log(branch, strlen(branch), sha1, &b);
if (ret > 1)
free(b);
else if (ret == 1) {
if (reflogs) {
free(reflogs->ref);
free(reflogs);

View File

@@ -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"

View File

@@ -2678,11 +2678,13 @@ int skip_unnecessary_picks(void)
if (write_in_full(fd, todo_list.buf.buf + offset,
todo_list.buf.len - offset) < 0) {
todo_list_release(&todo_list);
close(fd);
return error_errno(_("could not write to '%s'"),
rebase_path_todo());
}
if (ftruncate(fd, todo_list.buf.len - offset) < 0) {
todo_list_release(&todo_list);
close(fd);
return error_errno(_("could not truncate '%s'"),
rebase_path_todo());
}

11
setup.c
View File

@@ -697,11 +697,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) */
@@ -740,7 +745,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))

View File

@@ -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);

View File

@@ -396,6 +396,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
@@ -415,7 +416,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;

View File

@@ -1075,8 +1075,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))
@@ -1155,6 +1160,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;
}