Skip to content

Commit fa97302

Browse files
committed
fix memory leak; align with float implementation
1 parent 3f50b54 commit fa97302

File tree

6 files changed

+66
-35
lines changed

6 files changed

+66
-35
lines changed

Include/internal/pycore_long.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ extern void _PyLong_FiniTypes(PyInterpreterState *interp);
5555

5656
/* other API */
5757

58-
void _PyLong_Free(PyLongObject *op);
58+
void
59+
_PyLong_ExactDealloc(PyObject *self);
5960

6061
#define _PyLong_SMALL_INTS _Py_SINGLETON(small_ints)
6162

Objects/longobject.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ static inline void
4343
_Py_DECREF_INT(PyLongObject *op)
4444
{
4545
assert(PyLong_CheckExact(op));
46-
_Py_DECREF_SPECIALIZED((PyObject *)op, (destructor)_PyLong_Free);
46+
_Py_DECREF_SPECIALIZED((PyObject *)op, (destructor)_PyLong_ExactDealloc);
4747
}
4848

4949
static inline int
@@ -3616,9 +3616,39 @@ long_richcompare(PyObject *self, PyObject *other, int op)
36163616
Py_RETURN_RICHCOMPARE(result, 0, op);
36173617
}
36183618

3619+
void
3620+
_PyLong_ExactDealloc(PyObject *self)
3621+
{
3622+
assert(PyLong_CheckExact(self));
3623+
3624+
if (_PyLong_IsCompact((PyLongObject *)self)) {
3625+
_Py_FREELIST_FREE(ints, self, PyObject_Free);
3626+
return;
3627+
}
3628+
PyObject_Free(self);
3629+
}
3630+
36193631
static void
36203632
long_dealloc(PyObject *self)
36213633
{
3634+
PyLongObject *pylong = (PyLongObject*)self;
3635+
3636+
if (pylong && _PyLong_IsCompact(pylong)) {
3637+
stwodigits ival = medium_value(pylong);
3638+
if (IS_SMALL_INT(ival)) {
3639+
PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival);
3640+
if (pylong == small_pylong) {
3641+
/* This should never get called, but we also don't want to SEGV if
3642+
* we accidentally decref small Ints out of existence. Instead,
3643+
* since small Ints are immortal, re-set the reference count.
3644+
*/
3645+
// can we remove the next two lines? the immortal objects now have a fixed refcount
3646+
// in particular in the free-threading build this seeems safe
3647+
_Py_SetImmortal(self);
3648+
return;
3649+
}
3650+
}
3651+
}
36223652
Py_TYPE(self)->tp_free(self);
36233653
}
36243654

@@ -6613,7 +6643,7 @@ PyTypeObject PyLong_Type = {
66136643
0, /* tp_init */
66146644
0, /* tp_alloc */
66156645
long_new, /* tp_new */
6616-
(freefunc)_PyLong_Free, /* tp_free */
6646+
(freefunc)PyObject_Free, /* tp_free */
66176647
.tp_vectorcall = long_vectorcall,
66186648
.tp_version_tag = _Py_TYPE_VERSION_INT,
66196649
};

Objects/object.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,6 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization)
889889
// In the free-threaded build, freelists are per-PyThreadState and cleared in PyThreadState_Clear()
890890
// In the default build, freelists are per-interpreter and cleared in finalize_interp_types()
891891
clear_freelist(&freelists->floats, is_finalization, free_object);
892-
clear_freelist(&freelists->ints, is_finalization, free_object);
893892
for (Py_ssize_t i = 0; i < PyTuple_MAXSAVESIZE; i++) {
894893
clear_freelist(&freelists->tuples[i], is_finalization, free_object);
895894
}
@@ -907,6 +906,7 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization)
907906
clear_freelist(&freelists->object_stack_chunks, 1, PyMem_RawFree);
908907
}
909908
clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free);
909+
clear_freelist(&freelists->ints, is_finalization, free_object);
910910
}
911911

