@@ -188,9 +188,11 @@ long_alloc(Py_ssize_t size)
188188 _PyLong_InitTag (result );
189189 }
190190 _PyLong_SetSignAndDigitCount (result , size != 0 , size );
191- /* The digit has to be initialized explicitly to avoid
192- * use-of-uninitialized-value. */
193- result -> long_value .ob_digit [0 ] = 0 ;
191+ #ifdef Py_DEBUG
192+ // gh-147988: Fill digits with an invalid pattern to catch usage
193+ // of uninitialized digits.
194+ memset (result -> long_value .ob_digit , 0xFF , ndigits * sizeof (digit ));
195+ #endif
194196 return result ;
195197}
196198
@@ -1097,6 +1099,7 @@ _PyLong_FromByteArray(const unsigned char* bytes, size_t n,
10971099 int sign = is_signed ? -1 : 1 ;
10981100 if (idigit == 0 ) {
10991101 sign = 0 ;
1102+ v -> long_value .ob_digit [0 ] = 0 ;
11001103 }
11011104 _PyLong_SetSignAndDigitCount (v , sign , idigit );
11021105 return (PyObject * )maybe_small_long (long_normalize (v ));
@@ -2855,6 +2858,7 @@ long_from_non_binary_base(const char *start, const char *end, Py_ssize_t digits,
28552858 * res = NULL ;
28562859 return 0 ;
28572860 }
2861+ z -> long_value .ob_digit [0 ] = 0 ;
28582862 _PyLong_SetSignAndDigitCount (z , 0 , 0 );
28592863
28602864 /* `convwidth` consecutive input digits are treated as a single
@@ -3368,6 +3372,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
33683372 * prem = NULL ;
33693373 return NULL ;
33703374 }
3375+ a -> long_value .ob_digit [0 ] = 0 ;
33713376 v0 = v -> long_value .ob_digit ;
33723377 w0 = w -> long_value .ob_digit ;
33733378 wm1 = w0 [size_w - 1 ];
@@ -4144,10 +4149,6 @@ k_mul(PyLongObject *a, PyLongObject *b)
41444149 /* 1. Allocate result space. */
41454150 ret = long_alloc (asize + bsize );
41464151 if (ret == NULL ) goto fail ;
4147- #ifdef Py_DEBUG
4148- /* Fill with trash, to catch reference to uninitialized digits. */
4149- memset (ret -> long_value .ob_digit , 0xDF , _PyLong_DigitCount (ret ) * sizeof (digit ));
4150- #endif
41514152
41524153 /* 2. t1 <- ah*bh, and copy into high digits of result. */
41534154 if ((t1 = k_mul (ah , bh )) == NULL ) goto fail ;
@@ -5636,6 +5637,12 @@ long_bitwise(PyLongObject *a,
56365637 Py_UNREACHABLE ();
56375638 }
56385639
5640+ if ((size_z + negz ) == 0 ) {
5641+ Py_XDECREF (new_a );
5642+ Py_XDECREF (new_b );
5643+ return get_small_int (0 );
5644+ }
5645+
56395646 /* We allow an extra digit if z is negative, to make sure that
56405647 the final two's complement of z doesn't overflow. */
56415648 z = long_alloc (size_z + negz );
@@ -6959,6 +6966,28 @@ PyLongWriter_Finish(PyLongWriter *writer)
69596966 PyLongObject * obj = (PyLongObject * )writer ;
69606967 assert (Py_REFCNT (obj ) == 1 );
69616968
6969+ #ifdef Py_DEBUG
6970+ // gh-147988: Detect uninitialized digits: long_alloc() fills digits with
6971+ // 0xFF byte pattern. It's posssible because PyLong_BASE is smaller than
6972+ // the maximum value of the C digit type (uint32_t or unsigned short):
6973+ // most significan bits are unused by the API.
6974+ Py_ssize_t ndigits = _PyLong_DigitCount (obj );
6975+ if (ndigits == 0 ) {
6976+ // Check ob_digit[0] digit for the number zero
6977+ ndigits = 1 ;
6978+ }
6979+ for (Py_ssize_t i = 0 ; i < ndigits ; i ++ ) {
6980+ digit d = obj -> long_value .ob_digit [i ];
6981+ if (d & ~(digit )PyLong_MASK ) {
6982+ Py_DECREF (obj );
6983+ PyErr_Format (PyExc_SystemError ,
6984+ "PyLongWriter_Finish: digit %zd is uninitialized" ,
6985+ i );
6986+ return NULL ;
6987+ }
6988+ }
6989+ #endif
6990+
69626991 // Normalize and get singleton if possible
69636992 obj = maybe_small_long (long_normalize (obj ));
69646993
0 commit comments