* [PATCH] Fix handle leak in write_tree
@ 2007-04-23 19:49 Alex Riesen
2007-04-24 5:16 ` Junio C Hamano
2007-04-25 22:28 ` Alex Riesen
0 siblings, 2 replies; 7+ messages in thread
From: Alex Riesen @ 2007-04-23 19:49 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
This is a quick and dirty fix for the broken "git cherry-pick -n" on
some broken OS, which does not remove the directory entry after unlink
succeeded(!) if the file is still open somewher.
The entry is left but "protected": no open, no unlink, no stat.
Very annoying.
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
That should be enough to get going, but I have to say that the
interface to lockfiles is really troublesome. Why has the caller close
a handle it didn't open? Especially if there are perfect matches for
the opening function (hold_locked_index) in form of commit and
rollback?
How about something like this (just interface):
struct lock_file
{
struct lock_file *next;
pid_t owner;
int fd;
char on_list;
char filename[PATH_MAX];
};
struct lock_file *open_locked(const char *path, int die_on_error);
struct lock_file *open_index_locked(int die_on_error);
void commit_lock_file(struct lock_file *); /* always assuming .lock */
void rollback_lock_file(struct lock_file *);
builtin-write-tree.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/builtin-write-tree.c b/builtin-write-tree.c
index c88bbd1..d8284b4 100644
--- a/builtin-write-tree.c
+++ b/builtin-write-tree.c
@@ -29,6 +29,7 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
was_valid = cache_tree_fully_valid(active_cache_tree);
+ close(newfd);
if (!was_valid) {
if (cache_tree_update(active_cache_tree,
active_cache, active_nr,
@@ -36,8 +37,10 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
die("git-write-tree: error building trees");
if (0 <= newfd) {
if (!write_cache(newfd, active_cache, active_nr)
- && !close(newfd))
+ && !close(newfd)) {
commit_lock_file(lock_file);
+ newfd = -1;
+ }
}
/* Not being able to write is fine -- we are only interested
* in updating the cache-tree part, and if the next caller
@@ -55,6 +58,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
else
hashcpy(sha1, active_cache_tree->sha1);
+ if (0 <= newfd)
+ close(newfd);
rollback_lock_file(lock_file);
return 0;
--
1.5.1.1.946.gdb75a
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH] Fix handle leak in write_tree
2007-04-23 19:49 [PATCH] Fix handle leak in write_tree Alex Riesen
@ 2007-04-24 5:16 ` Junio C Hamano
2007-04-24 9:30 ` Alex Riesen
2007-04-25 22:28 ` Alex Riesen
1 sibling, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2007-04-24 5:16 UTC (permalink / raw)
To: Alex Riesen; +Cc: git
Alex Riesen <raa.lkml@gmail.com> writes:
> This is a quick and dirty fix for the broken "git cherry-pick -n" on
> some broken OS, which does not remove the directory entry after unlink
> succeeded(!) if the file is still open somewher.
> The entry is left but "protected": no open, no unlink, no stat.
> Very annoying.
>
> Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
> ---
>
> That should be enough to get going, but I have to say that the
> interface to lockfiles is really troublesome. Why has the caller close
> a handle it didn't open? Especially if there are perfect matches for
> the opening function (hold_locked_index) in form of commit and
> rollback?
>
> How about something like this (just interface):
>
> struct lock_file
> {
> struct lock_file *next;
> pid_t owner;
> int fd;
> char on_list;
> char filename[PATH_MAX];
> };
>
> struct lock_file *open_locked(const char *path, int die_on_error);
> struct lock_file *open_index_locked(int die_on_error);
> void commit_lock_file(struct lock_file *); /* always assuming .lock */
> void rollback_lock_file(struct lock_file *);
I agree that making commit and rollback close the file
descriptor and lock holders to use lock->fd for write() makes
more sense, although it is a bit unclear from the above set of
function signatures what your plan on the lifetime rule for
"struct lock_file" is. If it will be linked to the list given
to the atexit() handler and the caller of open_locked() never
frees it, I think I am fine with the interface.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Fix handle leak in write_tree
2007-04-24 5:16 ` Junio C Hamano
@ 2007-04-24 9:30 ` Alex Riesen
2007-04-24 9:33 ` Junio C Hamano
0 siblings, 1 reply; 7+ messages in thread
From: Alex Riesen @ 2007-04-24 9:30 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
On 4/24/07, Junio C Hamano <junkio@cox.net> wrote:
> > How about something like this (just interface):
> >
> > struct lock_file
> > {
> > struct lock_file *next;
> > pid_t owner;
> > int fd;
> > char on_list;
> > char filename[PATH_MAX];
> > };
> >
> > struct lock_file *open_locked(const char *path, int die_on_error);
> > struct lock_file *open_index_locked(int die_on_error);
> > void commit_lock_file(struct lock_file *); /* always assuming .lock */
> > void rollback_lock_file(struct lock_file *);
>
> I agree that making commit and rollback close the file
> descriptor and lock holders to use lock->fd for write() makes
> more sense, although it is a bit unclear from the above set of
> function signatures what your plan on the lifetime rule for
> "struct lock_file" is. If it will be linked to the list given
> to the atexit() handler and the caller of open_locked() never
> frees it, I think I am fine with the interface.
I actually expected the caller to define the lifetime. atexit is not exactly
libification-effort friendly. I could imagine open*locked with an additional
argument for atexit registration, I just don't like the idea (dislike
die_on_error
too). Isn't such kind of resource control _generally_ nicer to implement
in the top levels of a program?
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Fix handle leak in write_tree
2007-04-24 9:30 ` Alex Riesen
@ 2007-04-24 9:33 ` Junio C Hamano
2007-04-25 20:59 ` Alex Riesen
0 siblings, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2007-04-24 9:33 UTC (permalink / raw)
To: Alex Riesen; +Cc: git
"Alex Riesen" <raa.lkml@gmail.com> writes:
> ... Isn't such kind of resource control _generally_ nicer to implement
> in the top levels of a program?
In theory perhaps, but my understanding of our use of atexit()
is to clean them up in situations beyond the control of the top
levels of a program, most notably upon exit on signal.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Fix handle leak in write_tree
2007-04-24 9:33 ` Junio C Hamano
@ 2007-04-25 20:59 ` Alex Riesen
2007-04-25 21:16 ` Junio C Hamano
0 siblings, 1 reply; 7+ messages in thread
From: Alex Riesen @ 2007-04-25 20:59 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Junio C Hamano, Tue, Apr 24, 2007 11:33:48 +0200:
>
> > ... Isn't such kind of resource control _generally_ nicer to implement
> > in the top levels of a program?
>
> In theory perhaps, but my understanding of our use of atexit()
> is to clean them up in situations beyond the control of the top
> levels of a program, most notably upon exit on signal.
>
struct git_context;
/* or whatever is the latest name for the repo bookeeping is.
It have to be passed to every git-related function anyway. */
struct lock_file *open_index_locked(struct git_context *, int die_on_error);
int commit_index_locked(struct git_context *, struct lock_file *);
... and so on.
Then let the top level call something like
git_cleanup(struct git_context *);
in its _own_ signal or atexit handlers. If it didn't setup the
handlers, than perhaps it did want it so (leaving tempfiles behind is
sometimes done on purpose). Or it _is_ a bug, but then it is clear:
you have to cleanup, and you do git's part of cleanup with
git_cleanup.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] Fix handle leak in write_tree
2007-04-25 20:59 ` Alex Riesen
@ 2007-04-25 21:16 ` Junio C Hamano
0 siblings, 0 replies; 7+ messages in thread
From: Junio C Hamano @ 2007-04-25 21:16 UTC (permalink / raw)
To: Alex Riesen; +Cc: git
Alex Riesen <raa.lkml@gmail.com> writes:
> Then let the top level call something like
>
> git_cleanup(struct git_context *);
>
> in its _own_ signal or atexit handlers. If it didn't setup the
> handlers, than perhaps it did want it so (leaving tempfiles behind is
> sometimes done on purpose). Or it _is_ a bug, but then it is clear:
> you have to cleanup, and you do git's part of cleanup with
> git_cleanup.
I would agree that libification would need to go something along
that line.
In the meantime for 1.5.2 stabilization, let's do the minimum
fix of applying your earlier patch.
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] Fix handle leak in write_tree
2007-04-23 19:49 [PATCH] Fix handle leak in write_tree Alex Riesen
2007-04-24 5:16 ` Junio C Hamano
@ 2007-04-25 22:28 ` Alex Riesen
1 sibling, 0 replies; 7+ messages in thread
From: Alex Riesen @ 2007-04-25 22:28 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano
This is a quick and dirty fix for the broken "git cherry-pick -n" on
some broken OS, which does not remove the directory entry after unlink
succeeded(!) if the file is still open somewher.
The entry is left but "protected": no open, no unlink, no stat.
Very annoying.
Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---
Alex Riesen, Mon, Apr 23, 2007 21:49:25 +0200:
> diff --git a/builtin-write-tree.c b/builtin-write-tree.c
> index c88bbd1..d8284b4 100644
> --- a/builtin-write-tree.c
> +++ b/builtin-write-tree.c
> @@ -29,6 +29,7 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
>
> was_valid = cache_tree_fully_valid(active_cache_tree);
>
> + close(newfd);
> if (!was_valid) {
> if (cache_tree_update(active_cache_tree,
> active_cache, active_nr,
BTW, can someone explain this hunk? And how does it manage to
pass the tests?! And HOW did it manage to pass me?!!!
builtin-write-tree.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/builtin-write-tree.c b/builtin-write-tree.c
index c88bbd1..391de53 100644
--- a/builtin-write-tree.c
+++ b/builtin-write-tree.c
@@ -36,8 +36,10 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
die("git-write-tree: error building trees");
if (0 <= newfd) {
if (!write_cache(newfd, active_cache, active_nr)
- && !close(newfd))
+ && !close(newfd)) {
commit_lock_file(lock_file);
+ newfd = -1;
+ }
}
/* Not being able to write is fine -- we are only interested
* in updating the cache-tree part, and if the next caller
@@ -55,6 +57,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
else
hashcpy(sha1, active_cache_tree->sha1);
+ if (0 <= newfd)
+ close(newfd);
rollback_lock_file(lock_file);
return 0;
--
1.5.2.rc0.65.gd296e
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2007-04-25 22:28 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-04-23 19:49 [PATCH] Fix handle leak in write_tree Alex Riesen
2007-04-24 5:16 ` Junio C Hamano
2007-04-24 9:30 ` Alex Riesen
2007-04-24 9:33 ` Junio C Hamano
2007-04-25 20:59 ` Alex Riesen
2007-04-25 21:16 ` Junio C Hamano
2007-04-25 22:28 ` Alex Riesen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).