912912
/*

Python/bytecodes.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
2727
#include "pycore_pystate.h" // _PyInterpreterState_GET()
2828
#include "pycore_range.h" // _PyRangeIterObject
29-
#include "pycore_long.h" // void _PyLong_Free(PyLongObject *op);
29+
#include "pycore_long.h" // void _PyLong_ExactDealloc(PyLongObject *op);
3030
#include "pycore_setobject.h" // _PySet_NextEntry()
3131
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
3232
#include "pycore_tuple.h" // _PyTuple_ITEMS()
@@ -515,8 +515,8 @@ dummy_func(
515515

516516
STAT_INC(BINARY_OP, hit);
517517
PyObject *res_o = _PyLong_Multiply((PyLongObject *)left_o, (PyLongObject *)right_o);
518-
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
519-
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
518+
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_ExactDealloc);
519+
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_ExactDealloc);
520520
INPUTS_DEAD();
521521
ERROR_IF(res_o == NULL, error);
522522
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -528,8 +528,8 @@ dummy_func(
528528

529529
STAT_INC(BINARY_OP, hit);
530530
PyObject *res_o = _PyLong_Add((PyLongObject *)left_o, (PyLongObject *)right_o);
531-
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
532-
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
531+
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_ExactDealloc);
532+
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_ExactDealloc);
533533
INPUTS_DEAD();
534534
ERROR_IF(res_o == NULL, error);
535535
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -541,8 +541,8 @@ dummy_func(
541541

542542
STAT_INC(BINARY_OP, hit);
543543
PyObject *res_o = _PyLong_Subtract((PyLongObject *)left_o, (PyLongObject *)right_o);
544-
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_Free);
545-
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_Free);
544+
PyStackRef_CLOSE_SPECIALIZED(right, (destructor)_PyLong_ExactDealloc);
545+
PyStackRef_CLOSE_SPECIALIZED(left, (destructor)_PyLong_ExactDealloc);
546546
INPUTS_DEAD();
547547
ERROR_IF(res_o == NULL, error);
548548
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -798,7 +798,7 @@ dummy_func(
798798
PyObject *res_o = PyList_GET_ITEM(list, index);
799799
assert(res_o != NULL);
800800
Py_INCREF(res_o);
801-
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
801+
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_ExactDealloc);
802802
DEAD(sub_st);
803803
PyStackRef_CLOSE(list_st);
804804
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -818,7 +818,7 @@ dummy_func(
818818
DEOPT_IF(Py_ARRAY_LENGTH(_Py_SINGLETON(strings).ascii) <= c);
819819
STAT_INC(BINARY_SUBSCR, hit);
820820
PyObject *res_o = (PyObject*)&_Py_SINGLETON(strings).ascii[c];
821-
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
821+
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_ExactDealloc);
822822
DEAD(sub_st);
823823
PyStackRef_CLOSE(str_st);
824824
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -839,7 +839,7 @@ dummy_func(
839839
PyObject *res_o = PyTuple_GET_ITEM(tuple, index);
840840
assert(res_o != NULL);
841841
Py_INCREF(res_o);
842-
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free);
842+
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_ExactDealloc);
843843
DEAD(sub_st);
844844
PyStackRef_CLOSE(tuple_st);
845845
res = PyStackRef_FromPyObjectSteal(res_o);
@@ -951,7 +951,7 @@ dummy_func(
951951
PyList_SET_ITEM(list, index, PyStackRef_AsPyObjectSteal(value));
952952
assert(old_value != NULL);
953953
Py_DECREF(old_value);
954-
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_Free );
954+
PyStackRef_CLOSE_SPECIALIZED(sub_st, (destructor)_PyLong_ExactDealloc );
955955
DEAD(sub_st);
956956
PyStackRef_CLOSE(list_st);
957957
}

Python/executor_cases.c.h

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)