[PATCH v2] Cygwin: open: Do not set tentative fhandler to fdtab
Takashi Yano <[email protected]>
| 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 special value ((fhandler_base *) -1) for
fdtab that marks the fd as reserved and means it 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: Johannes Schindelin <[email protected]>
---
winsup/cygwin/dtable.cc | 29 ++++++++++++-----------
winsup/cygwin/local_includes/cygheap.h | 6 ++---
winsup/cygwin/local_includes/dtable.h | 32 ++++++++++++++++++++++++--
winsup/cygwin/syscalls.cc | 13 +++++++----
4 files changed, 57 insertions(+), 23 deletions(-)
diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc
index e4d1cdf8f..7a4fd7dca 100644
--- a/winsup/cygwin/dtable.cc
+++ b/winsup/cygwin/dtable.cc
@@ -13,6 +13,7 @@ details. */
#include <stdio.h>
#include <unistd.h>
#include <wchar.h>
+#include <assert.h>
#define USE_SYS_TYPES_FD_SET
#include <winsock.h>
@@ -123,7 +124,7 @@ dtable::get_debugger_info ()
fhandler_base *fh = build_fh_name (std[i]);
if (!fh)
continue;
- fds[i] = fh;
+ fds.set_fhandler (i, fh);
if (!fh->open ((i ? (i == 2 ? O_RDWR : O_WRONLY) : O_RDONLY)
| O_BINARY, 0777))
release (i);
@@ -233,7 +234,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 && !fds.reserved (i))
{
res = (int) i;
goto out;
@@ -249,8 +250,9 @@ dtable::release (int fd)
{
if (fds[fd]->need_fixup_before ())
dec_need_fixup_before ();
+ assert (fds[fd]);
fds[fd]->dec_refcnt ();
- fds[fd] = NULL;
+ fds.set_fhandler (fd, NULL);
if (fd <= 2)
set_std_handle (fd);
}
@@ -263,11 +265,12 @@ cygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin,
if (fd == -1)
fd = cygheap->fdtab.find_unused_handle ();
fhandler_base *fh = build_fh_name (name);
- if (!fh)
+ if (!fh || cygheap->fdtab.reserved (fd))
fd = -1;
else
{
- cygheap->fdtab[fd] = fh;
+ cygheap->fdtab.set_fhandler (fd, fh);
+ assert (cygheap->fdtab[fd]);
cygheap->fdtab[fd]->inc_refcnt ();
fh->init (handle, myaccess, bin ?: fh->pc_binmode ());
}
@@ -348,7 +351,7 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
handle_to_fn (handle, name);
if (!name[0] && !dev)
- fds[fd] = NULL;
+ fds.set_fhandler (fd, NULL);
else
{
fhandler_base *fh;
@@ -425,7 +428,8 @@ dtable::init_std_file_from_handle (int fd, HANDLE handle)
if (!fh->open_setup (openflags))
api_fatal ("open_setup failed, %E");
fh->usecount = 0;
- cygheap->fdtab[fd] = fh;
+ cygheap->fdtab.set_fhandler (fd, fh);
+ assert (cygheap->fdtab[fd]);
cygheap->fdtab[fd]->inc_refcnt ();
set_std_handle (fd);
paranoid_printf ("fd %d, handle %p", fd, handle);
@@ -795,16 +799,15 @@ dtable::dup3 (int oldfd, int newfd, int flags)
if (!not_open (newfd))
close (newfd);
- else if ((size_t) newfd >= size
- && find_unused_handle (newfd) < 0)
+ else if (((size_t) newfd >= size && find_unused_handle (newfd) < 0)
+ || reserved (newfd))
/* couldn't extend fdtab */
{
newfh->close ();
res = -1;
goto done;
}
-
- fds[newfd] = newfh;
+ fds.set_fhandler (newfd, newfh);
if ((res = newfd) <= 2)
set_std_handle (res);
@@ -874,8 +877,8 @@ void
dtable::move_fd (int from, int to)
{
// close (to); /* It is assumed that this is close-on-exec */
- fds[to] = fds[from];
- fds[from] = NULL;
+ fds.set_fhandler (to, fds[from]);
+ fds.set_fhandler (from, NULL);
}
void
diff --git a/winsup/cygwin/local_includes/cygheap.h b/winsup/cygwin/local_includes/cygheap.h
index 74cfff652..db740f03d 100644
--- a/winsup/cygwin/local_includes/cygheap.h
+++ b/winsup/cygwin/local_includes/cygheap.h
@@ -569,10 +569,10 @@ class cygheap_fdmanip
}
virtual void release () { cygheap->fdtab.release (fd); }
operator int &() {return fd;}
- operator fhandler_base* &() {return cygheap->fdtab[fd];}
+ operator fhandler_base* () {return cygheap->fdtab[fd];}
operator fhandler_socket* () const {return reinterpret_cast<fhandler_socket *> (cygheap->fdtab[fd]);}
operator fhandler_pipe* () const {return reinterpret_cast<fhandler_pipe *> (cygheap->fdtab[fd]);}
- void operator = (fhandler_base *fh) {cygheap->fdtab[fd] = fh;}
+ void operator = (fhandler_base *fh) {cygheap->fdtab.set_fhandler (fd, fh);}
fhandler_base *operator -> () const {return cygheap->fdtab[fd];}
bool isopen () const
{
@@ -609,7 +609,7 @@ class cygheap_fdnew : public cygheap_fdmanip
if (cygheap->fdtab[fd])
cygheap->fdtab[fd]->inc_refcnt ();
}
- void operator = (fhandler_base *fh) {cygheap->fdtab[fd] = fh;}
+ void operator = (fhandler_base *fh) {cygheap->fdtab.set_fhandler (fd, fh);}
};
class cygheap_fdget : public cygheap_fdmanip
diff --git a/winsup/cygwin/local_includes/dtable.h b/winsup/cygwin/local_includes/dtable.h
index 7803fae1b..89c776c2d 100644
--- a/winsup/cygwin/local_includes/dtable.h
+++ b/winsup/cygwin/local_includes/dtable.h
@@ -17,9 +17,30 @@ details. */
class suffix_info;
#define BFH_OPTS (PC_NULLEMPTY | PC_FULL | PC_POSIX)
+#define FDTAB_RESERVED ((fhandler_base *) -1)
class dtable
{
- fhandler_base **fds;
+ class dtable_fds
+ {
+ fhandler_base **fds;
+ public:
+ inline void set_fhandler (int fd, fhandler_base *fh) {fds[fd] = fh;}
+ inline fhandler_base *operator [](int fd) const
+ {
+ fhandler_base *fh = fds[fd];
+ return (fh == FDTAB_RESERVED) ? NULL : fh;
+ }
+ operator fhandler_base **() {return fds;}
+ void operator = (fhandler_base **ptr) {fds = ptr;}
+ inline void reserve (int fd) { fds[fd] = FDTAB_RESERVED; }
+ inline void unreserve (int fd)
+ {
+ if (fds[fd] == FDTAB_RESERVED)
+ fds[fd] = NULL;
+ }
+ inline bool reserved (int fd) { return fds[fd] == FDTAB_RESERVED; }
+ };
+ dtable_fds fds;
fhandler_base **archetypes;
unsigned narchetypes;
unsigned farchetype;
@@ -61,7 +82,11 @@ public:
void init_std_file_from_handle (int fd, HANDLE handle);
int dup3 (int oldfd, int newfd, int flags);
void fixup_after_exec ();
- inline fhandler_base *&operator [](int fd) const { return fds[fd]; }
+ inline void set_fhandler (int fd, fhandler_base *fh)
+ {
+ fds.set_fhandler (fd, fh);
+ }
+ inline fhandler_base *operator [](int fd) const { return fds[fd]; }
bool select_read (int fd, select_stuff *);
bool select_write (int fd, select_stuff *);
bool select_except (int fd, select_stuff *);
@@ -76,6 +101,9 @@ public:
void fixup_before_fork (DWORD win_proc_id);
void lock () {lock_process::locker.acquire ();}
void unlock () {lock_process::locker.release ();}
+ inline void reserve (int fd) { fds.reserve (fd); }
+ inline void unreserve (int fd) { fds.unreserve (fd); }
+ inline bool reserved (int fd) { return fds.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..5ca02c0a1 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -24,6 +24,7 @@ details. */
#include <dirent.h>
#include <ntsecapi.h>
#include <iptypes.h>
+#include <assert.h>
#include "ntdll.h"
#include <cygwin/version.h>
@@ -146,7 +147,9 @@ dup_finish (int oldfd, int newfd, int flags)
int res;
if ((res = cygheap->fdtab.dup3 (oldfd, newfd, flags | O_EXCL)) == newfd)
{
- cygheap_fdget (newfd)->inc_refcnt ();
+ cygheap_fdget cfd (newfd);
+ assert ((fhandler_base *) cfd);
+ cfd->inc_refcnt ();
cygheap->fdtab.unlock (); /* dup3 exits with lock set on success */
}
return res;
@@ -1558,8 +1561,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);
+ cygheap->fdtab.unlock ();
if (fh->dev () == FH_PROCESSFD && fh->pc.follow_fd_symlink ())
{
@@ -1588,7 +1591,7 @@ open (const char *unix_path, int flags, ...)
FILE_OPEN_FOR_BACKUP_INTENT);
cygheap->fdtab.lock ();
- cygheap->fdtab[fd] = fh;
+ cygheap->fdtab.set_fhandler (fd, fh);
fh->inc_refcnt ();
cygheap->fdtab.unlock ();
@@ -1601,7 +1604,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.unreserve (fd);
cygheap->fdtab.unlock ();
}
if (res < 0 && fh)
--
2.51.0