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: eval() leaks 1 reference every time
Type: resource usage Stage:
Components: Interpreter Core Versions: Python 3.0
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: loewis Nosy List: amaury.forgeotdarc, benjamin.peterson, brett.cannon, christian.heimes, loewis, nnorwitz, pitrou
Priority: release blocker Keywords: needs review, patch

Created on 2008-08-22 22:09 by amaury.forgeotdarc, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
buffer-leak.patch amaury.forgeotdarc, 2008-08-23 00:02
buffer-leak.patch amaury.forgeotdarc, 2008-08-24 21:03
buffer-leak.patch amaury.forgeotdarc, 2008-08-25 08:47
Messages (24)
msg71783 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-22 22:09
version 3.0, any call to eval() leaks one reference:

>>> eval('1')
1
[42093 refs]
>>> eval('1')
1
[42094 refs]
>>> eval('1')
1
[42095 refs]
>>> eval('1')
1
[42096 refs]
msg71784 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2008-08-22 22:17
The error is inside compile, not eval:

>>> compile("1", "test", "eval")
<code object <module> at 0x7ffe1ce2ed50, file "test", line 1>
[43379 refs]
>>> compile("1", "test", "eval")
<code object <module> at 0x7ffe1ce2e3b0, file "test", line 1>
[43380 refs]
>>> compile("1", "test", "eval")
<code object <module> at 0x7ffe1ce2ed50, file "test", line 1>
[43381 refs]
>>> compile("1", "test", "eval")
<code object <module> at 0x7ffe1ce2e3b0, file "test", line 1>
[43382 refs]
msg71785 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-22 22:20
The leaked reference refers to the bytes object which encodes the code
being compiled:
>>> for x in range(1000): compile("1", "test", "eval")
>>> sys.getrefcount(b'1')
1004
msg71787 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2008-08-22 22:24
Could it be related to the fact that test_bytes is leaking?

test_bytes leaked [129, 129, 129, 129] references, sum=516
msg71788 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2008-08-22 22:28
Good point! It's leaking even more on my 64bit machine:

test_bytes leaked [195, 195, 195, 195] references, sum=780
msg71789 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-22 22:37
Benjamin: yes, test_bytes calls eval() 128 times.
Christian: please "svn up", I just corrected another leak in bytesobject.c
msg71790 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2008-08-22 22:47
I was already up to date. r65985 leaks 195 references in each run on my box.
msg71791 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-22 22:55
The attached patch corrects the eval() and compile() reference leak.
The problem is in PyObject_AsReadBuffer.

Needs review: view->obj seems to own the reference, but object.h say the
opposite.
msg71792 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-22 23:10
PyObject_AsCharBuffer is affected as well.
This fixes for me the last refleak in test_bytes.
msg71795 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-23 00:02
Of course, I forgot PyObject_AsWriteBuffer in my patch.

I wonder if turning view.obj into an owned reference was a good idea.
There are more calls to bf_getbuffer (in getarg.c), they leak too: 

test_struct leaked [5, 5, 5, 5] references, sum=20

because of a PyArg_ParseTuple with s# and a bytes object.
msg71819 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2008-08-23 22:38
Ignoring the question of whether owning the reference is the right thing
or not, the patch looks fine, although I don't see a reason for the
decrements to not be Py_DECREF since the function calls just won't even
happen if the object that the buffer is being created for is NULL.

As for changing whether Py_buffer holds a reference, that's tricky.
Removing the increment from PyBuffer_FillInfo() segfaults the
interpreter, so some code already assumes it does increment. There is
also the question of what the common use-case is; are buffers more like
items from a container, or their own object? The former says to
increment, the latter says to decrement. And since Py_buffer objects are
not true Python objects you can't just Py_DECREF() them.

My gut says to let buffers own a reference and to fix the "s#" leak.
msg71821 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-08-23 23:26
Hi,

Making Py_buffer INCREF the original object is IMO the right thing to
do, because in most cases letting the original object disappear means
the memory region will become invalid as well. If you don't want the
INCREF, you can pass NULL as the obj parameter to PyBuffer_FillInfo() -
a piece of code in unicodeobject.c does just that.

However, since this decision was made recently (at the same time the s*
format codes were introduced), it is not reflected in the buffer API
documentation.
msg71828 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2008-08-24 05:51
This is a partial (or complete) duplicate of 3656.
msg71832 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2008-08-24 07:14
Even with the patch, there are still tons of leaks.  I don't know if
it's due to the same problem or not.  So far there is:

test_unittest leaked [124, 124] references, sum=248
test_array leaked [110, 110] references, sum=220
test_audioop leaked [75, 75] references, sum=150
test_binascii leaked [4, 4] references, sum=8

There are probably more.
msg71834 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-24 09:18
The main cause of these leaks is each time PyArg_ParseTuple("s#") is
passed a bytes object.
If FillInfo() increfs the given object, every object should have a
bf_releasebuffer that decrefs it.
msg71835 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-08-24 11:23
Le dimanche 24 août 2008 à 09:18 +0000, Amaury Forgeot d'Arc a écrit :
> If FillInfo() increfs the given object, every object should have a
> bf_releasebuffer that decrefs it.

