From 5d9ef6bfb696106f8052a44c1e392695e908eafa Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Tue, 22 Jul 2025 10:48:16 +1000 Subject: [PATCH] py/objint_longlong: Fix left shift of negative values. Previous comment was wrong, left shifting a negative value is UB in C. Use the same approach as small int shifts (from runtime.c). Signed-off-by: Angus Gratton --- py/objint_longlong.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 22ac0ba12..339ce7cfd 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -208,14 +208,14 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i case MP_BINARY_OP_LSHIFT: case MP_BINARY_OP_INPLACE_LSHIFT: - if ((int)rhs_val < 0) { + if (rhs_val < 0) { // negative shift not allowed mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); } - result = lhs_val << (int)rhs_val; - // Left-shifting of negative values is implementation defined in C, but assume compiler - // will give us typical 2s complement behaviour unless the value overflows - overflow = rhs_val > 0 && ((lhs_val >= 0 && result < lhs_val) || (lhs_val < 0 && result > lhs_val)); + overflow = rhs_val >= (sizeof(long long) * MP_BITS_PER_BYTE) + || lhs_val > (LLONG_MAX >> rhs_val) + || lhs_val < (LLONG_MIN >> rhs_val); + result = (unsigned long long)lhs_val << rhs_val; break; case MP_BINARY_OP_RSHIFT: case MP_BINARY_OP_INPLACE_RSHIFT: