Skip to content

Commit f4dfd08

Browse files
committed
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 <[email protected]>
2 parents 3d8d9a8 + c7f60b1 commit f4dfd08

24 files changed

+82
-29
lines changed

builtin/am.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,15 +1351,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
13511351
struct strbuf sb = STRBUF_INIT;
13521352
FILE *fp = xfopen(mail, "r");
13531353
const char *x;
1354+
int ret = 0;
13541355

13551356
if (strbuf_getline_lf(&sb, fp))
1356-
return -1;
1357+
ret = -1;
13571358

1358-
if (!skip_prefix(sb.buf, "From ", &x))
1359-
return -1;
1359+
if (!ret && !skip_prefix(sb.buf, "From ", &x))
1360+
ret = -1;
13601361

1361-
if (get_oid_hex(x, commit_id) < 0)
1362-
return -1;
1362+
if (!ret && get_oid_hex(x, commit_id) < 0)
1363+
ret = -1;
13631364

13641365
strbuf_release(&sb);
13651366
fclose(fp);

builtin/cat-file.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,
165165
die("git cat-file %s: bad file", obj_name);
166166

167167
write_or_die(1, buf, size);
168+
free(buf);
168169
return 0;
169170
}
170171

builtin/checkout.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ static int checkout_merged(int pos, const struct checkout *state)
251251
if (!ce)
252252
die(_("make_cache_entry failed for path '%s'"), path);
253253
status = checkout_entry(ce, state, NULL);
254+
free(ce);
254255
return status;
255256
}
256257

builtin/difftool.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ static void changed_files(struct hashmap *result, const char *index_path,
226226
hashmap_entry_init(entry, strhash(buf.buf));
227227
hashmap_add(result, entry);
228228
}
229+
fclose(fp);
229230
if (finish_command(&diff_files))
230231
die("diff-files did not exit properly");
231232
strbuf_release(&index_env);
@@ -497,6 +498,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
497498
}
498499
}
499500

501+
fclose(fp);
500502
if (finish_command(&child)) {
501503
ret = error("error occurred running diff --raw");
502504
goto finish;

builtin/fast-export.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,7 @@ static void handle_tag(const char *name, struct tag *tag)
765765
(int)(tagger_end - tagger), tagger,
766766
tagger == tagger_end ? "" : "\n",
767767
(int)message_size, (int)message_size, message ? message : "");
768+
free(buf);
768769
}
769770

770771
static struct commit *get_commit(struct rev_cmdline_entry *e, char *full_name)

builtin/mailsplit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
232232

233233
do {
234234
peek = fgetc(f);
235-
} while (isspace(peek));
235+
} while (peek >= 0 && isspace(peek));
236236
ungetc(peek, f);
237237

238238
if (strbuf_getwholeline(&buf, f, '\n')) {

builtin/mktree.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
7272
unsigned mode;
7373
enum object_type mode_type; /* object type derived from mode */
7474
enum object_type obj_type; /* object type derived from sha */
75-
char *path;
75+
char *path, *p = NULL;
7676
unsigned char sha1[20];
7777

7878
ptr = buf;
@@ -102,7 +102,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
102102
struct strbuf p_uq = STRBUF_INIT;
103103
if (unquote_c_style(&p_uq, path, NULL))
104104
die("invalid quoting");
105-
path = strbuf_detach(&p_uq, NULL);
105+
path = p = strbuf_detach(&p_uq, NULL);
106106
}
107107

108108
/*
@@ -136,6 +136,7 @@ static void mktree_line(char *buf, size_t len, int nul_term_line, int allow_miss
136136
}
137137

138138
append_to_tree(mode, sha1, path);
139+
free(p);
139140
}
140141

141142
int cmd_mktree(int ac, const char **av, const char *prefix)

builtin/name-rev.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ static void name_rev(struct commit *commit,
2828
struct rev_name *name = (struct rev_name *)commit->util;
2929
struct commit_list *parents;
3030
int parent_number = 1;
31+
char *p = NULL;
3132

3233
parse_commit(commit);
3334

3435
if (commit->date < cutoff)
3536
return;
3637

3738
if (deref) {
38-
tip_name = xstrfmt("%s^0", tip_name);
39+
tip_name = p = xstrfmt("%s^0", tip_name);
3940

4041
if (generation)
4142
die("generation: %d, but deref?", generation);
@@ -53,8 +54,10 @@ static void name_rev(struct commit *commit,
5354
name->taggerdate = taggerdate;
5455
name->generation = generation;
5556
name->distance = distance;
56-
} else
57+
} else {
58+
free(p);
5759
return;
60+
}
5861

5962
for (parents = commit->parents;
6063
parents;

builtin/pack-redundant.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,7 @@ static void minimize(struct pack_list **min)
442442
/* return if there are no objects missing from the unique set */
443443
if (missing->size == 0) {
444444
*min = unique;
445+
free(missing);
445446
return;
446447
}
447448