There's no need for that, PyBuffer_Release() does the decref.
But PyBuffer_Release() must be used instead of calling bf_releasebuffer
directly.
msg71871 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-24 21:03
This new version of the patch modifies getargs.c and use
PyObject_GetBuffer and PyBuffer_Release in place of the raw bf_getbuffer
and bf_releasebuffer.
Also make sure that each GetBuffer is matched with a ReleaseBuffer
(except for s* and w*, where the calling code is responsible for this)

This seems to correct most of the refleaks mentioned above, except:

- test_unittest leaks 120 refs because the 'audioop' module is
re-imported many times. See issue3667, or the test case should be dropped.

- test_binascii leaks one time because of issue3668.
msg71883 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2008-08-24 21:38
Another PyBuffer_Release(&pin); looks necessary at @@ -805,6 +807,7 @@.
msg71899 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2008-08-24 23:20
With the latest patch (and the one addition PyBuffer_Release() I noted
above), valgrind is happy wrt memory leaks.  The only problem valgrind
found is a read of uninitialized memory.  See
http://bugs.python.org/issue3657 .

I don't know the buffer code to know if this is the correct fix. 
However, it fixes the problems and that's probably good enough for now.
 If you can get someone familiar with the buffer code to review, that
would be great.  If not, this patch should be applied.
msg71900 - (view) Author: Neal Norwitz (nnorwitz) * (Python committer) Date: 2008-08-24 23:21
Also there should be a Misc/NEWS entry added. Also check the doc to see
it needs updating wrt ownership.
msg71901 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-08-24 23:24
> I don't know the buffer code to know if this is the correct fix. 
> However, it fixes the problems and that's probably good enough for now.
>  If you can get someone familiar with the buffer code to review, that
> would be great.

I don't know if I pass as "someone familiar with the buffer code", but
Amaury's patch is ok to me.
msg71911 - (view) Author: Amaury Forgeot d'Arc (amaury.forgeotdarc) * (Python committer) Date: 2008-08-25 08:47
Updated patch with the additional PyBuffer_Release mentioned by Neal,
plus a proposition of entry for the NEWS file.

There is no doc about the new interface, so no update is needed :-( 
See issue2619.
msg71982 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2008-08-26 15:05
Amaury, assuming you have tested it :-), the patch is ok to me. You can
commit.
msg72003 - (view) Author: Benjamin Peterson (benjamin.peterson) * (Python committer) Date: 2008-08-27 00:31
Fixed in r66047.
History
Date User Action Args
2022-04-11 14:56:38adminsetgithub: 47901
2008-08-27 00:31:54benjamin.petersonsetstatus: open -> closed
resolution: fixed
messages: + msg72003
2008-08-26 15:05:38pitrousetmessages: + msg71982
2008-08-25 08:47:41amaury.forgeotdarcsetfiles: + buffer-leak.patch
messages: + msg71911
2008-08-24 23:24:42pitrousetmessages: + msg71901
2008-08-24 23:21:30nnorwitzsettype: resource usage
messages: + msg71900
2008-08-24 23:20:14nnorwitzsetmessages: + msg71899
2008-08-24 21:38:22nnorwitzsetmessages: + msg71883
2008-08-24 21:03:48amaury.forgeotdarcsetfiles: + buffer-leak.patch
messages: + msg71871
2008-08-24 11:23:46pitrousetmessages: + msg71835
2008-08-24 09:47:41amaury.forgeotdarclinkissue3656 superseder
2008-08-24 09:18:35amaury.forgeotdarcsetmessages: + msg71834
2008-08-24 07:14:43nnorwitzsetmessages: + msg71832
2008-08-24 05:51:19nnorwitzsetnosy: + nnorwitz
messages: + msg71828
2008-08-23 23:26:45pitrousetnosy: + pitrou
messages: + msg71821
2008-08-23 22:38:45brett.cannonsetnosy: + brett.cannon
messages: + msg71819
2008-08-23 00:35:43amaury.forgeotdarcsetassignee: loewis
nosy: + loewis
2008-08-23 00:02:32amaury.forgeotdarcsetfiles: - buffer-leak.patch
2008-08-23 00:02:20amaury.forgeotdarcsetfiles: + buffer-leak.patch
messages: + msg71795
2008-08-22 23:10:12amaury.forgeotdarcsetfiles: - buffer-leak.patch
2008-08-22 23:10:03amaury.forgeotdarcsetfiles: + buffer-leak.patch
messages: + msg71792
2008-08-22 22:55:21amaury.forgeotdarcsetkeywords: + needs review, patch
files: + buffer-leak.patch
messages: + msg71791
2008-08-22 22:47:30christian.heimessetmessages: + msg71790
2008-08-22 22:37:06amaury.forgeotdarcsetmessages: + msg71789
2008-08-22 22:28:14christian.heimessetmessages: + msg71788
2008-08-22 22:24:20benjamin.petersonsetnosy: + benjamin.peterson
messages: + msg71787
2008-08-22 22:20:04amaury.forgeotdarcsetmessages: + msg71785
2008-08-22 22:17:54christian.heimessetnosy: + christian.heimes
messages: + msg71784
2008-08-22 22:09:42amaury.forgeotdarccreate