Issue #23524: Replace _PyVerify_fd function with calling _set_thread_local_invalid_parameter_handler on every thread.

This commit is contained in:
Steve Dower 2015-03-06 14:47:02 -08:00
parent eef20de744
commit d81431f587
9 changed files with 160 additions and 112 deletions

View file

@ -1051,99 +1051,16 @@ PyLong_FromPy_off_t(Py_off_t offset)
}
#if defined _MSC_VER && _MSC_VER >= 1400
/* Microsoft CRT in VS2005 and higher will verify that a filehandle is
* valid and raise an assertion if it isn't.
* Normally, an invalid fd is likely to be a C program error and therefore
* an assertion can be useful, but it does contradict the POSIX standard
* which for write(2) states:
* "Otherwise, -1 shall be returned and errno set to indicate the error."
* "[EBADF] The fildes argument is not a valid file descriptor open for
* writing."
* Furthermore, python allows the user to enter any old integer
* as a fd and should merely raise a python exception on error.
* The Microsoft CRT doesn't provide an official way to check for the
* validity of a file descriptor, but we can emulate its internal behaviour
* by using the exported __pinfo data member and knowledge of the
* internal structures involved.
* The structures below must be updated for each version of visual studio
* according to the file internal.h in the CRT source, until MS comes
* up with a less hacky way to do this.
* (all of this is to avoid globally modifying the CRT behaviour using
* _set_invalid_parameter_handler() and _CrtSetReportMode())
#if defined _MSC_VER && _MSC_VER >= 1400 && _MSC_VER < 1900
/* Legacy implementation of _PyVerify_fd_dup2 while transitioning to
* MSVC 14.0. This should eventually be removed. (issue23524)
*/
/* The actual size of the structure is determined at runtime.
* Only the first items must be present.
*/
#if _MSC_VER >= 1900
typedef struct {
CRITICAL_SECTION lock;
intptr_t osfhnd;
__int64 startpos;
char osfile;
} my_ioinfo;
#define IOINFO_L2E 6
#define IOINFO_ARRAYS 128
#else
typedef struct {
intptr_t osfhnd;
char osfile;
} my_ioinfo;
#define IOINFO_L2E 5
#define IOINFO_ARRAYS 64
#endif
extern __declspec(dllimport) char * __pioinfo[];
#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
#define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
#define FOPEN 0x01
#define _NO_CONSOLE_FILENO (intptr_t)-2
/* This function emulates what the windows CRT does to validate file handles */
int
_PyVerify_fd(int fd)
{
const int i1 = fd >> IOINFO_L2E;
const int i2 = fd & ((1 << IOINFO_L2E) - 1);
static size_t sizeof_ioinfo = 0;
/* Determine the actual size of the ioinfo structure,
* as used by the CRT loaded in memory
*/
if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) {
sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS;
}
if (sizeof_ioinfo == 0) {
/* This should not happen... */
goto fail;
}
/* See that it isn't a special CLEAR fileno */
if (fd != _NO_CONSOLE_FILENO) {
/* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that. Instead
* we check pointer validity and other info
*/
if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) {
/* finally, check that the file is open */
my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo);
if (info->osfile & FOPEN) {
return 1;
}
}
}
fail:
errno = EBADF;
return 0;
}
/* the special case of checking dup2. The target fd must be in a sensible range */
static int
_PyVerify_fd_dup2(int fd1, int fd2)
@ -1158,8 +1075,7 @@ _PyVerify_fd_dup2(int fd1, int fd2)
return 0;
}
#else
/* dummy version. _PyVerify_fd() is already defined in fileobject.h */
#define _PyVerify_fd_dup2(A, B) (1)
#define _PyVerify_fd_dup2(fd1, fd2) (_PyVerify_fd(fd1) && (fd2) >= 0)
#endif
#ifdef MS_WINDOWS