[PATCH] Cygwin: open: Do not set tentative fhandler to fdtab (A)
Takashi Yano <[email protected]> Mon, 3 Aug 2026 19:55:09 +0900
| Newsgroups | gmane.os.cygwin.patches |
|---|---|
| Message-ID | <[email protected]> |
Tentative assignment of fhandler to fdtab introduced by the commit
524d75ff7398 ("Cygwin: open: Unlock fdtab before open_with_arch()")
causes the undesired behaviour. The commit intended that fhandler
was just a marker for reservation of fd. However, another cygwin
call may assume that the fd is valid and in use, and may operate on
it.
This patch introduces a flag for fdtab that means the fd is reserved
and cannot be assigned for another open(), etc.
Fixes: 524d75ff7398 ("Cygwin: open: Unlock fdtab before open_with_arch()")
Suggested-by: Johannes Schindelin <[email protected]>
Signed-off-by: Takashi Yano <[email protected]>
Reviewed-by:
---
winsup/cygwin/dtable.cc | 17 ++++++++++++++++-
winsup/cygwin/local_includes/dtable.h | 2 ++
winsup/cygwin/syscalls.cc | 7 ++++---
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e4d1cdf8f..78eb7e3d9 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -73,6 +73,7 @@ dtable::extend (size_t howmuch, size_t min)
{
size_t new_size = size + howmuch;
fhandler_base **newfds;
+ bool *new_reserved;
if (new_size <= OPEN_MAX)
/* ok */;
@@ -93,14 +94,28 @@ dtable::extend (size_t howmuch, size_t min)
set_errno (ENOMEM);
return 0;
}
+ if (!(new_reserved =
+ (bool *) ccalloc (HEAP_ARGV, new_size, sizeof new_reserved[0])))
+ {
+ debug_printf ("calloc failed");
+ set_errno (ENOMEM);
+ cfree (newfds);
+ return 0;
+ }
if (fds)
{
memcpy (newfds, fds, size * sizeof (fds[0]));
cfree (fds);
}
+ if (reserved)
+ {
+ memcpy (new_reserved, reserved, size * sizeof (reserved[0]));
+ cfree (reserved);
+ }
size = new_size;
fds = newfds;
+ reserved = new_reserved;
debug_printf ("size %ld, fds %p", size, fds);
return 1;
}
@@ -233,7 +248,7 @@ dtable::find_unused_handle (size_t start)
do
{
for (size_t i = start; i < size; i++)
- if (fds[i] == NULL)
+ if (fds[i] == NULL && !reserved[i])
{
res = (int) i;
goto out;
diff --git a/winsup/cygwin/local_includes/dtable.h b/winsup/cygwin/local_includes/dtable.h
index 7803fae1b..e3ba48228 100644
--- a/winsup/cygwin/local_includes/dtable.h
+++ b/winsup/cygwin/local_includes/dtable.h
@@ -21,6 +21,7 @@ class dtable
{
fhandler_base **fds;
fhandler_base **archetypes;
+ bool *reserved;
unsigned narchetypes;
unsigned farchetype;
static const int initial_archetype_size = 8;
@@ -76,6 +77,7 @@ public:
void fixup_before_fork (DWORD win_proc_id);
void lock () {lock_process::locker.acquire ();}
void unlock () {lock_process::locker.release ();}
+ bool &reserve (int fd) { return reserved[fd]; }
};
fhandler_base *build_fh_dev (const device&, const char * = NULL);
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 5465d6c09..1d5e258dd 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1558,8 +1558,8 @@ open (const char *unix_path, int flags, ...)
cygheap->fdtab.unlock ();
__leave; /* errno already set */
}
- cygheap->fdtab[fd] = fh; /* tentative setting to mark as used */
- cygheap->fdtab.unlock();
+ cygheap->fdtab.reserve (fd) = true;
+ cygheap->fdtab.unlock ();
if (fh->dev () == FH_PROCESSFD && fh->pc.follow_fd_symlink ())
{
@@ -1590,6 +1590,7 @@ open (const char *unix_path, int flags, ...)
cygheap->fdtab.lock ();
cygheap->fdtab[fd] = fh;
fh->inc_refcnt ();
+ cygheap->fdtab.reserve (fd) = false;
cygheap->fdtab.unlock ();
if (fd <= 2)
@@ -1601,7 +1602,7 @@ open (const char *unix_path, int flags, ...)
if (res < 0 && fd >= 0)
{
cygheap->fdtab.lock ();
- cygheap->fdtab[fd] = NULL; /* Mark as unused */
+ cygheap->fdtab.reserve (fd) = false;
cygheap->fdtab.unlock ();
}
if (res < 0 && fh)
--
2.51.0