Skip to content

Commit a14685f

Browse files
committed
gh-147988: Initialize digits in long_alloc() in debug mode
When Python is built in debug mode, long_alloc() now initializes digits with a pattern to detect usage of uninitialized digits. _PyLong_CompactValue() makes sure that the digit is zero when the sign is zero.
1 parent 9e5b838 commit a14685f

File tree

2 files changed

+19
-7
lines changed

2 files changed

+19
-7
lines changed

Include/cpython/longintrepr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ _PyLong_CompactValue(const PyLongObject *op)
133133
assert(PyType_HasFeature(op->ob_base.ob_type, Py_TPFLAGS_LONG_SUBCLASS));
134134
assert(PyUnstable_Long_IsCompact(op));
135135
sign = 1 - (op->long_value.lv_tag & _PyLong_SIGN_MASK);
136+
if (sign == 0) {
137+
// gh-147988: Make sure that the digit is zero,
138+
// it helps detecting usage of uninitialized digits.
139+
assert(op->long_value.ob_digit[0] == 0);
140+
}
136141
return sign * (Py_ssize_t)op->long_value.ob_digit[0];
137142
}
138143

Objects/longobject.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,11 @@ long_alloc(Py_ssize_t size)
187187
_PyObject_Init((PyObject*)result, &PyLong_Type);
188188
}
189189
_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;
190+
#ifdef Py_DEBUG
191+
// gh-147988: Fill digits with an invalid pattern to catch usage
192+
// of uninitialized digits.
193+
memset(result->long_value.ob_digit, 0xFF, ndigits * sizeof(digit));
194+
#endif
193195
return result;
194196
}
195197

@@ -1094,6 +1096,7 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
10941096
int sign = is_signed ? -1: 1;
10951097
if (idigit == 0) {
10961098
sign = 0;
1099+
v->long_value.ob_digit[0] = 0;
10971100
}
10981101
_PyLong_SetSignAndDigitCount(v, sign, idigit);
10991102
return (PyObject *)maybe_small_long(long_normalize(v));
@@ -2852,6 +2855,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits,
28522855
*res = NULL;
28532856
return 0;
28542857
}
2858+
z->long_value.ob_digit[0] = 0;
28552859
_PyLong_SetSignAndDigitCount(z, 0, 0);
28562860

28572861
/* `convwidth` consecutive input digits are treated as a single
@@ -3365,6 +3369,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
33653369
*prem = NULL;
33663370
return NULL;
33673371
}
3372+
a->long_value.ob_digit[0] = 0;
33683373
v0 = v->long_value.ob_digit;
33693374
w0 = w->long_value.ob_digit;
33703375
wm1 = w0[size_w-1];
@@ -4141,10 +4146,6 @@ k_mul(PyLongObject *a, PyLongObject *b)
41414146
/* 1. Allocate result space. */
41424147
ret = long_alloc(asize + bsize);
41434148
if (ret == NULL) goto fail;
4144-
#ifdef Py_DEBUG
4145-
/* Fill with trash, to catch reference to uninitialized digits. */
4146-
memset(ret->long_value.ob_digit, 0xDF, _PyLong_DigitCount(ret) * sizeof(digit));
4147-
#endif
41484149

41494150
/* 2. t1 <- ah*bh, and copy into high digits of result. */
41504151
if ((t1 = k_mul(ah, bh)) == NULL) goto fail;
@@ -5633,6 +5634,12 @@ long_bitwise(PyLongObject *a,
56335634
Py_UNREACHABLE();
56345635
}
56355636

5637+
if ((size_z + negz) == 0) {
5638+
Py_XDECREF(new_a);
5639+
Py_XDECREF(new_b);
5640+
return get_small_int(0);
5641+
}
5642+
56365643
/* We allow an extra digit if z is negative, to make sure that
56375644
the final two's complement of z doesn't overflow. */
56385645
z = long_alloc(size_z + negz);

0 commit comments

Comments
 (0)