[pypy-commit] pypy cpyext-old-buffers: Except for str, require all buffers to provide get_raw_address() for cpyext.

devin.jeanpierre pypy.commits at gmail.com
Fri May 20 11:48:31 EDT 2016


Author: Devin Jeanpierre <jeanpierreda at gmail.com>
Branch: cpyext-old-buffers
Changeset: r84532:294edd159e7e
Date: 2016-05-20 08:47 -0700
http://bitbucket.org/pypy/pypy/changeset/294edd159e7e/

Log:	Except for str, require all buffers to provide get_raw_address() for
	cpyext.

	This removes the magic leakiness of the previous approach --
	instead, a buffer may choose to be magically leaky itself (which is
	what I've rewritten buffer() to be.)

diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -455,25 +455,9 @@
         raise oefmt(space.w_SystemError,
                     "accessing non-existent buffer segment")
     buf = space.readbuf_w(w_buf)
-    try:
-        address = buf.get_raw_address()
-    except ValueError:
-        from pypy.module.cpyext.bytesobject import PyString_AsString
-        # convert to a string and maybe leak some memory. :(
-        w_str = space.wrap(buf.as_str())
-        py_str = make_ref(space, w_str)
-        ref[0] = PyString_AsString(space, py_str)
-        if space.is_w(w_str, w_buf):
-            # We're reusing the string object, and it's the caller's
-            # responsibility to keep it alive.
-            Py_DecRef(space, py_str)
-        # else: we had to create a new string object to keep the
-        # bytes in, so we leak it on purpose.
-        # XXX Can we put a reference to the string object on the buffer?
-        return space.len_w(w_str)
-    else:
-        ref[0] = address
-        return len(buf)
+    address = buf.get_raw_address()
+    ref[0] = address
+    return len(buf)
 
 @cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
              header=None, error=-1)
@@ -493,6 +477,26 @@
     return len(buf)
 
 
+ at cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
+             header=None, error=-1)
+def str_getreadbuffer(space, w_str, segment, ref):
+    from pypy.module.cpyext.bytesobject import PyString_AsString
+    if segment != 0:
+        raise OperationError(space.w_SystemError, space.wrap
+                             ("accessing non-existent string segment"))
+    pyref = make_ref(space, w_str)
+    ref[0] = PyString_AsString(space, pyref)
+    # Stolen reference: the object has better exist somewhere else
+    Py_DecRef(space, pyref)
+    return space.len_w(w_str)
+
+
+ at cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
+             header=None, error=-1)
+def str_getcharbuffer(space, w_buf, segment, ref):
+    return str_getreadbuffer(space, w_buf, segment, rffi.cast(rffi.VOIDPP, ref))
+
+
 def setup_buffer_procs(space, w_type, pto):
     bufspec = w_type.layout.typedef.buffer
     if bufspec is None:
@@ -502,14 +506,26 @@
     lltype.render_immortal(c_buf)
     c_buf.c_bf_getsegcount = llhelper(bf_segcount.api_func.functype,
                                       bf_segcount.api_func.get_wrapper(space))
-    c_buf.c_bf_getreadbuffer = llhelper(bf_getreadbuffer.api_func.functype,
-                                 bf_getreadbuffer.api_func.get_wrapper(space))
-    c_buf.c_bf_getcharbuffer = llhelper(bf_getcharbuffer.api_func.functype,
-                                 bf_getcharbuffer.api_func.get_wrapper(space))
-    if bufspec == 'read-write':
-        c_buf.c_bf_getwritebuffer = llhelper(
-            bf_getwritebuffer.api_func.functype,
-            bf_getwritebuffer.api_func.get_wrapper(space))
+    if space.is_w(w_type, space.w_str):
+        # Special case: str doesn't support get_raw_address(), so we have a
+        # custom get*buffer that instead gives the address of the char* in the
+        # PyStringObject*!
+        c_buf.c_bf_getreadbuffer = llhelper(
+            str_getreadbuffer.api_func.functype,
+            str_getreadbuffer.api_func.get_wrapper(space))
+        c_buf.c_bf_getcharbuffer = llhelper(
+            str_getcharbuffer.api_func.functype,
+            str_getcharbuffer.api_func.get_wrapper(space))
+    else:
+        # use get_raw_address()
+        c_buf.c_bf_getreadbuffer = llhelper(bf_getreadbuffer.api_func.functype,
+                                    bf_getreadbuffer.api_func.get_wrapper(space))
+        c_buf.c_bf_getcharbuffer = llhelper(bf_getcharbuffer.api_func.functype,
+                                    bf_getcharbuffer.api_func.get_wrapper(space))
+        if bufspec == 'read-write':
+            c_buf.c_bf_getwritebuffer = llhelper(
+                bf_getwritebuffer.api_func.functype,
+                bf_getwritebuffer.api_func.get_wrapper(space))
     pto.c_tp_as_buffer = c_buf
     pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
 


More information about the pypy-commit mailing list