Skip to content

Commit eba7af3

Browse files
committed
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 <[email protected]>
2 parents d7631f8 + fd4a85b commit eba7af3

23 files changed

+149
-64
lines changed

builtin/am.c

+6-9
Original file line numberDiff line numberDiff line change
@@ -1351,19 +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

1355-
if (strbuf_getline_lf(&sb, fp))
1356-
return -1;
1357-
1358-
if (!skip_prefix(sb.buf, "From ", &x))
1359-
return -1;
1360-
1361-
if (get_oid_hex(x, commit_id) < 0)
1362-
return -1;
1356+
if (strbuf_getline_lf(&sb, fp) ||
1357+
!skip_prefix(sb.buf, "From ", &x) ||
1358+
get_oid_hex(x, commit_id) < 0)
1359+
ret = -1;
13631360

13641361
strbuf_release(&sb);
13651362
fclose(fp);
1366-
return 0;
1363+
return ret;
13671364
}
13681365

13691366
/**

builtin/cat-file.c

+1
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

+10-8
Original file line numberDiff line numberDiff line change
@@ -235,22 +235,24 @@ static int checkout_merged(int pos, const struct checkout *state)
235235
/*
236236
* NEEDSWORK:
237237
* There is absolutely no reason to write this as a blob object
238-
* and create a phony cache entry just to leak. This hack is
239-
* primarily to get to the write_entry() machinery that massages
240-
* the contents to work-tree format and writes out which only
241-
* allows it for a cache entry. The code in write_entry() needs
242-
* to be refactored to allow us to feed a <buffer, size, mode>
243-
* instead of a cache entry. Such a refactoring would help
244-
* merge_recursive as well (it also writes the merge result to the
245-
* object database even when it may contain conflicts).
238+
* and create a phony cache entry. This hack is primarily to get
239+
* to the write_entry() machinery that massages the contents to
240+
* work-tree format and writes out which only allows it for a
241+
* cache entry. The code in write_entry() needs to be refactored
242+
* to allow us to feed a <buffer, size, mode> instead of a cache
243+
* entry. Such a refactoring would help merge_recursive as well
244+
* (it also writes the merge result to the object database even
245+
* when it may contain conflicts).
246246
*/
247247
if (write_sha1_file(result_buf.ptr, result_buf.size,
248248
blob_type, oid.hash))
249249
die(_("Unable to add merge result for '%s'"), path);
250+
free(result_buf.ptr);
250251
ce = make_cache_entry(mode, oid.hash, path, 2, 0);
251252
if (!ce)
252253
die(_("make_cache_entry failed for path '%s'"), path);
253254
status = checkout_entry(ce, state, NULL);
255+
free(ce);
254256
return status;
255257
}
256258

builtin/difftool.c

+23-10
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);
@@ -439,8 +440,10 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
439440
}
440441

441442
if (lmode && status != 'C') {
442-
if (checkout_path(lmode, &loid, src_path, &lstate))
443-
return error("could not write '%s'", src_path);
443+
if (checkout_path(lmode, &loid, src_path, &lstate)) {
444+
ret = error("could not write '%s'", src_path);
445+
goto finish;
446+
}
444447
}
445448

