diff options
author | Steve Dower <steve.dower@microsoft.com> | 2015-03-06 22:47:02 (GMT) |
---|---|---|
committer | Steve Dower <steve.dower@microsoft.com> | 2015-03-06 22:47:02 (GMT) |
commit | d81431f587e9eab67db683908548b0ad46847b38 (patch) | |
tree | 69bbc1cdda06acab523871f322982b00931a3675 /Python | |
parent | eef20de744cfdf971d5a80d6e3f9c7f7cb9e14fc (diff) | |
download | cpython-d81431f587e9eab67db683908548b0ad46847b38.zip cpython-d81431f587e9eab67db683908548b0ad46847b38.tar.gz cpython-d81431f587e9eab67db683908548b0ad46847b38.tar.bz2 |
Issue #23524: Replace _PyVerify_fd function with calling _set_thread_local_invalid_parameter_handler on every thread.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/fileutils.c | 108 | ||||
-rw-r--r-- | Python/pystate.c | 11 |
2 files changed, 114 insertions, 5 deletions
diff --git a/Python/fileutils.c b/Python/fileutils.c index e7111c1..c0dbc86 100644 --- a/Python/fileutils.c +++ b/Python/fileutils.c @@ -3,6 +3,7 @@ #include <locale.h> #ifdef MS_WINDOWS +# include <malloc.h> # include <windows.h> #endif @@ -636,14 +637,10 @@ _Py_fstat(int fd, struct _Py_stat_struct *result) else h = (HANDLE)_get_osfhandle(fd); - /* Protocol violation: we explicitly clear errno, instead of - setting it to a POSIX error. Callers should use GetLastError. */ errno = 0; if (h == INVALID_HANDLE_VALUE) { - /* This is really a C library error (invalid file handle). - We set the Win32 error to the closes one matching. */ - SetLastError(ERROR_INVALID_HANDLE); + errno = EBADF; return -1; } memset(result, 0, sizeof(*result)); @@ -652,6 +649,7 @@ _Py_fstat(int fd, struct _Py_stat_struct *result) if (type == FILE_TYPE_UNKNOWN) { DWORD error = GetLastError(); if (error != 0) { + errno = EINVAL; return -1; } /* else: valid but unknown file */ @@ -666,6 +664,7 @@ _Py_fstat(int fd, struct _Py_stat_struct *result) } if (!GetFileInformationByHandle(h, &info)) { + errno = EINVAL; return -1; } @@ -1267,3 +1266,102 @@ error: } #endif +#ifdef _MSC_VER +#if _MSC_VER >= 1900 + +/* This function lets the Windows CRT validate the file handle without + terminating the process if it's invalid. */ +int +_PyVerify_fd(int fd) +{ + intptr_t osh; + /* Fast check for the only condition we know */ + if (fd < 0) { + _set_errno(EBADF); + return 0; + } + osh = _get_osfhandle(fd); + return osh != (intptr_t)-1; +} + +#elif _MSC_VER >= 1400 +/* Legacy implementation of _PyVerify_fd while transitioning to + * MSVC 14.0. This should eventually be removed. (issue23524) + */ + +/* 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()) + */ +/* The actual size of the structure is determined at runtime. + * Only the first items must be present. + */ +typedef struct { + intptr_t osfhnd; + char osfile; +} my_ioinfo; + +extern __declspec(dllimport) char * __pioinfo[]; +#define IOINFO_L2E 5 +#define IOINFO_ARRAYS 64 +#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; +} + +#endif /* _MSC_VER >= 1900 || _MSC_VER >= 1400 */ +#endif /* defined _MSC_VER */ diff --git a/Python/pystate.c b/Python/pystate.c index 32a635c..ee1e469 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -22,6 +22,12 @@ to avoid the expense of doing their own locking). #endif #endif +#if defined _MSC_VER && _MSC_VER >= 1900 +/* Issue #23524: Temporary fix to disable termination due to invalid parameters */ +PyAPI_DATA(void*) _Py_silent_invalid_parameter_handler; +#include <stdlib.h> +#endif + #ifdef __cplusplus extern "C" { #endif @@ -222,6 +228,11 @@ new_threadstate(PyInterpreterState *interp, int init) tstate->next->prev = tstate; interp->tstate_head = tstate; HEAD_UNLOCK(); + +#if defined _MSC_VER && _MSC_VER >= 1900 + /* Issue #23524: Temporary fix to disable termination due to invalid parameters */ + _set_thread_local_invalid_parameter_handler((_invalid_parameter_handler)_Py_silent_invalid_parameter_handler); +#endif } return tstate; |