Skip to content

Commit 539d6bf

Browse files
committed
fix c undefined behaviour
1 parent 92bc898 commit 539d6bf

1 file changed

Lines changed: 13 additions & 11 deletions

File tree

Python/specialize.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2213,15 +2213,6 @@ shift_guard(PyObject *lhs, PyObject *rhs)
22132213
return (is_compactlong(lhs) && is_compactnonnegativelong(rhs) && (_PyLong_CompactValue((PyLongObject *)rhs) <= 16) );
22142214
}
22152215

2216-
#define BITWISE_LONGS_ACTION_STWODIGITS(NAME, OP) \
2217-
static PyObject * \
2218-
(NAME)(PyObject *lhs, PyObject *rhs) \
2219-
{ \
2220-
stwodigits rhs_val = (stwodigits)_PyLong_CompactValue((PyLongObject *)rhs); \
2221-
stwodigits lhs_val = (stwodigits) _PyLong_CompactValue((PyLongObject *)lhs); \
2222-
return PyLong_FromLongLong(lhs_val OP rhs_val); \
2223-
}
2224-
22252216
#define BITWISE_LONGS_ACTION(NAME, OP) \
22262217
static PyObject * \
22272218
(NAME)(PyObject *lhs, PyObject *rhs) \
@@ -2233,11 +2224,22 @@ shift_guard(PyObject *lhs, PyObject *rhs)
22332224
BITWISE_LONGS_ACTION(compactlongs_or, |)
22342225
BITWISE_LONGS_ACTION(compactlongs_and, &)
22352226
BITWISE_LONGS_ACTION(compactlongs_xor, ^)
2236-
BITWISE_LONGS_ACTION_STWODIGITS(compactlongs_lshift, <<)
22372227
BITWISE_LONGS_ACTION(compactlongs_rshift, >>)
2238-
#undef BITWISE_LONGS_ACTION_STWODIGITS
22392228
#undef BITWISE_LONGS_ACTION
22402229

2230+
static PyObject *
2231+
compactlongs_lshift(PyObject *lhs, PyObject *rhs)
2232+
{
2233+
// Left-shifting a negative signed value is undefined behavior in C, so
2234+
// perform the shift in unsigned arithmetic and reinterpret. The guard
2235+
// limits rhs_val to [0, 16] and compact long magnitudes fit comfortably
2236+
// in stwodigits with that headroom, so no overflow occurs.
2237+
Py_ssize_t rhs_val = _PyLong_CompactValue((PyLongObject *)rhs);
2238+
Py_ssize_t lhs_val = _PyLong_CompactValue((PyLongObject *)lhs);
2239+
stwodigits result = (stwodigits)((unsigned long long)lhs_val << rhs_val);
2240+
return PyLong_FromLongLong(result);
2241+
}
2242+
22412243
/* float-long */
22422244

22432245
static inline int

0 commit comments

Comments
 (0)