446449
if (rmode && !S_ISLNK(rmode)) {
@@ -456,9 +459,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
456459
hashmap_add(&working_tree_dups, entry);
457460

458461
if (!use_wt_file(workdir, dst_path, &roid)) {
459-
if (checkout_path(rmode, &roid, dst_path, &rstate))
460-
return error("could not write '%s'",
461-
dst_path);
462+
if (checkout_path(rmode, &roid, dst_path,
463+
&rstate)) {
464+
ret = error("could not write '%s'",
465+
dst_path);
466+
goto finish;
467+
}
462468
} else if (!is_null_oid(&roid)) {
463469
/*
464470
* Changes in the working tree need special
@@ -473,10 +479,12 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
473479
ADD_CACHE_JUST_APPEND);
474480

475481
add_path(&rdir, rdir_len, dst_path);
476-
if (ensure_leading_directories(rdir.buf))
477-
return error("could not create "
478-
"directory for '%s'",
479-
dst_path);
482+
if (ensure_leading_directories(rdir.buf)) {
483+
ret = error("could not create "
484+
"directory for '%s'",
485+
dst_path);
486+
goto finish;
487+
}
480488
add_path(&wtdir, wtdir_len, dst_path);
481489
if (symlinks) {
482490
if (symlink(wtdir.buf, rdir.buf)) {
@@ -497,13 +505,15 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
497505
}
498506
}
499507

508+
fclose(fp);
509+
fp = NULL;
500510
if (finish_command(&child)) {
501511
ret = error("error occurred running diff --raw");
502512
goto finish;
503513
}
504514

505515
if (!i)
506-
return 0;
516+
goto finish;
507517

508518
/*
509519
* 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,
626636
exit_cleanup(tmpdir, rc);
627637

628638
finish:
639+
if (fp)
640+
fclose(fp);
641+
629642
free(lbase_dir);
630643
free(rbase_dir);
631644
strbuf_release(&ldir);

builtin/fast-export.c

+2
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ static void handle_tag(const char *name, struct tag *tag)
734734
oid_to_hex(&tag->object.oid));
735735
case DROP:
736736
/* Ignore this tag altogether */
737+
free(buf);
737738
return;
738739
case REWRITE:
739740
if (tagged->type != OBJ_COMMIT) {
@@ -765,6 +766,7 @@ static void handle_tag(const char *name, struct tag *tag)
765766
(int)(tagger_end - tagger), tagger,
766767
tagger == tagger_end ? "" : "\n",
767768
(int)message_size, (int)message_size, message ? message : "");
769+
free(buf);
768770
}
769771

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

builtin/mailsplit.c

+10
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,16 @@ static int split_mbox(const char *file, const char *dir, int allow_bare,
232232

233233
do {
234234
peek = fgetc(f);
235+
if (peek == EOF) {
236+
if (f == stdin)
237+
/* empty stdin is OK */
238+
ret = skip;
239+
else {
240+
fclose(f);
241+
error(_("empty mbox: '%s'"), file);
242+
}
243+
goto out;
244+
}
235245
} while (isspace(peek));
236246
ungetc(peek, f);
237247

builtin/mktree.c

+3-2
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, *to_free = 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 = to_free = 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(to_free);
139140
}
140141

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

builtin/name-rev.c

+5-2
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 *to_free = 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 = to_free = 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(to_free);
5759
return;
60+
}
5861

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

builtin/pack-redundant.c

+1
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

+3-1
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

+5-3
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

+3-1
Original file line numberDiff line numberDiff line change
@@ -1174,8 +1174,10 @@ static char **get_path_split(void)
11741174
++n;
11751175
}
11761176
}
1177-
if (!n)
1177+
if (!n) {
1178+
free(envpath);
11781179
return NULL;
1180+
}
11791181

11801182
ALLOC_ARRAY(path, n + 1);
11811183
p = envpath;

compat/winansi.c

+12
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ static int is_console(int fd)
100100
if (!fd) {
101101
if (!GetConsoleMode(hcon, &mode))
102102
return 0;
103+
/*
104+
* This code path is only reached if there is no console
105+
* attached to stdout/stderr, i.e. we will not need to output
106+
* any text to any console, therefore we might just as well
107+
* use black as foreground color.
108+
*/
109+
sbi.wAttributes = 0;
103110
} else if (!GetConsoleScreenBufferInfo(hcon, &sbi))
104111
return 0;
105112

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

129136
/* convert utf-8 to utf-16 */
130137
int wlen = xutftowcsn(wbuf, (char*) str, ARRAY_SIZE(wbuf), len);
138+
if (wlen < 0) {
139+
wchar_t *err = L"[invalid]";
140+
WriteConsoleW(console, err, wcslen(err), &dummy, NULL);
141+
return;
142+
}
131143

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

config.c

+4-1
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);

line-log.c

+1
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_line_log_data(parent_range);
11281129
return changed;
11291130
}
11301131

mailinfo.c

+8-1
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,10 @@ static int read_one_header_line(struct strbuf *line, FILE *in)
882882
for (;;) {
883883
int peek;
884884

885-
peek = fgetc(in); ungetc(peek, in);
885+
peek = fgetc(in);
886+
if (peek == EOF)
887+
break;
888+
ungetc(peek, in);
886889
if (peek != ' ' && peek != '\t')
887890
break;
888891
if (strbuf_getline_lf(&continuation, in))
@@ -1099,6 +1102,10 @@ int mailinfo(struct mailinfo *mi, const char *msg, const char *patch)
10991102

11001103
do {
11011104
peek = fgetc(mi->input);
1105+
if (peek == EOF) {
1106+
fclose(cmitmsg);
1107+
return error("empty patch: '%s'", patch);
1108+
}
11021109
} while (isspace(peek));
11031110
ungetc(peek, mi->input);
11041111

patch-ids.c

+2-1
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;

0 commit comments

Comments
 (0)