Skip to content
Permalink
Browse files

Merge branch 'coverity-v4-plus-fixup'

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>
  • Loading branch information...
dscho committed May 9, 2017
2 parents d7631f8 + fd4a85b commit eba7af3dbb4c846c6303c5f64102acee696c9ab0
Showing with 149 additions and 64 deletions.
  1. +6 −9 builtin/am.c
  2. +1 −0 builtin/cat-file.c
  3. +10 −8 builtin/checkout.c
  4. +23 −10 builtin/difftool.c
  5. +2 −0 builtin/fast-export.c
  6. +10 −0 builtin/mailsplit.c
  7. +3 −2 builtin/mktree.c
  8. +5 −2 builtin/name-rev.c
  9. +1 −0 builtin/pack-redundant.c
  10. +3 −1 builtin/receive-pack.c
  11. +5 −3 builtin/worktree.c
  12. +3 −1 compat/mingw.c
  13. +12 −0 compat/winansi.c
  14. +4 −1 config.c
  15. +1 −0 line-log.c
  16. +8 −1 mailinfo.c
  17. +2 −1 patch-ids.c
  18. +17 −3 reflog-walk.c
  19. +3 −2 remote.c
  20. +8 −3 setup.c
  21. +6 −2 shallow.c
  22. +1 −1 worktree.c
  23. +15 −14 wt-status.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;
}

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

@@ -235,22 +235,24 @@ 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))
die(_("Unable to add merge result for '%s'"), path);
free(result_buf.ptr);
ce = make_cache_entry(mode, oid.hash, path, 2, 0);
if (!ce)
die(_("make_cache_entry failed for path '%s'"), path);
status = checkout_entry(ce, state, NULL);
free(ce);
return status;
}

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

@@ -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)
@@ -28,14 +28,15 @@ 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);

if (commit->date < cutoff)
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;
@@ -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;
}

@@ -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)) {
@@ -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);
@@ -1174,8 +1174,10 @@ static char **get_path_split(void)
++n;
}
}
if (!n)
if (!n) {
free(envpath);
return NULL;
}

ALLOC_ARRAY(path, n + 1);
p = envpath;
@@ -100,6 +100,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;

@@ -128,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);
@@ -2620,7 +2620,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)) {
@@ -2702,11 +2702,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);
@@ -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;
}

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

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

0 comments on commit eba7af3

Please sign in to comment.
You can’t perform that action at this time.