Author: Armin Rigo <[email protected]>
Branch: py3.6
Changeset: r97889:19641c3cf073
Date: 2019-10-29 22:44 +0100
http://bitbucket.org/pypy/pypy/changeset/19641c3cf073/

Log:    memory leak: c_data is assigned a str2charp() that was never freed

diff --git a/pypy/module/cpyext/unicodeobject.py 
b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -101,13 +101,33 @@
 
 @slot_function([PyObject], lltype.Void)
 def unicode_dealloc(space, py_obj):
-    if get_wbuffer(py_obj):
+    if has_wbuffer_memory(py_obj):
         lltype.free(get_wbuffer(py_obj), flavor="raw")
-    if get_utf8(py_obj):
+    if has_utf8_memory(py_obj):
         lltype.free(get_utf8(py_obj), flavor="raw")
+    if not get_compact(py_obj) and get_data(py_obj):
+        lltype.free(get_data(py_obj), flavor="raw")
     from pypy.module.cpyext.object import _dealloc
     _dealloc(space, py_obj)
 
+def has_wbuffer_memory(py_obj):
+    ptr = get_wbuffer(py_obj)
+    if not ptr:
+        return False
+    elif not get_ready(py_obj):
+        return True
+    else:
+        return cts.cast('void *', ptr) != get_data(py_obj)
+
+def get_compact_ascii(py_obj):
+    return get_ascii(py_obj) and get_compact(py_obj)
+
+def has_utf8_memory(py_obj):
+    if get_compact_ascii(py_obj):
+        return False
+    utf8 = get_utf8(py_obj)
+    return bool(utf8) and cts.cast('void *', utf8) != get_data(py_obj)
+
 def get_len(py_obj):
     py_obj = cts.cast('PyASCIIObject*', py_obj)
     return py_obj.c_length
@@ -178,6 +198,12 @@
     py_obj = cts.cast('PyUnicodeObject*', py_obj)
     py_obj.c_data = p_data
 
+def get_compact(py_obj):
+    return rffi.getintfield(get_state(py_obj), 'c_compact')
+
+def set_compact(py_obj, value):
+    get_state(py_obj).c_compact = cts.cast('unsigned char', value)
+
 
 @cpython_api([Py_UNICODE], rffi.INT_real, error=CANNOT_FAIL)
 def Py_UNICODE_ISSPACE(space, ch):
@@ -300,8 +326,8 @@
                     "Character U+%s is not in range [U+0000; U+10ffff]",
                     '%x' % maxchar)
     if maxchar < 256:
-        ucs1_data = rffi.str2charp(value)
-        set_data(py_obj, cts.cast('void*', ucs1_data))
+        ucs1_data = cts.cast('void *', rffi.str2charp(value))
+        set_data(py_obj, ucs1_data)
         set_kind(py_obj, _1BYTE_KIND)
         set_len(py_obj, get_wsize(py_obj))
         if maxchar < 128:
@@ -313,31 +339,33 @@
             set_utf8(py_obj, cts.cast('char *', 0))
             set_utf8_len(py_obj, 0)
     elif maxchar < 65536:
-        ucs2_str = utf8_encode_utf_16_helper(
-            value, 'strict',
-            byteorder=BYTEORDER)
-        if rffi.sizeof(lltype.UniChar) == 2 and not get_wbuffer(py_obj):
-            # Copy unicode buffer
-            wchar = cts.cast('wchar_t*', rffi.str2charp(ucs2_str))
-            set_wbuffer(py_obj, wchar)
-            set_wsize(py_obj, len(ucs2_str) // 2)
-        ucs2_data = cts.cast('Py_UCS2 *', rffi.str2charp(ucs2_str))
-        set_data(py_obj, cts.cast('void*', ucs2_data))
+        ucs2_data = cts.cast('void *', 0)
+        if rffi.sizeof(lltype.UniChar) == 2:
+            ucs2_data = cts.cast('void *', get_wbuffer(py_obj))
+        if not ucs2_data:
+            ucs2_str = utf8_encode_utf_16_helper(
+                value, 'strict',
+                byteorder=BYTEORDER)
+            ucs2_data = cts.cast('void *', rffi.str2charp(ucs2_str))
+            if rffi.sizeof(lltype.UniChar) == 2:
+                set_wbuffer(py_obj, cts.cast('wchar_t *', ucs2_data))
+        set_data(py_obj, ucs2_data)
         set_len(py_obj, get_wsize(py_obj))
         set_kind(py_obj, _2BYTE_KIND)
         set_utf8(py_obj, cts.cast('char *', 0))
         set_utf8_len(py_obj, 0)
     else:
-        ucs4_str = utf8_encode_utf_32_helper(
-            value, 'strict',
-            byteorder=BYTEORDER)
-        if rffi.sizeof(lltype.UniChar) == 4 and not get_wbuffer(py_obj):
-            # Copy unicode buffer
-            wchar = cts.cast('wchar_t*', rffi.str2charp(ucs4_str))
-            set_wbuffer(py_obj, wchar)
-            set_wsize(py_obj, len(ucs4_str) // 4)
-        ucs4_data = get_wbuffer(py_obj)
-        set_data(py_obj, cts.cast('void*', ucs4_data))
+        ucs4_data = cts.cast('void *', 0)
+        if rffi.sizeof(lltype.UniChar) == 4:
+            ucs4_data = cts.cast('void *', get_wbuffer(py_obj))
+        if not ucs4_data:
+            ucs4_str = utf8_encode_utf_32_helper(
+                value, 'strict',
+                byteorder=BYTEORDER)
+            ucs4_data = cts.cast('void *', rffi.str2charp(ucs4_str))
+            if rffi.sizeof(lltype.UniChar) == 4:
+                set_wbuffer(py_obj, cts.cast('wchar_t *', ucs4_data))
+        set_data(py_obj, ucs4_data)
         set_len(py_obj, get_wsize(py_obj))
         set_kind(py_obj, _4BYTE_KIND)
         set_utf8(py_obj, cts.cast('char *', 0))
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to