Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r84091:5e6d2531c7c9
Date: 2016-05-01 11:35 +0200
http://bitbucket.org/pypy/pypy/changeset/5e6d2531c7c9/

Log:    Fix PyString_Concat and PyString_ConcatAndDel to do the right thing
        with reference counts (I think)

diff --git a/pypy/module/cpyext/bytesobject.py 
b/pypy/module/cpyext/bytesobject.py
--- a/pypy/module/cpyext/bytesobject.py
+++ b/pypy/module/cpyext/bytesobject.py
@@ -6,7 +6,7 @@
 from pypy.module.cpyext.pyerrors import PyErr_BadArgument
 from pypy.module.cpyext.pyobject import (
     PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
-    make_typedescr, get_typedescr, as_pyobj, Py_IncRef)
+    make_typedescr, get_typedescr, as_pyobj, Py_IncRef, get_w_obj_and_decref)
 
 ##
 ## Implementation of PyStringObject
@@ -233,7 +233,7 @@
 def _PyString_Eq(space, w_str1, w_str2):
     return space.eq_w(w_str1, w_str2)
 
-@cpython_api([PyObjectP, PyObject], lltype.Void)
+@cpython_api([PyObjectP, PyObject], lltype.Void, error=None)
 def PyString_Concat(space, ref, w_newpart):
     """Create a new string object in *string containing the contents of newpart
     appended to string; the caller will own the new reference.  The reference 
to
@@ -241,26 +241,27 @@
     the old reference to string will still be discarded and the value of
     *string will be set to NULL; the appropriate exception will be set."""
 
-    if not ref[0]:
+    old = ref[0]
+    if not old:
         return
 
-    if w_newpart is None or not PyString_Check(space, ref[0]) or not \
-            (space.isinstance_w(w_newpart, space.w_str) or 
-             space.isinstance_w(w_newpart, space.w_unicode)):
-        Py_DecRef(space, ref[0])
-        ref[0] = lltype.nullptr(PyObject.TO)
-        return
-    w_str = from_ref(space, ref[0])
-    w_newstr = space.add(w_str, w_newpart)
-    ref[0] = make_ref(space, w_newstr)
-    Py_IncRef(space, ref[0])
+    ref[0] = lltype.nullptr(PyObject.TO)
+    w_str = get_w_obj_and_decref(space, old)
+    if w_newpart is not None and PyString_Check(space, old):
+        # xxx if w_newpart is not a string or unicode or bytearray,
+        # this might call __radd__() on it, whereas CPython raises
+        # a TypeError in this case.
+        w_newstr = space.add(w_str, w_newpart)
+        ref[0] = make_ref(space, w_newstr)
 
-@cpython_api([PyObjectP, PyObject], lltype.Void)
+@cpython_api([PyObjectP, PyObject], lltype.Void, error=None)
 def PyString_ConcatAndDel(space, ref, newpart):
     """Create a new string object in *string containing the contents of newpart
     appended to string.  This version decrements the reference count of 
newpart."""
-    PyString_Concat(space, ref, newpart)
-    Py_DecRef(space, newpart)
+    try:
+        PyString_Concat(space, ref, newpart)
+    finally:
+        Py_DecRef(space, newpart)
 
 @cpython_api([PyObject, PyObject], PyObject)
 def PyString_Format(space, w_format, w_args):
diff --git a/pypy/module/cpyext/test/test_bytesobject.py 
b/pypy/module/cpyext/test/test_bytesobject.py
--- a/pypy/module/cpyext/test/test_bytesobject.py
+++ b/pypy/module/cpyext/test/test_bytesobject.py
@@ -359,6 +359,7 @@
         assert space.str_w(from_ref(space, ptr[0])) == 'abcdef'
         api.PyString_Concat(ptr, space.w_None)
         assert not ptr[0]
+        api.PyErr_Clear()
         ptr[0] = lltype.nullptr(PyObject.TO)
         api.PyString_Concat(ptr, space.wrap('def')) # should not crash
         lltype.free(ptr, flavor='raw')
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to