Issue 13091: ctypes: memory leak (original) (raw)

Created on 2011-10-02 09:11 by skrah, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Messages (5)
msg144765 - (view) Author: Stefan Krah (skrah) * (Python committer) Date: 2011-10-02 09:11
Seen in test_multiprocessing: ==31662== 44 bytes in 1 blocks are definitely lost in loss record 687 of 10,548 ==31662== at 0x4C2154B: malloc (vg_replace_malloc.c:236) ==31662== by 0x41CC27: PyMem_Malloc (object.c:1699) ==31662== by 0x127D9F51: resize (callproc.c:1664) ==31662== by 0x5759D8: PyCFunction_Call (methodobject.c:81) ==31662== by 0x48E294: call_function (ceval.c:3980) ==31662== by 0x4895E1: PyEval_EvalFrameEx (ceval.c:2605) ==31662== by 0x48E67B: fast_function (ceval.c:4068) ==31662== by 0x48E3C7: call_function (ceval.c:4001) ==31662== by 0x4895E1: PyEval_EvalFrameEx (ceval.c:2605) ==31662== by 0x48C54F: PyEval_EvalCodeEx (ceval.c:3355) ==31662== by 0x48E786: fast_function (ceval.c:4078) ==31662== by 0x48E3C7: call_function (ceval.c:4001)
msg144784 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2011-10-02 22:13
How did you obtain this? the resize() function is not called by test_multiprocessing. And are you sure that it's not some kind of reference leak? (this pointer is tied to a CDataObject; its tp_alloc should free the memory)
msg144791 - (view) Author: Meador Inge (meador.inge) * (Python committer) Date: 2011-10-02 22:58
I can reproduce this with: valgrind --tool=memcheck --log-file=leaks.txt --leak-check=full --suppressions=Misc/valgrind-python.supp ./python -m test test_ctypes Where as: valgrind --tool=memcheck --log-file=leaks.txt --leak-check=full --suppressions=Misc/valgrind-python.supp ./python -m test test_multiprocessing turns up nothing in 'ctypes.resize'.
msg144797 - (view) Author: Meador Inge (meador.inge) * (Python committer) Date: 2011-10-03 00:22
> this pointer is tied to a CDataObject; its tp_alloc should free the > memory The free in 'PyCData_clear' is conditional: if ((self->b_needsfree) && ((size_t)dict->size > sizeof(self->b_value))) PyMem_Free(self->b_ptr); As written, 'PyCData_clear' has no way of knowing that memory has been {m,re}alloc'd in 'resize'. So in some cases memory will leak. Here is a small reproduction case extracted from 'test_varsize_struct.py'. from ctypes import * class X(Structure): _fields_ = [("item", c_int), ("array", c_int * 1)] x = X() x.item = 42 x.array[0] = 100 new_size = sizeof(X) + sizeof(c_int) * 5 resize(x, new_size) One potential fix is: diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -2440,7 +2440,7 @@ PyCData_clear(CDataObject *self) assert(dict); /* Cannot be NULL for CDataObject instances */ Py_CLEAR(self->b_objects); if ((self->b_needsfree) - && ((size_t)dict->size > sizeof(self->b_value))) + && (self->b_ptr != (char *)&self->b_value)) PyMem_Free(self->b_ptr); self->b_ptr = NULL; Py_CLEAR(self->b_base); I need to think about that more, though.
msg177113 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2012-12-07 19:20
See patch in issue 16628.
History
Date User Action Args
2022-04-11 14:57:22 admin set github: 57300
2012-12-07 19:20:41 pitrou set status: open -> closednosy: + pitroumessages: + superseder: leak in ctypes.resize()resolution: duplicate
2011-10-03 00:22:15 meador.inge set messages: + versions: + Python 2.7, Python 3.2
2011-10-02 22:58:35 meador.inge set messages: +
2011-10-02 22:13:54 amaury.forgeotdarc set messages: +
2011-10-02 15:12:12 meador.inge set nosy: + amaury.forgeotdarc, belopolsky, meador.ingecomponents: + ctypes
2011-10-02 09:11:57 skrah create