Skip to content

Commit 004dce0

Browse files
committed
add lshift; avoid undefined behavior
1 parent e6af9b2 commit 004dce0

2 files changed

Lines changed: 25 additions & 4 deletions

File tree

Lib/test/test_opcache.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,6 +1422,12 @@ def binary_op_bitwise_extend():
14221422
a, b = 10, 2
14231423
a >>= b
14241424
self.assertEqual(a, 2)
1425+
a, b = 10, 2
1426+
a = a << b
1427+
self.assertEqual(a, 40)
1428+
a, b = 10, 2
1429+
a <<= b
1430+
self.assertEqual(a, 40)
14251431

14261432
binary_op_bitwise_extend()
14271433
self.assert_specialized(binary_op_bitwise_extend, "BINARY_OP_EXTEND")

Python/specialize.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,8 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, PyObject *consts,
585585
#define SPEC_FAIL_BINARY_OP_OR_DIFFERENT_TYPES 30
586586
#define SPEC_FAIL_BINARY_OP_XOR_INT 31
587587
#define SPEC_FAIL_BINARY_OP_XOR_DIFFERENT_TYPES 32
588+
#define SPEC_FAIL_BINARY_OP_LSHIFT_INT 33
589+
#define SPEC_FAIL_BINARY_OP_LSHIFT_DIFFERENT_TYPES 34
588590
#define SPEC_FAIL_BINARY_OP_RSHIFT_INT 33
589591
#define SPEC_FAIL_BINARY_OP_RSHIFT_DIFFERENT_TYPES 34
590592

@@ -2373,6 +2375,12 @@ binary_op_fail_kind(int oparg, PyObject *lhs, PyObject *rhs)
23732375
return SPEC_FAIL_BINARY_OP_FLOOR_DIVIDE;
23742376
case NB_LSHIFT:
23752377
case NB_INPLACE_LSHIFT:
2378+
if (!Py_IS_TYPE(lhs, Py_TYPE(rhs))) {
2379+
return SPEC_FAIL_BINARY_OP_LSHIFT_DIFFERENT_TYPES;
2380+
}
2381+
if (PyLong_CheckExact(lhs)) {
2382+
return SPEC_FAIL_BINARY_OP_LSHIFT_INT;
2383+
}
23762384
return SPEC_FAIL_BINARY_OP_LSHIFT;
23772385
case NB_MATRIX_MULTIPLY:
23782386
case NB_INPLACE_MATRIX_MULTIPLY:
@@ -2461,9 +2469,13 @@ compactlongs_guard(PyObject *lhs, PyObject *rhs)
24612469
}
24622470

24632471
static int
2464-
compactlong_compactnonnegativelong_guard(PyObject *lhs, PyObject *rhs)
2472+
shift_guard(PyObject *lhs, PyObject *rhs)
24652473
{
2466-
return (is_compactlong(lhs) && is_compactnonnegativelong(rhs));
2474+
// we could use _long_is_small_int here, which is slightly faster than is_compactnonnegativelong
2475+
2476+
// rshift with value larger the the number of bits is undefined in C
2477+
// for lshift we do not want to overflow, but we always have at least 16 bits available
2478+
return (is_compactlong(lhs) && is_compactnonnegativelong(rhs) && (_PyLong_CompactValue((PyLongObject *)rhs) <= 16) );
24672479
}
24682480

24692481
#define BITWISE_LONGS_ACTION(NAME, OP) \
@@ -2477,6 +2489,7 @@ compactlong_compactnonnegativelong_guard(PyObject *lhs, PyObject *rhs)
24772489
BITWISE_LONGS_ACTION(compactlongs_or, |)
24782490
BITWISE_LONGS_ACTION(compactlongs_and, &)
24792491
BITWISE_LONGS_ACTION(compactlongs_xor, ^)
2492+
BITWISE_LONGS_ACTION(compactlongs_lshift, <<)
24802493
BITWISE_LONGS_ACTION(compactlongs_rshift, >>)
24812494
#undef BITWISE_LONGS_ACTION
24822495

@@ -2554,11 +2567,13 @@ static _PyBinaryOpSpecializationDescr compactlongs_specs[NB_OPARG_LAST+1] = {
25542567
[NB_OR] = {compactlongs_guard, compactlongs_or},
25552568
[NB_AND] = {compactlongs_guard, compactlongs_and},
25562569
[NB_XOR] = {compactlongs_guard, compactlongs_xor},
2557-
[NB_RSHIFT] = {compactlong_compactnonnegativelong_guard, compactlongs_rshift},
2570+
[NB_LSHIFT] = {shift_guard, compactlongs_lshift},
2571+
[NB_RSHIFT] = {shift_guard, compactlongs_rshift},
25582572
[NB_INPLACE_OR] = {compactlongs_guard, compactlongs_or},
25592573
[NB_INPLACE_AND] = {compactlongs_guard, compactlongs_and},
25602574
[NB_INPLACE_XOR] = {compactlongs_guard, compactlongs_xor},
2561-
[NB_INPLACE_RSHIFT] = {compactlong_compactnonnegativelong_guard, compactlongs_rshift},
2575+
[NB_INPLACE_LSHIFT] = {shift_guard, compactlongs_lshift},
2576+
[NB_INPLACE_RSHIFT] = {shift_guard, compactlongs_rshift},
25622577
};
25632578

25642579
static _PyBinaryOpSpecializationDescr float_compactlong_specs[NB_OPARG_LAST+1] = {

0 commit comments

Comments
 (0)