Skip to content

Commit c3d034d

Browse files
committed
csum-file: introduce discard_hashfile()
The hashfile API is used to write out a "hashfile", which has a final checksum (typically SHA-1) at the end. An in-core hashfile structure has up to two file descriptors and a few buffers that can only be freed by calling a helper function that is private to the csum-file implementation. The usual flow of a user of the API is to first open a file descriptor for writing, obtain a hashfile associated with that write file descriptor by calling either hashfd() or hashfd_check(), call hashwrite() number of times to write data to the file, and then call finalize_hashfile(), which appends th checksum to the end of the file, closes file descriptors and releases associated buffers. But what if a caller finds some error after calling hashfd() to start the process and/or hashwrite() to send some data to the file, and wants to abort the operation? The underlying file descriptor is often managed by the tempfile API, so aborting will clean the file out of the filesystem, but the resources associated with the in-core hashfile structure is lost. Introduce discard_hashfile() API function to allow them to release the resources held by a hashfile structure the callers want to dispose of, and use that in read-cache.c:do_write_index(), which is a central place that writes the index file. Mark t2107 as leak-free, as this leak in "update-index --cacheinfo" test that deliberately makes it fail is now plugged. Signed-off-by: Junio C Hamano <[email protected]>
1 parent ad57f14 commit c3d034d

File tree

4 files changed

+89
-21
lines changed

4 files changed

+89
-21
lines changed

csum-file.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,15 @@ int finalize_hashfile(struct hashfile *f, unsigned char *result,
102102
return fd;
103103
}
104104

105+
void discard_hashfile(struct hashfile *f)
106+
{
107+
if (0 <= f->check_fd)
108+
close(f->check_fd);
109+
if (0 <= f->fd)
110+
close(f->fd);
111+
free_hashfile(f);
112+
}
113+
105114
void hashwrite(struct hashfile *f, const void *buf, unsigned int count)
106115
{
107116
while (count) {

csum-file.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ struct hashfile *hashfd(int fd, const char *name);
4747
struct hashfile *hashfd_check(const char *name);
4848
struct hashfile *hashfd_throughput(int fd, const char *name, struct progress *tp);
4949
int finalize_hashfile(struct hashfile *, unsigned char *, enum fsync_component, unsigned int);
50+
void discard_hashfile(struct hashfile *);
5051
void hashwrite(struct hashfile *, const void *, unsigned int);
5152
void hashflush(struct hashfile *f);
5253
void crc32_begin(struct hashfile *);

read-cache.c

Lines changed: 78 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2963,7 +2963,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
29632963

29642964
if (err) {
29652965
free(ieot);
2966-
return err;
2966+
goto cleanup;
29672967
}
29682968

29692969
offset = hashfile_total(f);
@@ -2992,8 +2992,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
29922992
hashwrite(f, sb.buf, sb.len);
29932993
strbuf_release(&sb);
29942994
free(ieot);
2995-
if (err)
2996-
return -1;
2995+
/*
2996+
* NEEDSWORK: write_index_ext_header() never returns a failure,
2997+
* and this part may want to be simplified.
2998+
*/
2999+
if (err) {
3000+
err = -1;
3001+
goto cleanup;
3002+
}
29973003
}
29983004

29993005
if (write_extensions & WRITE_SPLIT_INDEX_EXTENSION &&
@@ -3008,8 +3014,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
30083014
sb.len) < 0;
30093015
hashwrite(f, sb.buf, sb.len);
30103016
strbuf_release(&sb);
3011-
if (err)
3012-
return -1;
3017+
/*
3018+
* NEEDSWORK: write_link_extension() never returns a failure,
3019+
* and this part may want to be simplified.
3020+
*/
3021+
if (err) {
3022+
err = -1;
3023+
goto cleanup;
3024+
}
30133025
}
30143026
if (write_extensions & WRITE_CACHE_TREE_EXTENSION &&
30153027
!drop_cache_tree && istate->cache_tree) {
@@ -3019,8 +3031,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
30193031
err = write_index_ext_header(f, eoie_c, CACHE_EXT_TREE, sb.len) < 0;
30203032
hashwrite(f, sb.buf, sb.len);
30213033
strbuf_release(&sb);
3022-
if (err)
3023-
return -1;
3034+
/*
3035+
* NEEDSWORK: write_index_ext_header() never returns a failure,
3036+
* and this part may want to be simplified.
3037+
*/
3038+
if (err) {
3039+
err = -1;
3040+
goto cleanup;
3041+
}
30243042
}
30253043
if (write_extensions & WRITE_RESOLVE_UNDO_EXTENSION &&
30263044
istate->resolve_undo) {
@@ -3031,8 +3049,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
30313049
sb.len) < 0;
30323050
hashwrite(f, sb.buf, sb.len);
30333051
strbuf_release(&sb);
3034-
if (err)
3035-
return -1;
3052+
/*
3053+
* NEEDSWORK: write_index_ext_header() never returns a failure,
3054+
* and this part may want to be simplified.
3055+
*/
3056+
if (err) {
3057+
err = -1;
3058+
goto cleanup;
3059+
}
30363060
}
30373061
if (write_extensions & WRITE_UNTRACKED_CACHE_EXTENSION &&
30383062
istate->untracked) {
@@ -3043,8 +3067,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
30433067
sb.len) < 0;
30443068
hashwrite(f, sb.buf, sb.len);
30453069
strbuf_release(&sb);
3046-
if (err)
3047-
return -1;
3070+
/*
3071+
* NEEDSWORK: write_index_ext_header() never returns a failure,
3072+
* and this part may want to be simplified.
3073+
*/
3074+
if (err) {
3075+
err = -1;
3076+
goto cleanup;
3077+
}
30483078
}
30493079
if (write_extensions & WRITE_FSMONITOR_EXTENSION &&
30503080
istate->fsmonitor_last_update) {
@@ -3054,12 +3084,25 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
30543084
err = write_index_ext_header(f, eoie_c, CACHE_EXT_FSMONITOR, sb.len) < 0;
30553085
hashwrite(f, sb.buf, sb.len);
30563086
strbuf_release(&sb);
3057-
if (err)
3058-
return -1;
3087+
/*
3088+
* NEEDSWORK: write_index_ext_header() never returns a failure,
3089+
* and this part may want to be simplified.
3090+
*/
3091+
if (err) {
3092+
err = -1;
3093+
goto cleanup;
3094+
}
30593095
}
30603096
if (istate->sparse_index) {
3061-
if (write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0) < 0)
3062-
return -1;
3097+
err = write_index_ext_header(f, eoie_c, CACHE_EXT_SPARSE_DIRECTORIES, 0);
3098+
/*
3099+
* NEEDSWORK: write_index_ext_header() never returns a failure,
3100+
* and this part may want to be simplified.
3101+
*/
3102+
if (err) {
3103+
err = -1;
3104+
goto cleanup;
3105+
}
30633106
}
30643107

30653108
/*
@@ -3075,8 +3118,14 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
30753118
err = write_index_ext_header(f, NULL, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0;
30763119
hashwrite(f, sb.buf, sb.len);
30773120
strbuf_release(&sb);
3078-
if (err)
3079-
return -1;
3121+
/*
3122+
* NEEDSWORK: write_index_ext_header() never returns a failure,
3123+
* and this part may want to be simplified.
3124+
*/
3125+
if (err) {
3126+
err = -1;
3127+
goto cleanup;
3128+
}
30803129
}
30813130

30823131
csum_fsync_flag = 0;
@@ -3085,13 +3134,16 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
30853134

30863135
finalize_hashfile(f, istate->oid.hash, FSYNC_COMPONENT_INDEX,
30873136
CSUM_HASH_IN_STREAM | csum_fsync_flag);
3137+
f = NULL;
30883138

30893139
if (close_tempfile_gently(tempfile)) {
3090-
error(_("could not close '%s'"), get_tempfile_path(tempfile));
3091-
return -1;
3140+
err = error(_("could not close '%s'"), get_tempfile_path(tempfile));
3141+
goto cleanup;
3142+
}
3143+
if (stat(get_tempfile_path(tempfile), &st)) {
3144+
err = error_errno(_("could not stat '%s'"), get_tempfile_path(tempfile));
3145+
goto cleanup;
30923146
}
3093-
if (stat(get_tempfile_path(tempfile), &st))
3094-
return -1;
30953147
istate->timestamp.sec = (unsigned int)st.st_mtime;
30963148
istate->timestamp.nsec = ST_MTIME_NSEC(st);
30973149
trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed);
@@ -3106,6 +3158,11 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
31063158
istate->cache_nr);
31073159

31083160
return 0;
3161+
3162+
cleanup:
3163+
if (f)
3164+
discard_hashfile(f);
3165+
return err;
31093166
}
31103167

31113168
void set_alternate_index_output(const char *name)

t/t2107-update-index-basic.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ test_description='basic update-index tests
55
Tests for command-line parsing and basic operation.
66
'
77

8+
TEST_PASSES_SANITIZE_LEAK=true
89
. ./test-lib.sh
910

1011
test_expect_success 'update-index --nonsense fails' '

0 commit comments

Comments
 (0)