builtin/receive-pack.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
986986
{
987987
const char *name = cmd->ref_name;
988988
struct strbuf namespaced_name_buf = STRBUF_INIT;
989-
const char *namespaced_name, *ret;
989+
static char *namespaced_name;
990+
const char *ret;
990991
struct object_id *old_oid = &cmd->old_oid;
991992
struct object_id *new_oid = &cmd->new_oid;
992993

@@ -997,6 +998,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
997998
}
998999

9991000
strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
1001+
free(namespaced_name);
10001002
namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
10011003

10021004
if (is_ref_checked_out(namespaced_name)) {

builtin/worktree.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
414414
find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
415415
if (wt->is_detached)
416416
strbuf_addstr(&sb, "(detached HEAD)");
417-
else if (wt->head_ref)
418-
strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
419-
else
417+
else if (wt->head_ref) {
418+
char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
419+
strbuf_addf(&sb, "[%s]", ref);
420+
free(ref);
421+
} else
420422
strbuf_addstr(&sb, "(error)");
421423
}
422424
printf("%s\n", sb.buf);

compat/mingw.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1172,8 +1172,10 @@ static char **get_path_split(void)
11721172
++n;
11731173
}
11741174
}
1175-
if (!n)
1175+
if (!n) {
1176+
free(envpath);
11761177
return NULL;
1178+
}
11771179

11781180
ALLOC_ARRAY(path, n + 1);
11791181
p = envpath;

compat/winansi.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ static int is_console(int fd)
100100
if (!fd) {
101101
if (!GetConsoleMode(hcon, &mode))
102102
return 0;
103+
sbi.wAttributes = FOREGROUND_BLUE | FOREGROUND_GREEN |
104+
FOREGROUND_RED;
103105
} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
104106
return 0;
105107

@@ -128,6 +130,11 @@ static void write_console(unsigned char *str, size_t len)
128130

129131
/* convert utf-8 to utf-16 */
130132
int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
133+
if (wlen < 0) {
134+
wchar_t *err = L"[invalid]";
135+
WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
136+
return;
137+
}
131138

132139
/* write directly to console */
133140
WriteConsoleW(console, wbuf, wlen, &dummy, NULL);

config.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2620,7 +2620,7 @@ int git_config_rename_section_in_file(const char *config_filename,
26202620
struct lock_file *lock;
26212621
int out_fd;
26222622
char buf[1024];
2623-
FILE *config_file;
2623+
FILE *config_file = NULL;
26242624
struct stat st;
26252625

26262626
if (new_name && !section_name_is_ok(new_name)) {
@@ -2702,11 +2702,14 @@ int git_config_rename_section_in_file(const char *config_filename,
27022702
}
27032703
}
27042704
fclose(config_file);
2705+
config_file = NULL;
27052706
commit_and_out:
27062707
if (commit_lock_file(lock) < 0)
27072708
ret = error_errno("could not write config file %s",
27082709
config_filename);
27092710
out:
2711+
if (config_file)
2712+
fclose(config_file);
27102713
rollback_lock_file(lock);
27112714
out_no_rollback:
27122715
free(filename_buf);

http-backend.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -681,8 +681,10 @@ int cmd_main(int argc, const char **argv)
681681
if (!regexec(&re, dir, 1, out, 0)) {
682682
size_t n;
683683

684-
if (strcmp(method, c->method))
684+
if (strcmp(method, c->method)) {
685+
free(dir);
685686
return bad_request(&hdr, c);
687+
}
686688

687689
cmd = c;
688690
n = out[0].rm_eo - out[0].rm_so;
@@ -708,5 +710,7 @@ int cmd_main(int argc, const char **argv)
708710
max_request_buffer);
709711

710712
cmd->imp(&hdr, cmd_arg);
713+
free(dir);
714+
free(cmd_arg);
711715
return 0;
712716
}

line-log.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,7 @@ static int process_ranges_ordinary_commit(struct rev_info *rev, struct commit *c
11251125
changed = process_all_files(&parent_range, rev, &queue, range);
11261126
if (parent)
11271127
add_line_range(rev, parent, parent_range);
1128+
free(parent_range);
11281129
return changed;
11291130
}
11301131

mailinfo.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
10991099

11001100
do {
11011101
peek = fgetc(mi->input);
1102-
} while (isspace(peek));
1102+
} while (peek >= 0 && isspace(peek));
11031103
ungetc(peek, mi->input);
11041104

11051105
/* process the email header */

