Security context
Medium· 5.3PYSEC-2025-201 CVE-2025-46152Published Sep 25, 2025

In PyTorch before 2.7.0, bitwise_right_shift produces incorrect output for certain out-of-bounds values of the "other" argument.

Research this vulnerability

Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.

Affected versions

2.6.0 → fixed in 2.7.0

Details

In PyTorch before 2.7.0, bitwise_right_shift produces incorrect output for certain out-of-bounds values of the "other" argument.

The fix

Update

leslie-fang-intel· Dec 20, 2024, 07:03 AM+661921270f31e7
test/inductor/test_cpu_repro.py+18 0
@@ -2281,6 +2281,24 @@ def test_bitwise_right_shift(self):
res = cfn(x, bit_num)
self.assertEqual(res_aten_eager, res)
+ def test_bitwise_shift_right_corner_inputs(self):
+ # Fix https://github.com/pytorch/pytorch/issues/143555
+ x = torch.tensor(1000, dtype=torch.int64)
+ bit_num = torch.tensor(64, dtype=torch.int64)
+ res_aten_eager = torch.bitwise_right_shift(x, bit_num)
+ cfn = torch.compile(torch.bitwise_right_shift)
+ res = cfn(x, bit_num)
+ self.assertEqual(res_aten_eager, res)
+
+ def test_bitwise_shift_left_corner_inputs(self):
+ # Fix https://github.com/pytorch/pytorch/issues/143555
+ x = torch.tensor(1000, dtype=torch.int64)
+ bit_num = torch.tensor(64, dtype=torch.int64)
+ res_aten_eager = torch.bitwise_left_shift(x, bit_num)
+ cfn = torch.compile(torch.bitwise_left_shift)
+ res = cfn(x, bit_num)
+ self.assertEqual(res_aten_eager, res)
+
def test_view_dtype(self):
def f(x):
return x.view(torch.int32) >> 2
torch/_inductor/codegen/cpp.py+32 2
@@ -973,11 +973,41 @@ def bitwise_xor(a, b):
@staticmethod
def bitwise_left_shift(a, b):
- return f"decltype({a})({a} << {b})"
+ code = BracesBuffer()
+ code.writeline("[&]()")
+ with code.indent():
+ scalar_t = DTYPE_TO_CPP[a.dtype]
+ code.writeline(
+ f"constexpr decltype({b}) max_shift = sizeof({scalar_t}) * CHAR_BIT;"
+ )
+ code.writeline(
+ f"if ((static_cast<std::make_signed_t<{scalar_t}>>({b}) < 0) || ({b} >= max_shift))"
+ )
+ with code.indent():
+ code.writeline(f"return decltype({a})(0);")
+ code.writeline(
+ f"return decltype({a})(static_cast<std::make_unsigned_t<{scalar_t}>>({a}) << {b});"
+ )
+ code.writeline("()")
+ return code
@staticmethod
def bitwise_right_shift(a, b):
- return f"decltype({a})({a} >> {b})"
+ code = BracesBuffer()
+ code.writeline("[&]()")
+ with code.indent():
+ scalar_t = DTYPE_TO_CPP[a.dtype]
+ code.writeline(
+ f"constexpr decltype({b}) max_shift = sizeof({scalar_t}) * CHAR_BIT - std::is_signed_v<{scalar_t}>;"
+ )
+ code.writeline(
+ f"if ((static_cast<std::make_signed_t<{scalar_t}>>({b}) < 0) || ({b} >= max_shift))"
+ )
+ with code.indent():
+ code.writeline(f"return decltype({a})({a} >> max_shift);")
+ code.writeline(f"return decltype({a})({a} >> {b});")
+ code.writeline("()")
+ return code
@staticmethod
def rand(seed: sympy.Expr, offset: sympy.Expr):
test/inductor/test_cpu_repro.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
test/inductor/test_cpu_repro.py+1 1
@@ -2291,7 +2291,7 @@ def test_bitwise_shift_right_corner_inputs(self):
self.assertEqual(res_aten_eager, res)
def test_bitwise_shift_left_corner_inputs(self):
- # Fix https://github.com/pytorch/pytorch/issues/143555
+ # Fix https://github.com/pytorch/pytorch/issues/143566
x = torch.tensor(1000, dtype=torch.int64)
bit_num = torch.tensor(64, dtype=torch.int64)
res_aten_eager = torch.bitwise_left_shift(x, bit_num)
test/inductor/test_cpu_repro.py | 31 +++++++++++++++----------------
1 file changed, 15 insertions(+), 16 deletions(-)
test/inductor/test_cpu_repro.py+15 16
@@ -2281,23 +2281,22 @@ def test_bitwise_right_shift(self):
res = cfn(x, bit_num)
self.assertEqual(res_aten_eager, res)
- def test_bitwise_shift_right_corner_inputs(self):
+ def test_bitwise_shift_corner_inputs(self):
# Fix https://github.com/pytorch/pytorch/issues/143555
- x = torch.tensor(1000, dtype=torch.int64)
- bit_num = torch.tensor(64, dtype=torch.int64)
- res_aten_eager = torch.bitwise_right_shift(x, bit_num)
- cfn = torch.compile(torch.bitwise_right_shift)
- res = cfn(x, bit_num)
- self.assertEqual(res_aten_eager, res)
-
- def test_bitwise_shift_left_corner_inputs(self):
- # Fix https://github.com/pytorch/pytorch/issues/143566
- x = torch.tensor(1000, dtype=torch.int64)
- bit_num = torch.tensor(64, dtype=torch.int64)
- res_aten_eager = torch.bitwise_left_shift(x, bit_num)
- cfn = torch.compile(torch.bitwise_left_shift)
- res = cfn(x, bit_num)
- self.assertEqual(res_aten_eager, res)
+ # and https://github.com/pytorch/pytorch/issues/143566
+ bitwise_fns = (
+ torch.bitwise_left_shift,
+ torch.bitwise_right_shift,
+ )
+ for bitwise_fn in bitwise_fns:
+ torch._dynamo.reset()
+ metrics.reset()
+ x = torch.tensor(1000, dtype=torch.int64)
+ bit_num = torch.tensor(64, dtype=torch.int64)
+ res_aten_eager = bitwise_fn(x, bit_num)
+ cfn = torch.compile(bitwise_fn)
+ res = cfn(x, bit_num)
+ self.assertEqual(res_aten_eager, res)
def test_view_dtype(self):
def f(x):

References