Skip to content

Commit d7073e5

Browse files
committed
gh-143050: add helper _PyLong_Init()
With this we can assume, that _PyLong_Set*() operate on non-immortal integers.
1 parent 9e1f164 commit d7073e5

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

Include/internal/pycore_long.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,21 @@ _PyLong_SameSign(const PyLongObject *a, const PyLongObject *b)
285285
return (a->long_value.lv_tag & SIGN_MASK) == (b->long_value.lv_tag & SIGN_MASK);
286286
}
287287

288+
/* Initialize a freshly-allocated int.
289+
*
290+
* Fast operations for single digit integers (including zero)
291+
* assume that there is always at least one digit present.
292+
* The digit has to be initialized explicitly to avoid
293+
* use-of-uninitialized-value.
294+
*/
295+
static inline void
296+
_PyLong_Init(PyLongObject *op)
297+
{
298+
assert(PyLong_Check(op));
299+
op->long_value.lv_tag = 1; /* non-immortal zero */
300+
op->long_value.ob_digit[0] = 0;
301+
}
302+
288303
#define TAG_FROM_SIGN_AND_SIZE(sign, size) \
289304
((uintptr_t)(1 - (sign)) | ((uintptr_t)(size) << NON_SIZE_BITS))
290305

@@ -294,13 +309,15 @@ _PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size)
294309
assert(size >= 0);
295310
assert(-1 <= sign && sign <= 1);
296311
assert(sign != 0 || size == 0);
312+
assert(!_PyLong_IsSmallInt(op));
297313
op->long_value.lv_tag = TAG_FROM_SIGN_AND_SIZE(sign, size);
298314
}
299315

300316
static inline void
301317
_PyLong_SetDigitCount(PyLongObject *op, Py_ssize_t size)
302318
{
303319
assert(size >= 0);
320+
assert(!_PyLong_IsSmallInt(op));
304321
op->long_value.lv_tag = (((size_t)size) << NON_SIZE_BITS) | (op->long_value.lv_tag & SIGN_MASK);
305322
}
306323

Objects/longobject.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,9 @@ long_alloc(Py_ssize_t size)
185185
return NULL;
186186
}
187187
_PyObject_Init((PyObject*)result, &PyLong_Type);
188+
_PyLong_Init(result);
188189
}
189190
_PyLong_SetSignAndDigitCount(result, size != 0, size);
190-
/* The digit has to be initialized explicitly to avoid
191-
* use-of-uninitialized-value. */
192-
result->long_value.ob_digit[0] = 0;
193191
return result;
194192
}
195193

@@ -258,6 +256,7 @@ _PyLong_FromMedium(sdigit x)
258256
return NULL;
259257
}
260258
_PyObject_Init((PyObject*)v, &PyLong_Type);
259+
_PyLong_Init(v);
261260
}
262261
digit abs_x = x < 0 ? -x : x;
263262
_PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1);
@@ -337,6 +336,7 @@ medium_from_stwodigits(stwodigits x)
337336
return PyStackRef_NULL;
338337
}
339338
_PyObject_Init((PyObject*)v, &PyLong_Type);
339+
_PyLong_Init(v);
340340
}
341341
digit abs_x = x < 0 ? (digit)(-x) : (digit)x;
342342
_PyLong_SetSignAndDigitCount(v, x<0?-1:1, 1);
@@ -6011,29 +6011,34 @@ static PyObject *
60116011
long_subtype_new(PyTypeObject *type, PyObject *x, PyObject *obase)
60126012
{
60136013
PyLongObject *tmp, *newobj;
6014-
Py_ssize_t i, n;
6014+
Py_ssize_t size, ndigits;
6015+
int sign;
60156016

60166017
assert(PyType_IsSubtype(type, &PyLong_Type));
60176018
tmp = (PyLongObject *)long_new_impl(&PyLong_Type, x, obase);
60186019
if (tmp == NULL)
60196020
return NULL;
60206021
assert(PyLong_Check(tmp));
6021-
n = _PyLong_DigitCount(tmp);
6022+
size = _PyLong_DigitCount(tmp);
60226023
/* Fast operations for single digit integers (including zero)
60236024
* assume that there is always at least one digit present. */
6024-
if (n == 0) {
6025-
n = 1;
6026-
}
6027-
newobj = (PyLongObject *)type->tp_alloc(type, n);
6025+
ndigits = size ? size : 1;
6026+
newobj = (PyLongObject *)type->tp_alloc(type, ndigits);
60286027
if (newobj == NULL) {
60296028
Py_DECREF(tmp);
60306029
return NULL;
60316030
}
60326031
assert(PyLong_Check(newobj));
6033-
newobj->long_value.lv_tag = tmp->long_value.lv_tag & ~IMMORTALITY_BIT_MASK;
6034-
for (i = 0; i < n; i++) {
6035-
newobj->long_value.ob_digit[i] = tmp->long_value.ob_digit[i];
6032+
if (_PyLong_IsCompact(tmp)) {
6033+
sign = _PyLong_CompactSign(tmp);
6034+
}
6035+
else {
6036+
sign = _PyLong_NonCompactSign(tmp);
60366037
}
6038+
_PyLong_Init(newobj);
6039+
_PyLong_SetSignAndDigitCount(newobj, sign, size);
6040+
memcpy(newobj->long_value.ob_digit, tmp->long_value.ob_digit,
6041+
ndigits * sizeof(digit));
60376042
Py_DECREF(tmp);
60386043
return (PyObject *)newobj;
60396044
}

0 commit comments

Comments
 (0)