patch-ids.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,12 @@ struct patch_id *has_commit_patch_id(struct commit *commit,
9999
struct patch_id *add_commit_patch_id(struct commit *commit,
100100
struct patch_ids *ids)
101101
{
102-
struct patch_id *key = xcalloc(1, sizeof(*key));
102+
struct patch_id *key;
103103

104104
if (!patch_id_defined(commit))
105105
return NULL;
106106

107+
key = xcalloc(1, sizeof(*key));
107108
if (init_patch_id_entry(key, commit, ids)) {
108109
free(key);
109110
return NULL;

reflog-walk.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,11 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
183183
if (!reflogs || reflogs->nr == 0) {
184184
struct object_id oid;
185185
char *b;
186-
if (dwim_log(branch, strlen(branch), oid.hash, &b) == 1) {
186+
int ret = dwim_log(branch, strlen(branch),
187+
oid.hash, &b);
188+
if (ret > 1)
189+
free(b);
190+
else if (ret == 1) {
187191
if (reflogs) {
188192
free(reflogs->ref);
189193
free(reflogs);

remote.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,9 +1191,10 @@ static int match_explicit(struct ref *src, struct ref *dst,
11911191
else if (is_null_oid(&matched_src->new_oid))
11921192
error("unable to delete '%s': remote ref does not exist",
11931193
dst_value);
1194-
else if ((dst_guess = guess_ref(dst_value, matched_src)))
1194+
else if ((dst_guess = guess_ref(dst_value, matched_src))) {
11951195
matched_dst = make_linked_ref(dst_guess, dst_tail);
1196-
else
1196+
free(dst_guess);
1197+
} else
11971198
error("unable to push to unqualified destination: %s\n"
11981199
"The destination refspec neither matches an "
11991200
"existing ref on the remote nor\n"

setup.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -703,11 +703,16 @@ static const char *setup_discovered_git_dir(const char *gitdir,
703703

704704
/* --work-tree is set without --git-dir; use discovered one */
705705
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
706+
char *p = NULL;
707+
const char *ret;
708+
706709
if (offset != cwd->len && !is_absolute_path(gitdir))
707-
gitdir = real_pathdup(gitdir, 1);
710+
gitdir = p = real_pathdup(gitdir, 1);
708711
if (chdir(cwd->buf))
709712
die_errno("Could not come back to cwd");
710-
return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
713+
ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
714+
free(p);
715+
return ret;
711716
}
712717

713718
/* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
@@ -748,7 +753,7 @@ static const char *setup_bare_git_dir(struct strbuf *cwd, int offset,
748753

749754
/* --work-tree is set without --git-dir; use discovered one */
750755
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
751-
const char *gitdir;
756+
static const char *gitdir;
752757

753758
gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
754759
if (chdir(cwd->buf))

shallow.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -473,11 +473,15 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1,
473473
struct commit_list *head = NULL;
474474
int bitmap_nr = (info->nr_bits + 31) / 32;
475475
size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr);
476-
uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */
477-
uint32_t *bitmap = paint_alloc(info);
478476
struct commit *c = lookup_commit_reference_gently(sha1, 1);
477+
uint32_t *tmp; /* to be freed before return */
478+
uint32_t *bitmap;
479+
479480
if (!c)
480481
return;
482+
483+
tmp = xmalloc(bitmap_size);
484+
bitmap = paint_alloc(info);
481485
memset(bitmap, 0, bitmap_size);
482486
bitmap[id / 32] |= (1U << (id % 32));
483487
commit_list_insert(c, &head);

worktree.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ int submodule_uses_worktrees(const char *path)
399399

400400
/* The env would be set for the superproject. */
401401
get_common_dir_noenv(&sb, submodule_gitdir);
402+
free(submodule_gitdir);
402403

403404
/*
404405
* The check below is only known to be good for repository format
@@ -418,7 +419,6 @@ int submodule_uses_worktrees(const char *path)
418419
/* See if there is any file inside the worktrees directory. */
419420
dir = opendir(sb.buf);
420421
strbuf_release(&sb);
421-
free(submodule_gitdir);
422422

423423
if (!dir)
424424
return 0;

wt-status.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1088,8 +1088,13 @@ static int split_commit_in_progress(struct wt_status *s)
10881088
char *rebase_orig_head = read_line_from_git_path("rebase-merge/orig-head");
10891089

10901090
if (!head || !orig_head || !rebase_amend || !rebase_orig_head ||
1091-
!s->branch || strcmp(s->branch, "HEAD"))
1091+
!s->branch || strcmp(s->branch, "HEAD")) {
1092+
free(head);
1093+
free(orig_head);
1094+
free(rebase_amend);
1095+
free(rebase_orig_head);
10921096
return split_in_progress;
1097+
}
10931098

10941099
if (!strcmp(rebase_amend, rebase_orig_head)) {
10951100
if (strcmp(head, rebase_amend))
@@ -1168,6 +1173,7 @@ static int read_rebase_todolist(const char *fname, struct string_list *lines)
11681173
abbrev_sha1_in_line(&line);
11691174
string_list_append(lines, line.buf);
11701175
}
1176+
fclose(f);
11711177
return 0;
11721178
}
11731179

0 commit comments

Comments
 (0)