From 00164b4a9821e82f513183035587bea9243a7d5e Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Tue, 1 Aug 2017 14:13:24 -0400 Subject: [PATCH 3/3] VS2015 Support: Backport of "Issue #23524: Replace _PyVerify_fd function with calling _set_thread_local_invalid_parameter_handler on every thread." This commit is a partial backport of python/cpython@d81431f. It was originally designed to work with python-cmake-buildsystem. Implementation of "_PyVerify_fd" in "Python/fileutils.c" found only in Python 3.x has been copied into "Modules/posixmodule.c" The following modules have NOT been backported: * PCbuild --- Modules/posixmodule.c | 54 +++++++++++++++++++++++------------------- PC/invalid_parameter_handler.c | 22 +++++++++++++++++ Python/pystate.c | 12 ++++++++++ PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 1 + 5 files changed, 65 insertions(+), 26 deletions(-) create mode 100644 PC/invalid_parameter_handler.c diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 90d5318..6a180a0 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -277,6 +277,7 @@ extern int lstat(const char *, struct stat *); #include "osdefs.h" #include #include +#include #include /* for ShellExecute() */ #define popen _popen #define pclose _pclose @@ -535,8 +534,28 @@ _PyInt_FromDev(PY_LONG_LONG v) # define _PyInt_FromDev PyInt_FromLong #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; +} + +#define _PyVerify_fd_dup2(fd1, fd2) (_PyVerify_fd(fd1) && (fd2) >= 0) + +#elif _MSC_VER >= 1400 -#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 @@ -601,35 +580,18 @@ _PyInt_FromDev(PY_LONG_LONG v) * 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 +#define IOINFO_L2E 5 +#define IOINFO_ARRAYS 64 /* This function emulates what the windows CRT does to validate file handles */ int @@ -653,6 +649,8 @@ _PyVerify_fd_dup2(int fd1, int fd2) #define _PyVerify_fd_dup2(A, B) (1) #endif +#endif /* defined _MSC_VER */ + /* Return a dictionary corresponding to the POSIX environment table */ #if defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED)) /* On Darwin/MacOSX a shared library or framework has no access to @@ -1260,14 +1254,10 @@ win32_fstat(int file_number, struct win32_stat *result) h = (HANDLE)_get_osfhandle(file_number); - /* 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)); @@ -1268,6 +1266,7 @@ win32_fstat(int file_number, struct win32_stat *result) if (type == FILE_TYPE_UNKNOWN) { DWORD error = GetLastError(); if (error != 0) { + errno = EINVAL; return -1; } /* else: valid but unknown file */ @@ -1284,6 +1281,7 @@ win32_fstat(int file_number, struct win32_stat *result) } if (!GetFileInformationByHandle(h, &info)) { + errno = EINVAL; return -1; } diff --git a/PC/invalid_parameter_handler.c b/PC/invalid_parameter_handler.c new file mode 100644 index 0000000..3bc0104 --- /dev/null +++ b/PC/invalid_parameter_handler.c @@ -0,0 +1,22 @@ +#ifdef _MSC_VER + +#include + +#if _MSC_VER >= 1900 +/* pyconfig.h uses this function in the _Py_BEGIN/END_SUPPRESS_IPH + * macros. It does not need to be defined when building using MSVC + * earlier than 14.0 (_MSC_VER == 1900). + */ + +static void __cdecl _silent_invalid_parameter_handler( + wchar_t const* expression, + wchar_t const* function, + wchar_t const* file, + unsigned int line, + uintptr_t pReserved) { } + +void *_Py_silent_invalid_parameter_handler = + (void*)_silent_invalid_parameter_handler; +#endif + +#endif diff --git a/Python/pystate.c b/Python/pystate.c index eb992c1..1c0f970 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -22,6 +22,12 @@ 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 +#endif + #ifdef __cplusplus extern "C" { #endif @@ -202,6 +208,12 @@ new_threadstate(PyInterpreterState *interp, int init) tstate->next = interp->tstate_head; 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; -- 2.5.0 diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 99291ea..af17762 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -333,6 +333,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 99291ea..af17762 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -794,6 +794,9 @@ Parser + + PC + PC