Merged revisions 77989 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r77989 | antoine.pitrou | 2010-02-05 18:05:54 +0100 (ven., 05 févr. 2010) | 6 lines Issue #5677: Explicitly forbid write operations on read-only file objects, and read operations on write-only file objects. On Windows, the system C library would return a bogus result; on Solaris, it was possible to crash the interpreter. Patch by Stefan Krah. ........
This commit is contained in:
parent
6e127db0ed
commit
2483728850
|
@ -28,6 +28,8 @@ typedef struct {
|
||||||
PyObject *weakreflist; /* List of weak references */
|
PyObject *weakreflist; /* List of weak references */
|
||||||
int unlocked_count; /* Num. currently running sections of code
|
int unlocked_count; /* Num. currently running sections of code
|
||||||
using f_fp with the GIL released. */
|
using f_fp with the GIL released. */
|
||||||
|
int readable;
|
||||||
|
int writable;
|
||||||
} PyFileObject;
|
} PyFileObject;
|
||||||
|
|
||||||
PyAPI_DATA(PyTypeObject) PyFile_Type;
|
PyAPI_DATA(PyTypeObject) PyFile_Type;
|
||||||
|
|
|
@ -86,6 +86,8 @@ class AutoFileTests(unittest.TestCase):
|
||||||
self.assert_(repr(self.f).startswith("<open file '" + TESTFN))
|
self.assert_(repr(self.f).startswith("<open file '" + TESTFN))
|
||||||
|
|
||||||
def testErrors(self):
|
def testErrors(self):
|
||||||
|
self.f.close()
|
||||||
|
self.f = open(TESTFN, 'rb')
|
||||||
f = self.f
|
f = self.f
|
||||||
self.assertEquals(f.name, TESTFN)
|
self.assertEquals(f.name, TESTFN)
|
||||||
self.assert_(not f.isatty())
|
self.assert_(not f.isatty())
|
||||||
|
@ -123,6 +125,40 @@ class AutoFileTests(unittest.TestCase):
|
||||||
def testReadWhenWriting(self):
|
def testReadWhenWriting(self):
|
||||||
self.assertRaises(IOError, self.f.read)
|
self.assertRaises(IOError, self.f.read)
|
||||||
|
|
||||||
|
def testIssue5677(self):
|
||||||
|
# Remark: Do not perform more than one test per open file,
|
||||||
|
# since that does NOT catch the readline error on Windows.
|
||||||
|
data = 'xxx'
|
||||||
|
for mode in ['w', 'wb', 'a', 'ab']:
|
||||||
|
for attr in ['read', 'readline', 'readlines']:
|
||||||
|
self.f = open(TESTFN, mode)
|
||||||
|
self.f.write(data)
|
||||||
|
self.assertRaises(IOError, getattr(self.f, attr))
|
||||||
|
self.f.close()
|
||||||
|
|
||||||
|
self.f = open(TESTFN, mode)
|
||||||
|
self.f.write(data)
|
||||||
|
self.assertRaises(IOError, lambda: [line for line in self.f])
|
||||||
|
self.f.close()
|
||||||
|
|
||||||
|
self.f = open(TESTFN, mode)
|
||||||
|
self.f.write(data)
|
||||||
|
self.assertRaises(IOError, self.f.readinto, bytearray(len(data)))
|
||||||
|
self.f.close()
|
||||||
|
|
||||||
|
for mode in ['r', 'rb', 'U', 'Ub', 'Ur', 'rU', 'rbU', 'rUb']:
|
||||||
|
self.f = open(TESTFN, mode)
|
||||||
|
self.assertRaises(IOError, self.f.write, data)
|
||||||
|
self.f.close()
|
||||||
|
|
||||||
|
self.f = open(TESTFN, mode)
|
||||||
|
self.assertRaises(IOError, self.f.writelines, [data, data])
|
||||||
|
self.f.close()
|
||||||
|
|
||||||
|
self.f = open(TESTFN, mode)
|
||||||
|
self.assertRaises(IOError, self.f.truncate)
|
||||||
|
self.f.close()
|
||||||
|
|
||||||
class OtherFileTests(unittest.TestCase):
|
class OtherFileTests(unittest.TestCase):
|
||||||
|
|
||||||
def testOpenDir(self):
|
def testOpenDir(self):
|
||||||
|
|
|
@ -538,7 +538,7 @@ class SizeofTest(unittest.TestCase):
|
||||||
# enumerate
|
# enumerate
|
||||||
check(enumerate([]), size(h + 'l3P'))
|
check(enumerate([]), size(h + 'l3P'))
|
||||||
# file
|
# file
|
||||||
check(self.file, size(h + '4P2i4P3i3Pi'))
|
check(self.file, size(h + '4P2i4P3i3P3i'))
|
||||||
# float
|
# float
|
||||||
check(float(0), size(h + 'd'))
|
check(float(0), size(h + 'd'))
|
||||||
# sys.floatinfo
|
# sys.floatinfo
|
||||||
|
|
|
@ -391,6 +391,7 @@ Pat Knight
|
||||||
Greg Kochanski
|
Greg Kochanski
|
||||||
Damon Kohler
|
Damon Kohler
|
||||||
Joseph Koshy
|
Joseph Koshy
|
||||||
|
Stefan Krah
|
||||||
Bob Kras
|
Bob Kras
|
||||||
Holger Krekel
|
Holger Krekel
|
||||||
Michael Kremer
|
Michael Kremer
|
||||||
|
|
|
@ -12,6 +12,11 @@ What's New in Python 2.6.5
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #5677: Explicitly forbid write operations on read-only file objects,
|
||||||
|
and read operations on write-only file objects. On Windows, the system C
|
||||||
|
library would return a bogus result; on Solaris, it was possible to crash
|
||||||
|
the interpreter. Patch by Stefan Krah.
|
||||||
|
|
||||||
- Issue #7819: Check sys.call_tracing() arguments types.
|
- Issue #7819: Check sys.call_tracing() arguments types.
|
||||||
|
|
||||||
- Issue #7788: Fix an interpreter crash produced by deleting a list
|
- Issue #7788: Fix an interpreter crash produced by deleting a list
|
||||||
|
|
|
@ -173,6 +173,13 @@ fill_file_fields(PyFileObject *f, FILE *fp, PyObject *name, char *mode,
|
||||||
f->f_encoding = Py_None;
|
f->f_encoding = Py_None;
|
||||||
Py_INCREF(Py_None);
|
Py_INCREF(Py_None);
|
||||||
f->f_errors = Py_None;
|
f->f_errors = Py_None;
|
||||||
|
f->readable = f->writable = 0;
|
||||||
|
if (strchr(mode, 'r') != NULL || f->f_univ_newline)
|
||||||
|
f->readable = 1;
|
||||||
|
if (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL)
|
||||||
|
f->writable = 1;
|
||||||
|
if (strchr(mode, '+') != NULL)
|
||||||
|
f->readable = f->writable = 1;
|
||||||
|
|
||||||
if (f->f_mode == NULL)
|
if (f->f_mode == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -487,6 +494,13 @@ err_closed(void)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
err_mode(char *action)
|
||||||
|
{
|
||||||
|
PyErr_Format(PyExc_IOError, "File not open for %s", action);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* Refuse regular file I/O if there's data in the iteration-buffer.
|
/* Refuse regular file I/O if there's data in the iteration-buffer.
|
||||||
* Mixing them would cause data to arrive out of order, as the read*
|
* Mixing them would cause data to arrive out of order, as the read*
|
||||||
* methods don't use the iteration buffer. */
|
* methods don't use the iteration buffer. */
|
||||||
|
@ -701,6 +715,8 @@ file_truncate(PyFileObject *f, PyObject *args)
|
||||||
|
|
||||||
if (f->f_fp == NULL)
|
if (f->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!f->writable)
|
||||||
|
return err_mode("writing");
|
||||||
if (!PyArg_UnpackTuple(args, "truncate", 0, 1, &newsizeobj))
|
if (!PyArg_UnpackTuple(args, "truncate", 0, 1, &newsizeobj))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@ -949,6 +965,8 @@ file_read(PyFileObject *f, PyObject *args)
|
||||||
|
|
||||||
if (f->f_fp == NULL)
|
if (f->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!f->readable)
|
||||||
|
return err_mode("reading");
|
||||||
/* refuse to mix with f.next() */
|
/* refuse to mix with f.next() */
|
||||||
if (f->f_buf != NULL &&
|
if (f->f_buf != NULL &&
|
||||||
(f->f_bufend - f->f_bufptr) > 0 &&
|
(f->f_bufend - f->f_bufptr) > 0 &&
|
||||||
|
@ -1018,6 +1036,8 @@ file_readinto(PyFileObject *f, PyObject *args)
|
||||||
|
|
||||||
if (f->f_fp == NULL)
|
if (f->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!f->readable)
|
||||||
|
return err_mode("reading");
|
||||||
/* refuse to mix with f.next() */
|
/* refuse to mix with f.next() */
|
||||||
if (f->f_buf != NULL &&
|
if (f->f_buf != NULL &&
|
||||||
(f->f_bufend - f->f_bufptr) > 0 &&
|
(f->f_bufend - f->f_bufptr) > 0 &&
|
||||||
|
@ -1389,6 +1409,8 @@ PyFile_GetLine(PyObject *f, int n)
|
||||||
PyFileObject *fo = (PyFileObject *)f;
|
PyFileObject *fo = (PyFileObject *)f;
|
||||||
if (fo->f_fp == NULL)
|
if (fo->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!fo->readable)
|
||||||
|
return err_mode("reading");
|
||||||
/* refuse to mix with f.next() */
|
/* refuse to mix with f.next() */
|
||||||
if (fo->f_buf != NULL &&
|
if (fo->f_buf != NULL &&
|
||||||
(fo->f_bufend - fo->f_bufptr) > 0 &&
|
(fo->f_bufend - fo->f_bufptr) > 0 &&
|
||||||
|
@ -1477,6 +1499,8 @@ file_readline(PyFileObject *f, PyObject *args)
|
||||||
|
|
||||||
if (f->f_fp == NULL)
|
if (f->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!f->readable)
|
||||||
|
return err_mode("reading");
|
||||||
/* refuse to mix with f.next() */
|
/* refuse to mix with f.next() */
|
||||||
if (f->f_buf != NULL &&
|
if (f->f_buf != NULL &&
|
||||||
(f->f_bufend - f->f_bufptr) > 0 &&
|
(f->f_bufend - f->f_bufptr) > 0 &&
|
||||||
|
@ -1510,6 +1534,8 @@ file_readlines(PyFileObject *f, PyObject *args)
|
||||||
|
|
||||||
if (f->f_fp == NULL)
|
if (f->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!f->readable)
|
||||||
|
return err_mode("reading");
|
||||||
/* refuse to mix with f.next() */
|
/* refuse to mix with f.next() */
|
||||||
if (f->f_buf != NULL &&
|
if (f->f_buf != NULL &&
|
||||||
(f->f_bufend - f->f_bufptr) > 0 &&
|
(f->f_bufend - f->f_bufptr) > 0 &&
|
||||||
|
@ -1628,6 +1654,8 @@ file_write(PyFileObject *f, PyObject *args)
|
||||||
Py_ssize_t n, n2;
|
Py_ssize_t n, n2;
|
||||||
if (f->f_fp == NULL)
|
if (f->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!f->writable)
|
||||||
|
return err_mode("writing");
|
||||||
if (f->f_binary) {
|
if (f->f_binary) {
|
||||||
if (!PyArg_ParseTuple(args, "s*", &pbuf))
|
if (!PyArg_ParseTuple(args, "s*", &pbuf))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1665,6 +1693,8 @@ file_writelines(PyFileObject *f, PyObject *seq)
|
||||||
assert(seq != NULL);
|
assert(seq != NULL);
|
||||||
if (f->f_fp == NULL)
|
if (f->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!f->writable)
|
||||||
|
return err_mode("writing");
|
||||||
|
|
||||||
result = NULL;
|
result = NULL;
|
||||||
list = NULL;
|
list = NULL;
|
||||||
|
@ -2105,6 +2135,8 @@ file_iternext(PyFileObject *f)
|
||||||
|
|
||||||
if (f->f_fp == NULL)
|
if (f->f_fp == NULL)
|
||||||
return err_closed();
|
return err_closed();
|
||||||
|
if (!f->readable)
|
||||||
|
return err_mode("reading");
|
||||||
|
|
||||||
l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE);
|
l = readahead_get_line_skip(f, 0, READAHEAD_BUFSIZE);
|
||||||
if (l == NULL || PyString_GET_SIZE(l) == 0) {
|
if (l == NULL || PyString_GET_SIZE(l) == 0) {
|
||||||
|
|
Loading…
Reference in New Issue