Index: Include/pyerrors.h =================================================================== --- Include/pyerrors.h (revision 68762) +++ Include/pyerrors.h (working copy) @@ -326,4 +326,15 @@ #ifdef __cplusplus } #endif + +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) +void _Py_SetCRTErrorHandler(int enter); +#define Py_BEGIN_CRT_ERROR_HANDLING _Py_SetCRTErrorHandler(1); +#define Py_END_CRT_ERROR_HANDLING _Py_SetCRTErrorHandler(0); +#else +/* no-ops */ +#define Py_BEGIN_CRT_ERROR_HANDLING +#define Py_END_CRT_ERROR_HANDLING +#endif + #endif /* !Py_ERRORS_H */ Index: Lib/test/test_file.py =================================================================== --- Lib/test/test_file.py (revision 68762) +++ Lib/test/test_file.py (working copy) @@ -154,7 +154,7 @@ for name in (TESTFN, unicode(TESTFN), unicode(TESTFN + '\t')): try: f = open(name, "rr") - except IOError: + except (IOError, ValueError): pass else: f.close() Index: Modules/_fileio.c =================================================================== --- Modules/_fileio.c (revision 68762) +++ Modules/_fileio.c (working copy) @@ -124,7 +124,11 @@ { #if defined(HAVE_FSTAT) struct stat buf; - if (fstat(fd, &buf) < 0 && errno == EBADF) { + int result; + Py_BEGIN_CRT_ERROR_HANDLING + result = fstat(fd, &buf); + Py_END_CRT_ERROR_HANDLING + if (result < 0 && errno == EBADF) { PyObject *exc; char *msg = strerror(EBADF); exc = PyObject_CallFunction(PyExc_OSError, "(is)", Index: Modules/posixmodule.c =================================================================== --- Modules/posixmodule.c (revision 68763) +++ Modules/posixmodule.c (working copy) @@ -581,9 +581,14 @@ fd = PyObject_AsFileDescriptor(fdobj); if (fd < 0) return NULL; + /* Wherever we accept integral file descriptors, we must use + * weaker error checking in the windows C runtime + */ + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS res = (*func)(fd); Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING if (res < 0) return posix_error(); Py_INCREF(Py_None); @@ -6188,9 +6193,11 @@ int fd, res; if (!PyArg_ParseTuple(args, "i:close", &fd)) return NULL; + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS res = close(fd); Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING if (res < 0) return posix_error(); Py_INCREF(Py_None); @@ -6208,10 +6215,12 @@ int fd_from, fd_to, i; if (!PyArg_ParseTuple(args, "ii:closerange", &fd_from, &fd_to)) return NULL; + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS for (i = fd_from; i < fd_to; i++) close(i); Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING Py_RETURN_NONE; } @@ -6226,9 +6235,11 @@ int fd; if (!PyArg_ParseTuple(args, "i:dup", &fd)) return NULL; + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS fd = dup(fd); Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING if (fd < 0) return posix_error(); return PyInt_FromLong((long)fd); @@ -6245,9 +6256,11 @@ int fd, fd2, res; if (!PyArg_ParseTuple(args, "ii:dup2", &fd, &fd2)) return NULL; + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS res = dup2(fd, fd2); Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING if (res < 0) return posix_error(); Py_INCREF(Py_None); @@ -6289,13 +6302,15 @@ if (PyErr_Occurred()) return NULL; + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS #if defined(MS_WIN64) || defined(MS_WINDOWS) res = _lseeki64(fd, pos, how); -#else + #else res = lseek(fd, pos, how); #endif Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING if (res < 0) return posix_error(); @@ -6325,9 +6340,11 @@ buffer = PyString_FromStringAndSize((char *)NULL, size); if (buffer == NULL) return NULL; + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS n = read(fd, PyString_AsString(buffer), size); Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING if (n < 0) { Py_DECREF(buffer); return posix_error(); @@ -6351,9 +6368,12 @@ if (!PyArg_ParseTuple(args, "is*:write", &fd, &pbuf)) return NULL; + /* turn off crt asserts on windows since we have no control over fd */ + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS size = write(fd, pbuf.buf, (size_t)pbuf.len); Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING PyBuffer_Release(&pbuf); if (size < 0) return posix_error(); @@ -6377,9 +6397,11 @@ /* on OpenVMS we must ensure that all bytes are written to the file */ fsync(fd); #endif + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS res = FSTAT(fd, &st); Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING if (res != 0) { #ifdef MS_WINDOWS return win32_error("fstat", NULL); @@ -6419,6 +6441,7 @@ PyMem_FREE(mode); return NULL; } + Py_BEGIN_CRT_ERROR_HANDLING Py_BEGIN_ALLOW_THREADS #if !defined(MS_WINDOWS) && defined(HAVE_FCNTL_H) if (mode[0] == 'a') { @@ -6438,6 +6461,7 @@ fp = fdopen(fd, mode); #endif Py_END_ALLOW_THREADS + Py_END_CRT_ERROR_HANDLING PyMem_FREE(mode); if (fp == NULL) return posix_error(); @@ -6455,10 +6479,13 @@ static PyObject * posix_isatty(PyObject *self, PyObject *args) { - int fd; + int fd, atty; if (!PyArg_ParseTuple(args, "i:isatty", &fd)) return NULL; - return PyBool_FromLong(isatty(fd)); + Py_BEGIN_CRT_ERROR_HANDLING + atty = isatty(fd); + Py_END_CRT_ERROR_HANDLING + return PyBool_FromLong(atty); } #ifdef HAVE_PIPE Index: Modules/timemodule.c =================================================================== --- Modules/timemodule.c (revision 68762) +++ Modules/timemodule.c (working copy) @@ -470,6 +470,23 @@ return NULL; } +#ifdef MS_WINDOWS + /* check that the format string contains only valid directives */ + for(outbuf = strchr(fmt, '%'); + outbuf != NULL; + outbuf = strchr(outbuf+2, '%')) + { + if (outbuf[1]=='#') + ++outbuf; /* not documented by python, */ + if (outbuf[1]=='\0' || + !strchr("aAbBcdfHIjmMpSUwWxXyYzZ%", outbuf[1])) + { + PyErr_SetString(PyExc_ValueError, "Invalid format string"); + return 0; + } + } +#endif + fmtlen = strlen(fmt); /* I hate these functions that presume you know how big the output Index: Objects/exceptions.c =================================================================== --- Objects/exceptions.c (revision 68762) +++ Objects/exceptions.c (working copy) @@ -1972,29 +1972,7 @@ if (PyDict_SetItemString(bdict, # TYPE, PyExc_ ## TYPE)) \ Py_FatalError("Module dictionary insertion problem."); -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) -/* crt variable checking in VisualStudio .NET 2005 */ -#include -static int prevCrtReportMode; -static _invalid_parameter_handler prevCrtHandler; - -/* Invalid parameter handler. Sets a ValueError exception */ -static void -InvalidParameterHandler( - const wchar_t * expression, - const wchar_t * function, - const wchar_t * file, - unsigned int line, - uintptr_t pReserved) -{ - /* Do nothing, allow execution to continue. Usually this - * means that the CRT will set errno to EINVAL - */ -} -#endif - - PyMODINIT_FUNC _PyExc_Init(void) { @@ -2153,13 +2131,6 @@ } Py_DECREF(bltinmod); - -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - /* Set CRT argument error handler */ - prevCrtHandler = _set_invalid_parameter_handler(InvalidParameterHandler); - /* turn off assertions in debug mode */ - prevCrtReportMode = _CrtSetReportMode(_CRT_ASSERT, 0); -#endif } void @@ -2167,9 +2138,4 @@ { Py_XDECREF(PyExc_MemoryErrorInst); PyExc_MemoryErrorInst = NULL; -#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) - /* reset CRT error handling */ - _set_invalid_parameter_handler(prevCrtHandler); - _CrtSetReportMode(_CRT_ASSERT, prevCrtReportMode); -#endif } Index: Objects/fileobject.c =================================================================== --- Objects/fileobject.c (revision 68762) +++ Objects/fileobject.c (working copy) @@ -181,6 +181,89 @@ return (PyObject *) f; } + +#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__) +#define Py_VERIFY_WINNT +/* The CRT on windows compiled with Visual Studio 2005 and higher may + * assert if given invalid mode strings. This is all fine and well + * in static languages like C where the mode string is typcially hard + * coded. But in Python, were we pass in the mode string from the user, + * we need to verify it first manually + */ +static int _PyVerify_Mode_WINNT(const char *mode) +{ + /* See if mode string is valid on Windows to avoid hard assertions */ + /* remove leading spacese */ + int singles = 0; + int pairs = 0; + int encoding = 0; + const char *s, *c; + + while(*mode == ' ') /* strip initial spaces */ + ++mode; + if (!strchr("rwa", *mode)) /* must start with one of these */ + return 0; + while (*++mode) { + if (*mode == ' ' || *mode == 'N') /* ignore spaces and N */ + continue; + s = "+TD"; /* each of this can appear only once */ + c = strchr(s, *mode); + if (c) { + int idx = s-c; + if (singles & (1<= 1400 && defined(__STDC_SECURE_LIB__) +#include +static void +InvalidParameterHandler( + const wchar_t * expression, + const wchar_t * function, + const wchar_t * file, + unsigned int line, + uintptr_t pReserved) +{ + /* Do nothing, allow execution to continue. Usually this + * means that the CRT will set errno to EINVAL + */ +} + +/* A function for temporarily disabling strict CRT error handling on + * windows. + * this is needed where we we have to accept a "raw" parameter from the + * user and have the CRT respond leniently, e.g. by issuing a EINVAL. + * Examples are functions that take integral file descriptors, + * strftime which takes an arbitrary format string, and the + * mode string for open() + * The settings are global, so we need a static counter to make sure + * that different threads don't step on each others toes. + * Must be invoked while holding the GIL + */ +void _Py_SetCRTErrorHandler(int enter){ + static int current_level = 0; + static _invalid_parameter_handler old_handler = 0; +#ifdef _DEBUG + static int old_mode = 0; +#endif + if (enter) { + if (current_level++ == 0) { + old_handler = _set_invalid_parameter_handler( + InvalidParameterHandler); +#ifdef _DEBUG + old_mode = _CrtSetReportMode(_CRT_ASSERT, 0); +#endif + } + } else { + if (--current_level == 0) { + _set_invalid_parameter_handler(old_handler); +#ifdef _DEBUG + _CrtSetReportMode(_CRT_ASSERT, old_mode); +#endif + } + } +} +#endif