[pypy-svn] r78313 - in pypy/branch/fast-forward/pypy/module/_io: . test

afa at codespeak.net afa at codespeak.net
Tue Oct 26 19:30:11 CEST 2010


Author: afa
Date: Tue Oct 26 19:30:09 2010
New Revision: 78313

Modified:
   pypy/branch/fast-forward/pypy/module/_io/interp_bufferedio.py
   pypy/branch/fast-forward/pypy/module/_io/test/test_bufferedio.py
Log:
Fix properties of incompletely initialized Buffered* objects.
This is especially important to avoid segfaults in __del__...


Modified: pypy/branch/fast-forward/pypy/module/_io/interp_bufferedio.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_io/interp_bufferedio.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_io/interp_bufferedio.py	Tue Oct 26 19:30:09 2010
@@ -1,6 +1,6 @@
 from __future__ import with_statement
 from pypy.interpreter.typedef import (
-    TypeDef, generic_new_descr)
+    TypeDef, GetSetProperty, generic_new_descr)
 from pypy.interpreter.gateway import interp2app, unwrap_spec
 from pypy.interpreter.baseobjspace import ObjSpace, W_Root
 from pypy.interpreter.error import OperationError, operationerrfmt
@@ -11,12 +11,15 @@
 from pypy.module._io.interp_io import DEFAULT_BUFFER_SIZE, W_BlockingIOError
 from pypy.module.thread.os_lock import Lock
 
+STATE_ZERO, STATE_OK, STATE_DETACHED = range(3)
+
 class BlockingIOError(Exception):
     pass
 
 class W_BufferedIOBase(W_IOBase):
     def __init__(self, space):
         W_IOBase.__init__(self, space)
+        self.state = STATE_ZERO
 
         self.buffer = lltype.nullptr(rffi.CCHARP.TO)
         self.pos = 0        # Current logical position in the buffer
@@ -84,6 +87,18 @@
         except OperationError:
             pass
 
+    def _check_init(self, space):
+        if self.state == STATE_ZERO:
+            raise OperationError(space.w_ValueError, space.wrap(
+                "I/O operation on uninitialized object"))
+        elif self.state == STATE_DETACHED:
+            raise OperationError(space.w_ValueError, space.wrap(
+                "raw stream has been detached"))
+
+    def _check_closed(self, space, message=None):
+        self._check_init(space)
+        W_IOBase._check_closed(self, space, message)
+
     def _raw_tell(self, space):
         w_pos = space.call_method(self.raw, "tell")
         pos = space.r_longlong_w(w_pos)
@@ -94,6 +109,10 @@
         self.abs_pos = pos
         return pos
 
+    def closed_get_w(space, self):
+        self._check_init(space)
+        return space.getattr(self.raw, space.wrap("closed"))
+
     def _readahead(self):
         if self.readable and self.read_end != -1:
             return self.read_end - self.pos
@@ -155,6 +174,7 @@
 
     @unwrap_spec('self', ObjSpace)
     def close_w(self, space):
+        self._check_init(space)
         with self.lock:
             if self._closed(space):
                 return
@@ -164,6 +184,7 @@
 
     @unwrap_spec('self', ObjSpace)
     def flush_w(self, space):
+        self._check_init(space)
         return space.call_method(self.raw, "flush")
 
     def _writer_flush_unlocked(self, space, restore_pos=False):
@@ -223,7 +244,7 @@
             l.append(self.buffer[i])
         return self._write(space, ''.join(l))
 
-class W_BufferedReader(W_BufferedIOBase, BufferedMixin):
+class W_BufferedReader(BufferedMixin, W_BufferedIOBase):
     def __init__(self, space):
         W_BufferedIOBase.__init__(self, space)
         self.ok = False
@@ -231,6 +252,7 @@
 
     @unwrap_spec('self', ObjSpace, W_Root, int)
     def descr_init(self, space, w_raw, buffer_size=DEFAULT_BUFFER_SIZE):
+        self.state = STATE_ZERO
         raw = space.interp_w(W_IOBase, w_raw)
         raw.check_readable_w(space)
 
@@ -240,6 +262,7 @@
 
         self._init(space)
         self._reader_reset_buf()
+        self.state = STATE_OK
 
     @unwrap_spec('self', ObjSpace, W_Root)
     def read_w(self, space, w_size=None):
@@ -397,11 +420,13 @@
     seek = interp2app(W_BufferedReader.seek_w),
     close = interp2app(W_BufferedReader.close_w),
     flush = interp2app(W_BufferedReader.flush_w),
+    closed = GetSetProperty(W_BufferedReader.closed_get_w),
     )
 
-class W_BufferedWriter(W_BufferedIOBase, BufferedMixin):
+class W_BufferedWriter(BufferedMixin, W_BufferedIOBase):
     @unwrap_spec('self', ObjSpace, W_Root, int)
     def descr_init(self, space, w_raw, buffer_size=DEFAULT_BUFFER_SIZE):
+        self.state = STATE_ZERO
         raw = space.interp_w(W_IOBase, w_raw)
         raw.check_writable_w(space)
 
@@ -411,6 +436,7 @@
 
         self._init(space)
         self._writer_reset_buf()
+        self.state = STATE_OK
 
     def _adjust_position(self, new_pos):
         self.pos = new_pos
@@ -545,6 +571,7 @@
     # from the mixin class
     seek = interp2app(W_BufferedWriter.seek_w),
     close = interp2app(W_BufferedWriter.close_w),
+    closed = GetSetProperty(W_BufferedWriter.closed_get_w),
     )
 
 class W_BufferedRWPair(W_BufferedIOBase):

Modified: pypy/branch/fast-forward/pypy/module/_io/test/test_bufferedio.py
==============================================================================
--- pypy/branch/fast-forward/pypy/module/_io/test/test_bufferedio.py	(original)
+++ pypy/branch/fast-forward/pypy/module/_io/test/test_bufferedio.py	Tue Oct 26 19:30:09 2010
@@ -1,4 +1,4 @@
-from pypy.conftest import gettestobjspace
+from pypy.conftest import gettestobjspace, option
 from pypy.interpreter.gateway import interp2app
 from pypy.tool.udir import udir
 
@@ -38,9 +38,12 @@
         cls.space = gettestobjspace(usemodules=['_io'])
         tmpfile = udir.join('tmpfile')
         cls.w_tmpfile = cls.space.wrap(str(tmpfile))
-        def readfile(space):
-            return space.wrap(tmpfile.read())
-        cls.w_readfile = cls.space.wrap(interp2app(readfile))
+        if option.runappdirect:
+            cls.w_readfile = tmpfile.read
+        else:
+            def readfile(space):
+                return space.wrap(tmpfile.read())
+            cls.w_readfile = cls.space.wrap(interp2app(readfile))
 
     def test_write(self):
         import _io
@@ -57,3 +60,12 @@
         f.write("abcd" * 5000)
         f.close()
         assert self.readfile() == "abcd" * 5000
+
+    def test_incomplete(self):
+        import _io
+        raw = _io.FileIO(self.tmpfile)
+        b = _io.BufferedWriter.__new__(_io.BufferedWriter)
+        raises(IOError, b.__init__, raw) # because file is not writable
+        raises(ValueError, getattr, b, 'closed')
+        raises(ValueError, b.flush)
+        raises(ValueError, b.close)



More information about the Pypy-commit mailing list