Commit 78ee805
committed
tmp-objdir: do not opendir() when handling a signal
In the tmp-objdir api, tmp_objdir_create will create a temporary
directory but also register signal handlers responsible for removing
the directory's contents and the directory itself. However, the
function responsible for recursively removing the contents and
directory, remove_dir_recurse() calls opendir(3) and closedir(3).
This can be problematic because these functions allocate and free
memory, which are not async-signal-safe functions. This can lead to
deadlocks.
One place we call tmp_objdir_create() is in git-receive-pack, where
we create a temporary quarantine directory "incoming". Incoming
objects will be written to this directory before they get moved to
the object directory.
We have observed this code leading to a deadlock:
Thread 1 (Thread 0x7f621ba0b200 (LWP 326305)):
#0 __lll_lock_wait_private (futex=futex@entry=0x7f621bbf8b80
<main_arena>) at ./lowlevellock.c:35
#1 0x00007f621baa635b in __GI___libc_malloc
(bytes=bytes@entry=32816) at malloc.c:3064
#2 0x00007f621bae9f49 in __alloc_dir (statp=0x7fff2ea7ed60,
flags=0, close_fd=true, fd=5)
at ../sysdeps/posix/opendir.c:118
#3 opendir_tail (fd=5) at ../sysdeps/posix/opendir.c:69
#4 __opendir (name=<optimized out>)
at ../sysdeps/posix/opendir.c:92
#5 0x0000557c19c77de1 in remove_dir_recurse ()
git#6 0x0000557c19d81a4f in remove_tmp_objdir_on_signal ()
#7 <signal handler called>
git#8 _int_malloc (av=av@entry=0x7f621bbf8b80 <main_arena>,
bytes=bytes@entry=7160) at malloc.c:4116
git#9 0x00007f621baa62c9 in __GI___libc_malloc (bytes=7160)
at malloc.c:3066
git#10 0x00007f621bd1e987 in inflateInit2_ ()
from /opt/gitlab/embedded/lib/libz.so.1
git#11 0x0000557c19dbe5f4 in git_inflate_init ()
git#12 0x0000557c19cee02a in unpack_compressed_entry ()
git#13 0x0000557c19cf08cb in unpack_entry ()
git#14 0x0000557c19cf0f32 in packed_object_info ()
git#15 0x0000557c19cd68cd in do_oid_object_info_extended ()
git#16 0x0000557c19cd6e2b in read_object_file_extended ()
git#17 0x0000557c19cdec2f in parse_object ()
git#18 0x0000557c19c34977 in lookup_commit_reference_gently ()
git#19 0x0000557c19d69309 in mark_uninteresting ()
git#20 0x0000557c19d2d180 in do_for_each_repo_ref_iterator ()
git#21 0x0000557c19d21678 in for_each_ref ()
git#22 0x0000557c19d6a94f in assign_shallow_commits_to_refs ()
git#23 0x0000557c19bc02b2 in cmd_receive_pack ()
git#24 0x0000557c19b29fdd in handle_builtin ()
git#25 0x0000557c19b2a526 in cmd_main ()
git#26 0x0000557c19b28ea2 in main ()
To prevent this, add a flag REMOVE_DIR_SIGNAL that allows
remove_dir_recurse() to know that a signal is being handled and avoid
calling opendir(3). One implication of this change is that when
signal handling, the temporary directory may not get cleaned up
properly.
Signed-off-by: John Cai <[email protected]>1 parent 4fd6c5e commit 78ee805
3 files changed
+14
-3
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3244 | 3244 | | |
3245 | 3245 | | |
3246 | 3246 | | |
3247 | | - | |
| 3247 | + | |
3248 | 3248 | | |
3249 | 3249 | | |
3250 | 3250 | | |
| |||
3261 | 3261 | | |
3262 | 3262 | | |
3263 | 3263 | | |
3264 | | - | |
| 3264 | + | |
| 3265 | + | |
| 3266 | + | |
| 3267 | + | |
3265 | 3268 | | |
3266 | 3269 | | |
3267 | 3270 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
498 | 498 | | |
499 | 499 | | |
500 | 500 | | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
501 | 504 | | |
502 | 505 | | |
503 | 506 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
37 | 38 | | |
38 | 39 | | |
39 | 40 | | |
| |||
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
52 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
53 | 58 | | |
54 | 59 | | |
55 | 60 | | |
| |||
0 commit comments