mirror of
https://github.com/python/cpython.git
synced 2025-12-15 21:44:50 +00:00
Bug #1462152: file() now checks more thoroughly for invalid mode
strings and removes a possible "U" before passing the mode to the C library function.
This commit is contained in:
parent
b678ce5aa6
commit
7b90e168f3
4 changed files with 61 additions and 38 deletions
|
|
@ -136,46 +136,45 @@ fill_file_fields(PyFileObject *f, FILE *fp, PyObject *name, char *mode,
|
|||
/* check for known incorrect mode strings - problem is, platforms are
|
||||
free to accept any mode characters they like and are supposed to
|
||||
ignore stuff they don't understand... write or append mode with
|
||||
universal newline support is expressly forbidden by PEP 278. */
|
||||
universal newline support is expressly forbidden by PEP 278.
|
||||
Additionally, remove the 'U' from the mode string as platforms
|
||||
won't know what it is. */
|
||||
/* zero return is kewl - one is un-kewl */
|
||||
static int
|
||||
check_the_mode(char *mode)
|
||||
sanitize_the_mode(char *mode)
|
||||
{
|
||||
char *upos;
|
||||
size_t len = strlen(mode);
|
||||
|
||||
switch (len) {
|
||||
case 0:
|
||||
if (!len) {
|
||||
PyErr_SetString(PyExc_ValueError, "empty mode string");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* reject wU, aU */
|
||||
case 2:
|
||||
switch (mode[0]) {
|
||||
case 'w':
|
||||
case 'a':
|
||||
if (mode[1] == 'U') {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"invalid mode string");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
upos = strchr(mode, 'U');
|
||||
if (upos) {
|
||||
memmove(upos, upos+1, len-(upos-mode)); /* incl null char */
|
||||
|
||||
/* reject w+U, a+U, wU+, aU+ */
|
||||
case 3:
|
||||
switch (mode[0]) {
|
||||
case 'w':
|
||||
case 'a':
|
||||
if ((mode[1] == '+' && mode[2] == 'U') ||
|
||||
(mode[1] == 'U' && mode[2] == '+')) {
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"invalid mode string");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
if (mode[0] == 'w' || mode[0] == 'a') {
|
||||
PyErr_Format(PyExc_ValueError, "universal newline "
|
||||
"mode can only be used with modes "
|
||||
"starting with 'r'");
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
|
||||
if (mode[0] != 'r') {
|
||||
memmove(mode+1, mode, strlen(mode)+1);
|
||||
mode[0] = 'r';
|
||||
}
|
||||
|
||||
if (!strchr(mode, 'b')) {
|
||||
memmove(mode+2, mode+1, strlen(mode));
|
||||
mode[1] = 'b';
|
||||
}
|
||||
} else if (mode[0] != 'r' && mode[0] != 'w' && mode[0] != 'a') {
|
||||
PyErr_Format(PyExc_ValueError, "mode string must begin with "
|
||||
"one of 'r', 'w', 'a' or 'U', not '%.200s'", mode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
@ -184,6 +183,7 @@ check_the_mode(char *mode)
|
|||
static PyObject *
|
||||
open_the_file(PyFileObject *f, char *name, char *mode)
|
||||
{
|
||||
char *newmode;
|
||||
assert(f != NULL);
|
||||
assert(PyFile_Check(f));
|
||||
#ifdef MS_WINDOWS
|
||||
|
|
@ -195,8 +195,18 @@ open_the_file(PyFileObject *f, char *name, char *mode)
|
|||
assert(mode != NULL);
|
||||
assert(f->f_fp == NULL);
|
||||
|
||||
if (check_the_mode(mode))
|
||||
/* probably need to replace 'U' by 'rb' */
|
||||
newmode = PyMem_MALLOC(strlen(mode) + 3);
|
||||
if (!newmode) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
strcpy(newmode, mode);
|
||||
|
||||
if (sanitize_the_mode(newmode)) {
|
||||
f = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* rexec.py can't stop a user from getting the file() constructor --
|
||||
all they have to do is get *any* file object f, and then do
|
||||
|
|
@ -204,16 +214,15 @@ open_the_file(PyFileObject *f, char *name, char *mode)
|
|||
if (PyEval_GetRestricted()) {
|
||||
PyErr_SetString(PyExc_IOError,
|
||||
"file() constructor not accessible in restricted mode");
|
||||
return NULL;
|
||||
f = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
errno = 0;
|
||||
|
||||
if (strcmp(mode, "U") == 0 || strcmp(mode, "rU") == 0)
|
||||
mode = "rb";
|
||||
#ifdef MS_WINDOWS
|
||||
if (PyUnicode_Check(f->f_name)) {
|
||||
PyObject *wmode;
|
||||
wmode = PyUnicode_DecodeASCII(mode, strlen(mode), NULL);
|
||||
wmode = PyUnicode_DecodeASCII(newmode, strlen(newmode), NULL);
|
||||
if (f->f_name && wmode) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
/* PyUnicode_AS_UNICODE OK without thread
|
||||
|
|
@ -227,7 +236,7 @@ open_the_file(PyFileObject *f, char *name, char *mode)
|
|||
#endif
|
||||
if (NULL == f->f_fp && NULL != name) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
f->f_fp = fopen(name, mode);
|
||||
f->f_fp = fopen(name, newmode);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
|
||||
|
|
@ -254,6 +263,10 @@ open_the_file(PyFileObject *f, char *name, char *mode)
|
|||
}
|
||||
if (f != NULL)
|
||||
f = dircheck(f);
|
||||
|
||||
cleanup:
|
||||
PyMem_FREE(newmode);
|
||||
|
||||
return (PyObject *)f;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue