A Name Error occurs in pytorch v2.7.0 when a PyTorch model consists of torch.cummin and is compiled by Inductor, leading to a Denial of Service (DoS).
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
0 → fixed in 2.7.1
Details
A Name Error occurs in pytorch v2.7.0 when a PyTorch model consists of torch.cummin and is compiled by Inductor, leading to a Denial of Service (DoS).
The fix
Update
test/inductor/test_torchinductor.py+10 −0
@@ -2543,6 +2543,16 @@ def fn(x):self.common(fn, (torch.ones(32, 32) * 70,))+def test_cummin(self):+def fn(x):+return x.cummin(0)++self.common(+fn, (torch.rand(16, 32),), check_lowp=not is_halide_backend(self.device)+)+self.common(fn, (torch.rand(1),), check_lowp=not is_halide_backend(self.device))+self.common(fn, (torch.rand(0),), check_lowp=not is_halide_backend(self.device))+def test_cumsum(self):def fn(x):return x.cumsum(0), x.cumsum(1)
torch/_inductor/lowering.py+4 −4
@@ -6295,9 +6295,9 @@ def log_add_exp_helper(a_tuple, b_tuple):@register_lowering(aten.cummax, type_promotion_kind=None)def cummax(x, axis=None):-if len(x.get_size()) == 0:+if x.get_numel() <= 1:assert axis in [0, -1]-return clone(x), empty_like(x, dtype=torch.int64)+return clone(x), zeros_like(x, dtype=torch.int64)dtype = x.get_dtype()combine_fn = ir.get_reduction_combine_fn(@@ -6315,9 +6315,9 @@ def cummax(x, axis=None):@register_lowering(aten.cummin, type_promotion_kind=None)def cummin(x, axis=None):-if len(x.get_size()) == 0:+if x.get_numel() <= 1:assert axis in [0, -1]-return clone(x), empty_like(x, dtype=torch.int64)+return clone(x), zeros_like(x, dtype=torch.int64)dtype = x.get_dtype()combine_fn = ir.get_reduction_combine_fn(test/inductor/test_torchinductor_codegen_dynamic_shapes.py | 1 +torch/_inductor/lowering.py | 4 ++--2 files changed, 3 insertions(+), 2 deletions(-)
test/inductor/test_torchinductor_codegen_dynamic_shapes.py+1 −0
@@ -159,6 +159,7 @@ def run(*ex, **kwargs):"test_conv_functional_bn_fuse_dynamic_shapes": TestFailure(("cpu",), is_skip=True),"test_convolution2_dynamic_shapes": TestFailure(("cpu",)),"test_cumprod_zero_dim_dynamic_shapes": TestFailure(("cpu",)),+"test_cummin_dynamic_shapes": TestFailure(("cpu", "cuda", "xpu")),"test_cumsum_dynamic_shapes": TestFailure(("cpu",)),"test_cumsum_no_mask_dynamic_shapes": TestFailure(("cpu",)),"test_cumsum_zero_dim_dynamic_shapes": TestFailure(("cpu",)),
torch/_inductor/lowering.py+2 −2
@@ -6295,7 +6295,7 @@ def log_add_exp_helper(a_tuple, b_tuple):@register_lowering(aten.cummax, type_promotion_kind=None)def cummax(x, axis=None):-if x.get_numel() <= 1:+if V.graph.sizevars.statically_known_leq(x.get_numel(), 1):assert axis in [0, -1]return clone(x), zeros_like(x, dtype=torch.int64)@@ -6315,7 +6315,7 @@ def cummax(x, axis=None):@register_lowering(aten.cummin, type_promotion_kind=None)def cummin(x, axis=None):-if x.get_numel() <= 1:+if V.graph.sizevars.statically_known_leq(x.get_numel(), 1):assert axis in [0, -1]return clone(x), zeros_like(x, dtype=torch.int64)test/inductor/test_torchinductor.py | 1 +1 file changed, 1 insertion(+)
test/inductor/test_torchinductor.py+1 −0
@@ -2543,6 +2543,7 @@ def fn(x):self.common(fn, (torch.ones(32, 32) * 70,))+@skip_if_halidedef test_cummin(self):def fn(x):return x.cummin(0)torch/_inductor/lowering.py | 18 ++++++++++++------1 file changed, 12 insertions(+), 6 deletions(-)
torch/_inductor/lowering.py+12 −6
@@ -6295,9 +6295,9 @@ def log_add_exp_helper(a_tuple, b_tuple):@register_lowering(aten.cummax, type_promotion_kind=None)def cummax(x, axis=None):-if V.graph.sizevars.statically_known_leq(x.get_numel(), 1):+if len(x.get_size()) == 0:assert axis in [0, -1]-return clone(x), zeros_like(x, dtype=torch.int64)+return clone(x), empty_like(x, dtype=torch.int64)dtype = x.get_dtype()combine_fn = ir.get_reduction_combine_fn(@@ -6306,7 +6306,10 @@ def cummax(x, axis=None):kwargs = _make_scan_inner(x, axis=axis, dtype=dtype)kwargs["dtypes"] = (dtype, torch.int64)-kwargs["inner_fns"] = (x.make_loader(), lambda _: "rindex")+kwargs["inner_fns"] = (+x.make_loader(),+lambda idx: ops.index_expr(idx[axis], torch.int64),+)values, indices = ir.Scan.create(**kwargs, combine_fn=combine_fn) # type: ignore[arg-type]if values is None:return fallback_cummax(x, dim=axis)@@ -6315,9 +6318,9 @@ def cummax(x, axis=None):@register_lowering(aten.cummin, type_promotion_kind=None)def cummin(x, axis=None):-if V.graph.sizevars.statically_known_leq(x.get_numel(), 1):+if len(x.get_size()) == 0:assert axis in [0, -1]-return clone(x), zeros_like(x, dtype=torch.int64)+return clone(x), empty_like(x, dtype=torch.int64)dtype = x.get_dtype()combine_fn = ir.get_reduction_combine_fn(@@ -6326,7 +6329,10 @@ def cummin(x, axis=None):kwargs = _make_scan_inner(x, axis=axis, dtype=dtype)kwargs["dtypes"] = (dtype, torch.int64)-kwargs["inner_fns"] = (x.make_loader(), lambda _: "rindex")+kwargs["inner_fns"] = (+x.make_loader(),+lambda idx: ops.index_expr(idx[axis], torch.int64),+)values, indices = ir.Scan.create(**kwargs, combine_fn=combine_fn) # type: ignore[arg-type]if values is None:return fallback_cummin(x, dim=axis)test/inductor/test_torchinductor.py | 1 +1 file changed, 1 insertion(+)
test/inductor/test_torchinductor.py+1 −0
@@ -2544,6 +2544,7 @@ def fn(x):self.common(fn, (torch.ones(32, 32) * 70,))@skip_if_halide+@xfail_if_mpsdef test_cummin(self):def fn(x):return x.cummin(0)