Re: [PATCH 02/22] try_merge_strategy(): remove redundant lock_file allocation
- From
Michael Haggerty <mhagger@alum.mit.edu>
- Date
- Apr 3, 2014, 12:43 UTC
- Message-ID
- <533D5755.7030609@alum.mit.edu>
- In-Reply-To
- <xmqqy4znwu4g.fsf@gitster.dls.corp.google.com>
On 04/02/2014 06:53 PM, Junio C Hamano wrote:
Show 26 quoted lines
> Jeff King <peff@peff.net> writes: > >> On Tue, Apr 01, 2014 at 05:58:10PM +0200, Michael Haggerty wrote: >> >>> By the time the "if" block is entered, the lock_file instance from the >>> main function block is no longer in use, so re-use that one instead of >>> allocating a second one. >>> >>> Note that the "lock" variable in the "if" block used to shadow the >>> "lock" variable at function scope, so the only change needed is to >>> remove the inner definition. >> >> I wonder if this would also be simpler if "lock" were simply declared as >> a static variable, and we drop the allocation entirely. I suppose that >> does create more cognitive load, though, in that it is only correct if >> the function is not recursive. On the other hand, the current code makes >> a reader unfamiliar with "struct lock" wonder if there is a free(lock) >> missing. > > Another thing that makes a reader wonder if this is a valid rewrite > is if it is safe to reuse a lock_file structure, especially because > the original gives a piece of memory _cleared_ with xcalloc(). The > second invocation of hold_locked_index() is now done on a dirty > piece of memory, and the reader needs to drill down the callchain to > see if that is safe (and if not, hold_locked_index() and probably > the underlying lock_file() needs to memset() it to NULs).
It's good that you and Peff asked questions about this sort of thing.
We reuse lock_file structures *all over the place*; for example, just search for "static struct lock_file". It has to be safe...
...and yet it isn't. Look in the definition of lock_file() (before my changes):
static int lock_file(struct lock_file *lk, const char *path, int flags)
{
...
strcpy(lk->filename, path);
if (!(flags & LOCK_NODEREF))
resolve_symlink(lk->filename, max_path_len);
strcat(lk->filename, ".lock");Remember that a reused lock_file structure is already in lock_file_list, and there is already a signal handler registered that will call remove_lock_file(), which looks like:
static void remove_lock_file(void)
{
pid_t me = getpid(); while (lock_file_list) {
if (lock_file_list->owner == me &&
lock_file_list->filename[0]) {
if (lock_file_list->fd >= 0)
close(lock_file_list->fd);
unlink_or_warn(lock_file_list->filename);
}
lock_file_list = lock_file_list->next;
}
}So, if the process gets a signal during the call to resolve_symlink(), the atexit() cleanup routine will delete the valuable file (the one being locked)!
It definitely looks like this area needs more work.
Michael
-- Michael Haggerty mhagger@alum.mit.edu http://softwareswirl.blogspot.com/