Otherwise, a deadlock can occur if the child process attempts to lock a file while the parent process is closing the same file, which is already locked. The deadlock mechanism is as follows.
When the child process attempts to lock a file, it notifies the parent process by calling CreateRemoteThread(), which creates a remote thread in the parent. That thread checks whether the file being locked is currently opened in the parent. During the operation, cygheap->fdtab is temporarily locked in order to enumerate the file descriptors. However, if the parent process is closing the same file at that moment, it also locks fdtab via cygheap_fdget cfd(fd, true) in __close(). If the parent acquires th fdtab lock first, it proceeds to call del_my_locks(), which attempts to lock the inode in inode_t:get(). At this point, the inode is already locked in the child, so the parent waits for the child to release the inode. Meanwhile, the child is waiting to acquire the fdtab lock, which is still held by the parent. As a result, the parent and child become deadlocked. There are two options to fix the deadlock: eather avoid locking fdtab in __close(), or avoid locking fdtab in create_lock_in_parent(). The latter is safer than the former because __close() calls release(), which modifies the fdtab contents, while cygheap_fdenum only reads them. Therefore, to resolve the issue, this patch removes the fdtab lock from create_lock_in_parent(). Addresses: https://cygwin.com/pipermail/cygwin/2025-December/259187.html Fixes: df63bd490a52 ("* cygheap.h (cygheap_fdmanip): New class: simplifies locking and retrieval of fds from cygheap->fdtab.") Reported-by: Nahor <[email protected]> Reviewed-by: Corinna Vinschen <[email protected]> Signed-off-by: Takashi Yano <[email protected]> --- winsup/cygwin/flock.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winsup/cygwin/flock.cc b/winsup/cygwin/flock.cc index ee79af3c9..221501d65 100644 --- a/winsup/cygwin/flock.cc +++ b/winsup/cygwin/flock.cc @@ -692,7 +692,7 @@ create_lock_in_parent (PVOID param) /* Check if we have an open file handle with the same unique id. */ { cnt = 0; - cygheap_fdenum cfd (true); + cygheap_fdenum cfd (false); while (cfd.next () >= 0) if (cfd->get_unique_id () == newlock.lf_id && ++cnt > 0) break; -- 2.51.0
