Skip to content

Commit 00164b4

Browse files
committed
VS2015 Support: Backport of "Issue python#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
1 parent e6a1f39 commit 00164b4

File tree

4 files changed

+64
-26
lines changed

4 files changed

+64
-26
lines changed

Modules/_io/fileio.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ check_fd(int fd)
159159
{
160160
#if defined(HAVE_FSTAT)
161161
struct stat buf;
162-
if (!_PyVerify_fd(fd) || (fstat(fd, &buf) < 0 && errno == EBADF)) {
162+
if (fstat(fd, &buf) < 0 && errno == EBADF) {
163163
PyObject *exc;
164164
char *msg = strerror(EBADF);
165165
exc = PyObject_CallFunction(PyExc_OSError, "(is)",

Modules/posixmodule.c

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ extern int lstat(const char *, struct stat *);
272272
#include "osdefs.h"
273273
#include <malloc.h>
274274
#include <windows.h>
275+
#include <malloc.h>
275276
#include <shellapi.h> /* for ShellExecute() */
276277
#define popen _popen
277278
#define pclose _pclose
@@ -528,8 +529,28 @@ _PyInt_FromDev(PY_LONG_LONG v)
528529
# define _PyInt_FromDev PyInt_FromLong
529530
#endif
530531

532+
#ifdef _MSC_VER
533+
#if _MSC_VER >= 1900
534+
535+
/* This function lets the Windows CRT validate the file handle without
536+
terminating the process if it's invalid. */
537+
int
538+
_PyVerify_fd(int fd)
539+
{
540+
intptr_t osh;
541+
/* Fast check for the only condition we know */
542+
if (fd < 0) {
543+
_set_errno(EBADF);
544+
return 0;
545+
}
546+
osh = _get_osfhandle(fd);
547+
return osh != (intptr_t)-1;
548+
}
549+
550+
#define _PyVerify_fd_dup2(fd1, fd2) (_PyVerify_fd(fd1) && (fd2) >= 0)
551+
552+
#elif _MSC_VER >= 1400
531553

532-
#if defined _MSC_VER && _MSC_VER >= 1400
533554
/* Microsoft CRT in VS2005 and higher will verify that a filehandle is
534555
* valid and raise an assertion if it isn't.
535556
* Normally, an invalid fd is likely to be a C program error and therefore
@@ -554,35 +575,18 @@ _PyInt_FromDev(PY_LONG_LONG v)
554575
* Only the first items must be present.
555576
*/
556577

557-
#if _MSC_VER >= 1900
558-
559-
typedef struct {
560-
CRITICAL_SECTION lock;
561-
intptr_t osfhnd;
562-
__int64 startpos;
563-
char osfile;
564-
} my_ioinfo;
565-
566-
#define IOINFO_L2E 6
567-
#define IOINFO_ARRAYS 128
568-
569-
#else
570-
571578
typedef struct {
572579
intptr_t osfhnd;
573580
char osfile;
574581
} my_ioinfo;
575582

576-
#define IOINFO_L2E 5
577-
#define IOINFO_ARRAYS 64
578-
579-
#endif
580-
581583
extern __declspec(dllimport) char * __pioinfo[];
582584
#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
583585
#define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
584586
#define FOPEN 0x01
585587
#define _NO_CONSOLE_FILENO (intptr_t)-2
588+
#define IOINFO_L2E 5
589+
#define IOINFO_ARRAYS 64
586590

587591
/* This function emulates what the windows CRT does to validate file handles */
588592
int
@@ -640,6 +644,8 @@ _PyVerify_fd_dup2(int fd1, int fd2)
640644
#define _PyVerify_fd_dup2(A, B) (1)
641645
#endif
642646

647+
#endif /* defined _MSC_VER */
648+
643649
/* Return a dictionary corresponding to the POSIX environment table */
644650
#if defined(WITH_NEXT_FRAMEWORK) || (defined(__APPLE__) && defined(Py_ENABLE_SHARED))
645651
/* On Darwin/MacOSX a shared library or framework has no access to
@@ -1242,14 +1248,10 @@ win32_fstat(int file_number, struct win32_stat *result)
12421248

12431249
h = (HANDLE)_get_osfhandle(file_number);
12441250

1245-
/* Protocol violation: we explicitly clear errno, instead of
1246-
setting it to a POSIX error. Callers should use GetLastError. */
12471251
errno = 0;
12481252

12491253
if (h == INVALID_HANDLE_VALUE) {
1250-
/* This is really a C library error (invalid file handle).
1251-
We set the Win32 error to the closes one matching. */
1252-
SetLastError(ERROR_INVALID_HANDLE);
1254+
errno = EBADF;
12531255
return -1;
12541256
}
12551257
memset(result, 0, sizeof(*result));
@@ -1258,6 +1260,7 @@ win32_fstat(int file_number, struct win32_stat *result)
12581260
if (type == FILE_TYPE_UNKNOWN) {
12591261
DWORD error = GetLastError();
12601262
if (error != 0) {
1263+
errno = EINVAL;
12611264
return -1;
12621265
}
12631266
/* else: valid but unknown file */
@@ -1272,6 +1275,7 @@ win32_fstat(int file_number, struct win32_stat *result)
12721275
}
12731276

12741277
if (!GetFileInformationByHandle(h, &info)) {
1278+
errno = EINVAL;
12751279
return -1;
12761280
}
12771281

PC/invalid_parameter_handler.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#ifdef _MSC_VER
2+
3+
#include <stdlib.h>
4+
5+
#if _MSC_VER >= 1900
6+
/* pyconfig.h uses this function in the _Py_BEGIN/END_SUPPRESS_IPH
7+
* macros. It does not need to be defined when building using MSVC
8+
* earlier than 14.0 (_MSC_VER == 1900).
9+
*/
10+
11+
static void __cdecl _silent_invalid_parameter_handler(
12+
wchar_t const* expression,
13+
wchar_t const* function,
14+
wchar_t const* file,
15+
unsigned int line,
16+
uintptr_t pReserved) { }
17+
18+
void *_Py_silent_invalid_parameter_handler =
19+
(void*)_silent_invalid_parameter_handler;
20+
#endif
21+
22+
#endif

Python/pystate.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ the expense of doing their own locking).
2222
#endif
2323
#endif
2424

25+
#if defined _MSC_VER && _MSC_VER >= 1900
26+
/* Issue #23524: Temporary fix to disable termination due to invalid parameters */
27+
PyAPI_DATA(void*) _Py_silent_invalid_parameter_handler;
28+
#include <stdlib.h>
29+
#endif
30+
2531
#ifdef __cplusplus
2632
extern "C" {
2733
#endif
@@ -202,6 +208,12 @@ new_threadstate(PyInterpreterState *interp, int init)
202208
tstate->next = interp->tstate_head;
203209
interp->tstate_head = tstate;
204210
HEAD_UNLOCK();
211+
212+
#if defined _MSC_VER && _MSC_VER >= 1900
213+
/* Issue #23524: Temporary fix to disable termination due to invalid parameters */
214+
_set_thread_local_invalid_parameter_handler((_invalid_parameter_handler)_Py_silent_invalid_parameter_handler);
215+
#endif
216+
205217
}
206218

207219
return tstate;

0 commit comments

Comments
 (0)