Skip to content

Commit 5dcc06f

Browse files
authored
bpo-38858: Allocate small integers on the heap (GH-17301)
Allocate small Python integers (small_ints of longobject.c) on the heap, rather than using static objects.
1 parent d672791 commit 5dcc06f

File tree

1 file changed

+19
-36
lines changed

1 file changed

+19
-36
lines changed

Objects/longobject.c

+19-36
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ PyObject *_PyLong_One = NULL;
4040
The integers that are preallocated are those in the range
4141
-NSMALLNEGINTS (inclusive) to NSMALLPOSINTS (not inclusive).
4242
*/
43-
static PyLongObject small_ints[NSMALLNEGINTS + NSMALLPOSINTS];
43+
static PyLongObject* small_ints[NSMALLNEGINTS + NSMALLPOSINTS] = {0};
4444

4545
#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
4646
#define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS)
@@ -52,9 +52,8 @@ Py_ssize_t _Py_quick_int_allocs, _Py_quick_neg_int_allocs;
5252
static PyObject *
5353
get_small_int(sdigit ival)
5454
{
55-
PyObject *v;
5655
assert(IS_SMALL_INT(ival));
57-
v = (PyObject *)&small_ints[ival + NSMALLNEGINTS];
56+
PyObject *v = (PyObject*)small_ints[ival + NSMALLNEGINTS];
5857
Py_INCREF(v);
5958
#ifdef COUNT_ALLOCS
6059
if (ival >= 0)
@@ -5784,40 +5783,30 @@ int
57845783
_PyLong_Init(void)
57855784
{
57865785
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
5787-
int ival, size;
5788-
PyLongObject *v = small_ints;
5789-
5790-
for (ival = -NSMALLNEGINTS; ival < NSMALLPOSINTS; ival++, v++) {
5791-
size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1);
5792-
if (Py_TYPE(v) == &PyLong_Type) {
5793-
/* The element is already initialized, most likely
5794-
* the Python interpreter was initialized before.
5795-
*/
5796-
Py_ssize_t refcnt;
5797-
PyObject* op = (PyObject*)v;
5798-
5799-
refcnt = Py_REFCNT(op) < 0 ? 0 : Py_REFCNT(op);
5800-
_Py_NewReference(op);
5801-
/* _Py_NewReference sets the ref count to 1 but
5802-
* the ref count might be larger. Set the refcnt
5803-
* to the original refcnt + 1 */
5804-
Py_REFCNT(op) = refcnt + 1;
5805-
assert(Py_SIZE(op) == size);
5806-
assert(v->ob_digit[0] == (digit)abs(ival));
5807-
}
5808-
else {
5809-
(void)PyObject_INIT(v, &PyLong_Type);
5786+
for (Py_ssize_t i=0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) {
5787+
sdigit ival = (sdigit)i - NSMALLNEGINTS;
5788+
int size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1);
5789+
5790+
PyLongObject *v = _PyLong_New(1);
5791+
if (!v) {
5792+
return -1;
58105793
}
5794+
58115795
Py_SIZE(v) = size;
58125796
v->ob_digit[0] = (digit)abs(ival);
5797+
5798+
small_ints[i] = v;
58135799
}
58145800
#endif
58155801
_PyLong_Zero = PyLong_FromLong(0);
5816-
if (_PyLong_Zero == NULL)
5802+
if (_PyLong_Zero == NULL) {
58175803
return 0;
5804+
}
5805+
58185806
_PyLong_One = PyLong_FromLong(1);
5819-
if (_PyLong_One == NULL)
5807+
if (_PyLong_One == NULL) {
58205808
return 0;
5809+
}
58215810

58225811
/* initialize int_info */
58235812
if (Int_InfoType.tp_name == NULL) {
@@ -5832,17 +5821,11 @@ _PyLong_Init(void)
58325821
void
58335822
_PyLong_Fini(void)
58345823
{
5835-
/* Integers are currently statically allocated. Py_DECREF is not
5836-
needed, but Python must forget about the reference or multiple
5837-
reinitializations will fail. */
58385824
Py_CLEAR(_PyLong_One);
58395825
Py_CLEAR(_PyLong_Zero);
58405826
#if NSMALLNEGINTS + NSMALLPOSINTS > 0
5841-
int i;
5842-
PyLongObject *v = small_ints;
5843-
for (i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++, v++) {
5844-
_Py_DEC_REFTOTAL;
5845-
_Py_ForgetReference((PyObject*)v);
5827+
for (Py_ssize_t i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) {
5828+
Py_CLEAR(small_ints[i]);
58465829
}
58475830
#endif
58485831
}

0 commit comments

Comments
 (0)