Skip to content

Commit 7a2040a

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 92d3e5a + 50cb324 commit 7a2040a

24 files changed

+87
-31
lines changed

builtin/am.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -762,14 +762,18 @@ static int split_mail_conv(mail_conv_fn fn, struct am_state *state,
762762
mail = mkpath("%s/%0*d", state->dir, state->prec, i + 1);
763763

764764
out = fopen(mail, "w");
765-
if (!out)
765+
if (!out) {
766+
if (in != stdin)
767+
fclose(in);
766768
return error_errno(_("could not open '%s' for writing"),
767769
mail);
770+
}
768771

769772
ret = fn(out, in, keep_cr);
770773

771774
fclose(out);
772-
fclose(in);
775+
if (in != stdin)
776+
fclose(in);
773777

774778
if (ret)
775779
return error(_("could not parse patch '%s'"), *paths);
@@ -1355,15 +1359,16 @@ static int get_mail_commit_oid(struct object_id *commit_id, const char *mail)
13551359
struct strbuf sb = STRBUF_INIT;
13561360
FILE *fp = xfopen(mail, "r");
13571361
const char *x;
1362+
int ret = 0;
13581363

13591364
if (strbuf_getline_lf(&sb, fp))
1360-
return -1;
1365+
ret = -1;
13611366

1362-
if (!skip_prefix(sb.buf, "From ", &x))
1363-
return -1;
1367+
if (!ret && !skip_prefix(sb.buf, "From ", &x))
1368+
ret = -1;
13641369

1365-
if (get_oid_hex(x, commit_id) < 0)
1366-
return -1;
1370+
if (!ret && get_oid_hex(x, commit_id) < 0)
1371+
ret = -1;
13671372

13681373
strbuf_release(&sb);
13691374
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
@@ -232,6 +232,7 @@ static int checkout_merged(int pos, const struct checkout *state)
232232
if (!ce)
233233
die(_("make_cache_entry failed for path '%s'"), path);
234234
status = checkout_entry(ce, state, NULL);
235+
free(ce);
235236
return status;
236237
}
237238

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
@@ -984,7 +984,8 @@ static const char *update(struct command *cmd, struct shallow_info *si)
984984
{
985985
const char *name = cmd->ref_name;
986986
struct strbuf namespaced_name_buf = STRBUF_INIT;
987-
const char *namespaced_name, *ret;
987+
static char *namespaced_name;
988+
const char *ret;
988989
unsigned char *old_sha1 = cmd->old_sha1;
989990
unsigned char *new_sha1 = cmd->new_sha1;
990991

@@ -995,6 +996,7 @@ static const char *update(struct command *cmd, struct shallow_info *si)
995996
}
996997

997998
strbuf_addf(&namespaced_name_buf, "%s%s", get_git_namespace(), name);
999+
free(namespaced_name);
9981000
namespaced_name = strbuf_detach(&namespaced_name_buf, NULL);
9991001

10001002
if (is_ref_checked_out(namespaced_name)) {

builtin/worktree.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,11 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)
408408
find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
409409
if (wt->is_detached)
410410
strbuf_addstr(&sb, "(detached HEAD)");
411-
else if (wt->head_ref)
412-
strbuf_addf(&sb, "[%s]", shorten_unambiguous_ref(wt->head_ref, 0));
413-
else
411+
else if (wt->head_ref) {
412+
char *ref = shorten_unambiguous_ref(wt->head_ref, 0);
413+
strbuf_addf(&sb, "[%s]", ref);
414+
free(ref);
415+
} else
414416
strbuf_addstr(&sb, "(error)");
415417
}
416418
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
@@ -2426,7 +2426,7 @@ int git_config_rename_section_in_file(const char *config_filename,
24262426
struct lock_file *lock;
24272427
int out_fd;
24282428
char buf[1024];
2429-
FILE *config_file;
2429+
FILE *config_file = NULL;
24302430
struct stat st;
24312431

24322432
if (new_name && !section_name_is_ok(new_name)) {
@@ -2508,11 +2508,14 @@ int git_config_rename_section_in_file(const char *config_filename,
25082508
}
25092509
}
25102510
fclose(config_file);
2511+
config_file = NULL;
25112512
commit_and_out:
25122513
if (commit_lock_file(lock) < 0)
25132514
ret = error_errno("could not write config file %s",
25142515
config_filename);
25152516
out:
2517+
if (config_file)
2518+
fclose(config_file);
25162519
rollback_lock_file(lock);
25172520
out_no_rollback:
25182521
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
@@ -1094,7 +1094,7 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
10941094

10951095
do {
10961096
peek = fgetc(mi->input);
1097-
} while (isspace(peek));
1097+
} while (peek >= 0 && isspace(peek));
10981098
ungetc(peek, mi->input);
10991099

11001100
/* 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: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,10 @@ int add_reflog_for_walk(struct reflog_walk_info *info,
183183
if (!reflogs || reflogs->nr == 0) {
184184
unsigned char sha1[20];
185185
char *b;
186-
if (dwim_log(branch, strlen(branch), sha1, &b) == 1) {
186+
int ret = dwim_log(branch, strlen(branch), sha1, &b);
187+
if (ret > 1)
188+
free(b);
189+
else if (ret == 1) {
187190
if (reflogs) {
188191
free(reflogs->ref);
189192
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
@@ -697,11 +697,16 @@ static const char *setup_discovered_git_dir(const char *gitdir,
697697

698698
/* --work-tree is set without --git-dir; use discovered one */
699699
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
700+
char *p = NULL;
701+
const char *ret;
702+
700703
if (offset != cwd->len && !is_absolute_path(gitdir))
701-
gitdir = real_pathdup(gitdir, 1);
704+
gitdir = p = real_pathdup(gitdir, 1);
702705
if (chdir(cwd->buf))
703706
die_errno("Could not come back to cwd");
704-
return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
707+
ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
708+
free(p);
709+
return ret;
705710
}
706711

707712
/* #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,
740745

741746
/* --work-tree is set without --git-dir; use discovered one */
742747
if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
743-
const char *gitdir;
748+
static const char *gitdir;
744749

745750
gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
746751
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
@@ -396,6 +396,7 @@ int submodule_uses_worktrees(const char *path)
396396

397397
/* The env would be set for the superproject. */
398398
get_common_dir_noenv(&sb, submodule_gitdir);
399+
free(submodule_gitdir);
399400

400401
/*
401402
* The check below is only known to be good for repository format
@@ -415,7 +416,6 @@ int submodule_uses_worktrees(const char *path)
415416
/* See if there is any file inside the worktrees directory. */
416417
dir = opendir(sb.buf);
417418
strbuf_release(&sb);
418-
free(submodule_gitdir);
419419

420420
if (!dir)
421421
return 0;

0 commit comments

Comments
 (0)