Skip to content

Commit 89563ec

Browse files
committed
Merge branch 'jk/incore-lockfile-removal'
The long-standing rule that an in-core lockfile instance, once it is used, must not be freed, has been lifted and the lockfile and tempfile APIs have been updated to reduce the chance of programming errors. * jk/incore-lockfile-removal: stop leaking lock structs in some simple cases ref_lock: stop leaking lock_files lockfile: update lifetime requirements in documentation tempfile: auto-allocate tempfiles on heap tempfile: remove deactivated list entries tempfile: use list.h for linked list tempfile: release deactivated strbufs instead of resetting tempfile: robustify cleanup handler tempfile: factor out deactivation tempfile: factor out activation tempfile: replace die("BUG") with BUG() tempfile: handle NULL tempfile pointers gracefully tempfile: prefer is_tempfile_active to bare access lockfile: do not rollback lock on failed close tempfile: do not delete tempfile on failed close always check return value of close_tempfile verify_signed_buffer: prefer close_tempfile() to close() setup_temporary_shallow: move tempfile struct into function setup_temporary_shallow: avoid using inactive tempfile write_index_as_tree: cleanup tempfile on error
2 parents 8a044c7 + bfffb48 commit 89563ec

18 files changed

Lines changed: 352 additions & 324 deletions

builtin/gc.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ static struct argv_array prune = ARGV_ARRAY_INIT;
4747
static struct argv_array prune_worktrees = ARGV_ARRAY_INIT;
4848
static struct argv_array rerere = ARGV_ARRAY_INIT;
4949

50-
static struct tempfile pidfile;
50+
static struct tempfile *pidfile;
5151
static struct lock_file log_lock;
5252

5353
static struct string_list pack_garbage = STRING_LIST_INIT_DUP;
@@ -78,7 +78,7 @@ static void process_log_file(void)
7878
*/
7979
int saved_errno = errno;
8080
fprintf(stderr, _("Failed to fstat %s: %s"),
81-
get_tempfile_path(&log_lock.tempfile),
81+
get_tempfile_path(log_lock.tempfile),
8282
strerror(saved_errno));
8383
fflush(stderr);
8484
commit_lock_file(&log_lock);
@@ -242,7 +242,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
242242
int fd;
243243
char *pidfile_path;
244244

245-
if (is_tempfile_active(&pidfile))
245+
if (is_tempfile_active(pidfile))
246246
/* already locked */
247247
return NULL;
248248

@@ -293,7 +293,7 @@ static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
293293
write_in_full(fd, sb.buf, sb.len);
294294
strbuf_release(&sb);
295295
commit_lock_file(&lock);
296-
register_tempfile(&pidfile, pidfile_path);
296+
pidfile = register_tempfile(pidfile_path);
297297
free(pidfile_path);
298298
return NULL;
299299
}

builtin/reset.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,8 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
367367
die_if_unmerged_cache(reset_type);
368368

369369
if (reset_type != SOFT) {
370-
struct lock_file *lock = xcalloc(1, sizeof(*lock));
371-
hold_locked_index(lock, LOCK_DIE_ON_ERROR);
370+
struct lock_file lock = LOCK_INIT;
371+
hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
372372
if (reset_type == MIXED) {
373373
int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
374374
if (read_from_tree(&pathspec, &oid, intent_to_add))
@@ -384,7 +384,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
384384
die(_("Could not reset index file to revision '%s'."), rev);
385385
}
386386

387-
if (write_locked_index(&the_index, lock, COMMIT_LOCK))
387+
if (write_locked_index(&the_index, &lock, COMMIT_LOCK))
388388
die(_("Could not write new index file."));
389389
}
390390

builtin/update-index.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
915915
struct refresh_params refresh_args = {0, &has_errors};
916916
int lock_error = 0;
917917
int split_index = -1;
918-
struct lock_file *lock_file;
918+
struct lock_file lock_file = LOCK_INIT;
919919
struct parse_opt_ctx_t ctx;
920920
strbuf_getline_fn getline_fn;
921921
int parseopt_state = PARSE_OPT_UNKNOWN;
@@ -1014,11 +1014,8 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
10141014

10151015
git_config(git_default_config, NULL);
10161016

1017-
/* We can't free this memory, it becomes part of a linked list parsed atexit() */
1018-
lock_file = xcalloc(1, sizeof(struct lock_file));
1019-
10201017
/* we will diagnose later if it turns out that we need to update it */
1021-
newfd = hold_locked_index(lock_file, 0);
1018+
newfd = hold_locked_index(&lock_file, 0);
10221019
if (newfd < 0)
10231020
lock_error = errno;
10241021

@@ -1153,11 +1150,11 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
11531150
exit(128);
11541151
unable_to_lock_die(get_index_file(), lock_error);
11551152
}
1156-
if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
1153+
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
11571154
die("Unable to write new index file");
11581155
}
11591156

1160-
rollback_lock_file(lock_file);
1157+
rollback_lock_file(&lock_file);
11611158

11621159
return has_errors ? 1 : 0;
11631160
}

cache-tree.c

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -603,19 +603,16 @@ static struct cache_tree *cache_tree_find(struct cache_tree *it, const char *pat
603603
int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
604604
{
605605
int entries, was_valid, newfd;
606-
struct lock_file *lock_file;
606+
struct lock_file lock_file = LOCK_INIT;
607+
int ret = 0;
607608

608-
/*
609-
* We can't free this memory, it becomes part of a linked list
610-
* parsed atexit()
611-
*/
612-
lock_file = xcalloc(1, sizeof(struct lock_file));
613-
614-
newfd = hold_lock_file_for_update(lock_file, index_path, LOCK_DIE_ON_ERROR);
609+
newfd = hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
615610

616611
entries = read_index_from(index_state, index_path);
617-
if (entries < 0)
618-
return WRITE_TREE_UNREADABLE_INDEX;
612+
if (entries < 0) {
613+
ret = WRITE_TREE_UNREADABLE_INDEX;
614+
goto out;
615+
}
619616
if (flags & WRITE_TREE_IGNORE_CACHE_TREE)
620617
cache_tree_free(&index_state->cache_tree);
621618

@@ -624,10 +621,12 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
624621

625622
was_valid = cache_tree_fully_valid(index_state->cache_tree);
626623
if (!was_valid) {
627-
if (cache_tree_update(index_state, flags) < 0)
628-
return WRITE_TREE_UNMERGED_INDEX;
624+
if (cache_tree_update(index_state, flags) < 0) {
625+
ret = WRITE_TREE_UNMERGED_INDEX;
626+
goto out;
627+
}
629628
if (0 <= newfd) {
630-
if (!write_locked_index(index_state, lock_file, COMMIT_LOCK))
629+
if (!write_locked_index(index_state, &lock_file, COMMIT_LOCK))
631630
newfd = -1;
632631
}
633632
/* Not being able to write is fine -- we are only interested
@@ -641,17 +640,19 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
641640
if (prefix) {
642641
struct cache_tree *subtree;
643642
subtree = cache_tree_find(index_state->cache_tree, prefix);
644-
if (!subtree)
645-
return WRITE_TREE_PREFIX_ERROR;
643+
if (!subtree) {
644+
ret = WRITE_TREE_PREFIX_ERROR;
645+
goto out;
646+
}
646647
hashcpy(sha1, subtree->oid.hash);
647648
}
648649
else
649650
hashcpy(sha1, index_state->cache_tree->oid.hash);
650651

652+
out:
651653
if (0 <= newfd)
652-
rollback_lock_file(lock_file);
653-
654-
return 0;
654+
rollback_lock_file(&lock_file);
655+
return ret;
655656
}
656657

657658
int write_cache_as_tree(unsigned char *sha1, int flags, const char *prefix)

config.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2450,7 +2450,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
24502450
{
24512451
int fd = -1, in_fd = -1;
24522452
int ret;
2453-
static struct lock_file lock;
2453+
struct lock_file lock = LOCK_INIT;
24542454
char *filename_buf = NULL;
24552455
char *contents = NULL;
24562456
size_t contents_sz;

credential-cache--daemon.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
#include "unix-socket.h"
66
#include "parse-options.h"
77

8-
static struct tempfile socket_file;
9-
108
struct credential_cache_entry {
119
struct credential item;
1210
timestamp_t expiration;
@@ -260,6 +258,7 @@ static void init_socket_directory(const char *path)
260258

261259
int cmd_main(int argc, const char **argv)
262260
{
261+
struct tempfile *socket_file;
263262
const char *socket_path;
264263
int ignore_sighup = 0;
265264
static const char *usage[] = {
@@ -285,7 +284,7 @@ int cmd_main(int argc, const char **argv)
285284
die("socket directory must be an absolute path");
286285

287286
init_socket_directory(socket_path);
288-
register_tempfile(&socket_file, socket_path);
287+
socket_file = register_tempfile(socket_path);
289288

290289
if (ignore_sighup)
291290
signal(SIGHUP, SIG_IGN);

diff.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ static struct diff_tempfile {
459459
* If this diff_tempfile instance refers to a temporary file,
460460
* this tempfile object is used to manage its lifetime.
461461
*/
462-
struct tempfile tempfile;
462+
struct tempfile *tempfile;
463463
} diff_temp[2];
464464

465465
struct emit_callback {
@@ -1414,7 +1414,7 @@ static void remove_tempfile(void)
14141414
{
14151415
int i;
14161416
for (i = 0; i < ARRAY_SIZE(diff_temp); i++) {
1417-
if (is_tempfile_active(&diff_temp[i].tempfile))
1417+
if (is_tempfile_active(diff_temp[i].tempfile))
14181418
delete_tempfile(&diff_temp[i].tempfile);
14191419
diff_temp[i].name = NULL;
14201420
}
@@ -3720,7 +3720,6 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
37203720
const struct object_id *oid,
37213721
int mode)
37223722
{
3723-
int fd;
37243723
struct strbuf buf = STRBUF_INIT;
37253724
struct strbuf template = STRBUF_INIT;
37263725
char *path_dup = xstrdup(path);
@@ -3730,18 +3729,18 @@ static void prep_temp_blob(const char *path, struct diff_tempfile *temp,
37303729
strbuf_addstr(&template, "XXXXXX_");
37313730
strbuf_addstr(&template, base);
37323731

3733-
fd = mks_tempfile_ts(&temp->tempfile, template.buf, strlen(base) + 1);
3734-
if (fd < 0)
3732+
temp->tempfile = mks_tempfile_ts(template.buf, strlen(base) + 1);
3733+
if (!temp->tempfile)
37353734
die_errno("unable to create temp-file");
37363735
if (convert_to_working_tree(path,
37373736
(const char *)blob, (size_t)size, &buf)) {
37383737
blob = buf.buf;
37393738
size = buf.len;
37403739
}
3741-
if (write_in_full(fd, blob, size) != size)
3740+
if (write_in_full(temp->tempfile->fd, blob, size) != size ||
3741+
close_tempfile_gently(temp->tempfile))
37423742
die_errno("unable to write temp-file");
3743-
close_tempfile(&temp->tempfile);
3744-
temp->name = get_tempfile_path(&temp->tempfile);
3743+
temp->name = get_tempfile_path(temp->tempfile);
37453744
oid_to_hex_r(temp->hex, oid);
37463745
xsnprintf(temp->mode, sizeof(temp->mode), "%06o", mode);
37473746
strbuf_release(&buf);

gpg-interface.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -202,26 +202,26 @@ int verify_signed_buffer(const char *payload, size_t payload_size,
202202
struct strbuf *gpg_output, struct strbuf *gpg_status)
203203
{
204204
struct child_process gpg = CHILD_PROCESS_INIT;
205-
static struct tempfile temp;
206-
int fd, ret;
205+
struct tempfile *temp;
206+
int ret;
207207
struct strbuf buf = STRBUF_INIT;
208208

209-
fd = mks_tempfile_t(&temp, ".git_vtag_tmpXXXXXX");
210-
if (fd < 0)
209+
temp = mks_tempfile_t(".git_vtag_tmpXXXXXX");
210+
if (!temp)
211211
return error_errno(_("could not create temporary file"));
212-
if (write_in_full(fd, signature, signature_size) < 0) {
212+
if (write_in_full(temp->fd, signature, signature_size) < 0 ||
213+
close_tempfile_gently(temp) < 0) {
213214
error_errno(_("failed writing detached signature to '%s'"),
214-
temp.filename.buf);
215+
temp->filename.buf);
215216
delete_tempfile(&temp);
216217
return -1;
217218
}
218-
close(fd);
219219

220220
argv_array_pushl(&gpg.args,
221221
gpg_program,
222222
"--status-fd=1",
223223
"--keyid-format=long",
224-
"--verify", temp.filename.buf, "-",
224+
"--verify", temp->filename.buf, "-",
225225
NULL);
226226

227227
if (!gpg_status)

list.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,42 @@ static inline void list_replace_init(struct list_head *old,
163163
INIT_LIST_HEAD(old);
164164
}
165165

166+
/*
167+
* This is exactly the same as a normal list_head, except that it can be
168+
* declared volatile (e.g., if you have a list that may be accessed from signal
169+
* handlers).
170+
*/
171+
struct volatile_list_head {
172+
volatile struct volatile_list_head *next, *prev;
173+
};
174+
175+
#define VOLATILE_LIST_HEAD(name) \
176+
volatile struct volatile_list_head name = { &(name), &(name) }
177+
178+
static inline void __volatile_list_del(volatile struct volatile_list_head *prev,
179+
volatile struct volatile_list_head *next)
180+
{
181+
next->prev = prev;
182+
prev->next = next;
183+
}
184+
185+
static inline void volatile_list_del(volatile struct volatile_list_head *elem)
186+
{
187+
__volatile_list_del(elem->prev, elem->next);
188+
}
189+
190+
static inline int volatile_list_empty(volatile struct volatile_list_head *head)
191+
{
192+
return head == head->next;
193+
}
194+
195+
static inline void volatile_list_add(volatile struct volatile_list_head *newp,
196+
volatile struct volatile_list_head *head)
197+
{
198+
head->next->prev = newp;
199+
newp->next = head->next;
200+
newp->prev = head;
201+
head->next = newp;
202+
}
203+
166204
#endif /* LIST_H */

lockfile.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,16 @@ static void resolve_symlink(struct strbuf *path)
7272
/* Make sure errno contains a meaningful value on error */
7373
static int lock_file(struct lock_file *lk, const char *path, int flags)
7474
{
75-
int fd;
7675
struct strbuf filename = STRBUF_INIT;
7776

7877
strbuf_addstr(&filename, path);
7978
if (!(flags & LOCK_NO_DEREF))
8079
resolve_symlink(&filename);
8180

8281
strbuf_addstr(&filename, LOCK_SUFFIX);
83-
fd = create_tempfile(&lk->tempfile, filename.buf);
82+
lk->tempfile = create_tempfile(filename.buf);
8483
strbuf_release(&filename);
85-
return fd;
84+
return lk->tempfile ? lk->tempfile->fd : -1;
8685
}
8786

8887
/*
@@ -191,7 +190,7 @@ char *get_locked_file_path(struct lock_file *lk)
191190
{
192191
struct strbuf ret = STRBUF_INIT;
193192

194-
strbuf_addstr(&ret, get_tempfile_path(&lk->tempfile));
193+
strbuf_addstr(&ret, get_tempfile_path(lk->tempfile));
195194
if (ret.len <= LOCK_SUFFIX_LEN ||
196195
strcmp(ret.buf + ret.len - LOCK_SUFFIX_LEN, LOCK_SUFFIX))
197196
die("BUG: get_locked_file_path() called for malformed lock object");

0 commit comments

Comments
 (0)