summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAngus Gratton <angus@redyak.com.au>2025-07-22 10:48:16 +1000
committerDamien George <damien@micropython.org>2025-07-24 15:50:00 +1000
commit5d9ef6bfb696106f8052a44c1e392695e908eafa (patch)
tree0c9cfb920a896df12d99545a851ae1faa9877ec1
parent3185bb5827acd6a1f27a9299abee52640dd495f2 (diff)
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 <angus@redyak.com.au>
-rw-r--r--py/objint_longlong.c10
1 files 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: