This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Potential memory leak in resize_compact() (for unicode objects)
Type: resource usage Stage: resolved
Components: Interpreter Core Versions: Python 3.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: dralley
Priority: normal Keywords:

Created on 2020-10-31 16:16 by dralley, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (2)
msg380077 - (view) Author: Daniel Alley (dralley) Date: 2020-10-31 16:16
Disclaimer: I'm not familiar with the interpreter internals, nor am I really a C dev, so I could be misinterpreting these results due to inexperience.

I've been attempting to debug a memory leak which I thought was caused by a C API extension that we are using.  When running the unit tests for this library under valgrind, I get a couple of results like the following, where the bottom of the call stack is a realloc() triggered by _PyUnicodeWriter_Finish()

==5732== 76 bytes in 1 blocks are definitely lost in loss record 4,571 of 9,822
==5732==    at 0x4C2C291: realloc (vg_replace_malloc.c:836)
==5732==    by 0x4F52323: _PyUnicodeWriter_Finish (in /usr/lib64/libpython3.6m.so.1.0)
==5732==    by 0x4F5A087: PyUnicode_FromFormatV (in /usr/lib64/libpython3.6m.so.1.0)
==5732==    by 0x4F937BC: PyErr_FormatV (in /usr/lib64/libpython3.6m.so.1.0)
==5732==    by 0x4F93433: PyErr_Format (in /usr/lib64/libpython3.6m.so.1.0)
==5732==    by 0x4F836B9: _PyEval_EvalFrameDefault (in /usr/lib64/libpython3.6m.so.1.0)
==5732==    by 0x4F87C9E: PyEval_EvalCodeEx (in /usr/lib64/libpython3.6m.so.1.0)
==5732==    by 0x4EF6DE2: ??? (in /usr/lib64/libpython3.6m.so.1.0)
==5732==    by 0x4EDEF62: PyObject_Call (in /usr/lib64/libpython3.6m.so.1.0)
==5732==    by 0xF9785EF: c_warningcb (in /usr/local/lib/pulp/lib/python3.6/site-packages/createrepo_c/_createrepo_c.so)
==5732==    by 0xF98F897: cr_xml_parser_warning (in /usr/local/lib/pulp/lib/python3.6/site-packages/createrepo_c/_createrepo_c.so)
==5732==    by 0xF98B59E: cr_start_handler (in /usr/local/lib/pulp/lib/python3.6/site-packages/createrepo_c/_createrepo_c.so)

There is no explicit call to realloc() in that function, but there is a call to resize_compact(), which in turn calls PyObject_Realloc(). I assume all those are getting inlined which is why it looks like there's nothing in-beteween -- if not, then maybe the leak is actually somewhere else.

The following is speculation given that I have limited understanding of interpreter workings.

In the version of Python I am using (3.6), resize_compact() has some code that looks suspicious to me: [0]

Two things jump out: 

1) "_Py_ForgetReference(unicode)", which according to this mailing list email [1] is used "to avoid having the deallocator run as result of the
DECREF".  The definition and usage of "_Py_ForgetReference(unicode)" in newer versions of Python is hidden behind "#ifdef Py_TRACE_REFS" flags [2], but it was not being done previously, which raises the question if perhaps it was being used improperly in previous versions. Forgetting about an object without deallocating it would certainly cause a leak.

2) When comparing [0] to a nearly identical piece of code meant for resizing bytestrings [3], I notice that in the branch handling the out of memory case, the bytestring version calls "PyObject_Del()" whereas the unicode version calls "_Py_NewReference()".

Can someone with more knowledge take a look at this?  And if neither of these are "the problem" then perhaps help me investigate what might be causing this Valgrind output?


[0] https://github.com/python/cpython/blob/3.6/Objects/unicodeobject.c#L943-L952

[1] https://www.mail-archive.com/python-dev@python.org/msg108525.html

[2] https://github.com/python/cpython/pull/18332/files#diff-34c966e7876d6f8bf801dd51896327e4f68bba02cddb95fbf3963f0b2e39c38aR1043-R1045

[3] https://github.com/python/cpython/blob/3.6/Objects/bytesobject.c#L3006-L3015
msg380091 - (view) Author: Daniel Alley (dralley) Date: 2020-10-31 19:39
A helpful user in the discord was able to point out where the bug was - in our extension, but not directly apparent from the valgrind output.
History
Date User Action Args
2022-04-11 14:59:37adminsetgithub: 86387
2020-10-31 19:39:25dralleysetstatus: open -> closed
resolution: not a bug
messages: + msg380091

stage: resolved
2020-10-31 16:16:40dralleycreate