Skip to content

Fix two crashes caused by constant_prop_pass - #24224

Open
pytorchbot wants to merge 1 commit into
release/1.6from
cherry-pick-24182-by-pytorch_bot_bot_
Open

pytorchbot wants to merge 1 commit into
release/1.6from
cherry-pick-24182-by-pytorch_bot_bot_

Conversation

@pytorchbot

Copy link
Copy Markdown
Collaborator

What is wrong today

Programs that go through constant_prop_pass can crash in two ways: one inside the pass, and one later when the program is lowered.

1. A folded value that is not a tensor. The pass also folds values such as the int from .item() on a buffer, and the bools that torch._check turns into runtime checks. When a node that stays in the graph reads such a value, the pass tries to turn it into a constant tensor input and fails:

n = self.n.item()        # self.n is a buffer
torch._check(n >= 1)
torch._check(n <= x.shape[0])
return x[:n] * self.w[:n]
TypeError: cannot create weak reference to 'bool' object

2. A folded parameter that still requires grad. Folding self.w.t(), or one chunk of a packed weight, gives a view that still has requires_grad=True, because torch.no_grad() does not clear that flag on a view. For some views, such as a transposed one, to_edge then copies the constant into a non-leaf tensor, and lowering to a backend can fail when it deep-copies the program:

RuntimeError: Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment.

An op can also return the parameter itself, like self.w.to(torch.float32) on a float32 parameter. Then the pass stores the nn.Parameter as a constant, and to_edge fails with AttributeError: ... is not a buffer.

What this change does

Two commits, one per crash:

  1. Only tensors can become constant inputs. So a non-tensor value that a node outside the fold reads now stays in the graph, together with the non-tensor values it is computed from. Tensors computed from it still fold: self.w[:n] still becomes one constant. Programs that constant_prop_pass handled before are unchanged.
  2. A folded constant must be a plain tensor that does not require grad, so the pass now detaches every folded tensor.

What was tested

On macOS arm64:

  • Two new tests in exir/tests/test_passes.py, one per commit. Each fails before its commit and passes after: the first with TypeError: cannot create weak reference to 'int' object, the second with the AttributeError above.
    • The first covers a scalar read at runtime, one returned as an output, one whose first reader is folded, and one read only by folded nodes (it folds away). The program also lowers with to_edge(...).to_executorch().
    • The second covers the transposed view and the to case, and checks that the output matches eager.
  • The rest of exir/tests/test_passes.py, exir/emit/test/test_emit.py and exir/tests/test_quant_fusion_pass.py. Five tests in those files fail the same way with and without this change, because they need the quantized and custom op libraries.

## What is wrong today

Programs that go through `constant_prop_pass` can crash in two ways: one
inside the pass, and one later when the program is lowered.

**1. A folded value that is not a tensor.** The pass also folds values
such as the int from `.item()` on a buffer, and the bools that
`torch._check` turns into runtime checks. When a node that stays in the
graph reads such a value, the pass tries to turn it into a constant
tensor input and fails:

```python
n = self.n.item()        # self.n is a buffer
torch._check(n >= 1)
torch._check(n <= x.shape[0])
return x[:n] * self.w[:n]
```
```
TypeError: cannot create weak reference to 'bool' object
```

**2. A folded parameter that still requires grad.** Folding
`self.w.t()`, or one chunk of a packed weight, gives a view that still
has `requires_grad=True`, because `torch.no_grad()` does not clear that
flag on a view. For some views, such as a transposed one, `to_edge` then
copies the constant into a non-leaf tensor, and lowering to a backend
can fail when it deep-copies the program:

```
RuntimeError: Only Tensors created explicitly by the user (graph leaves) support the deepcopy protocol at the moment.
```

An op can also return the parameter itself, like
`self.w.to(torch.float32)` on a float32 parameter. Then the pass stores
the `nn.Parameter` as a constant, and `to_edge` fails with
`AttributeError: ... is not a buffer`.

## What this change does

Two commits, one per crash:

1. Only tensors can become constant inputs. So a non-tensor value that a
node outside the fold reads now stays in the graph, together with the
non-tensor values it is computed from. Tensors computed from it still
fold: `self.w[:n]` still becomes one constant. Programs that
`constant_prop_pass` handled before are unchanged.
2. A folded constant must be a plain tensor that does not require grad,
so the pass now detaches every folded tensor.

## What was tested

On macOS arm64:
- Two new tests in `exir/tests/test_passes.py`, one per commit. Each
fails before its commit and passes after: the first with `TypeError:
cannot create weak reference to 'int' object`, the second with the
`AttributeError` above.
- The first covers a scalar read at runtime, one returned as an output,
one whose first reader is folded, and one read only by folded nodes (it
folds away). The program also lowers with
`to_edge(...).to_executorch()`.
- The second covers the transposed view and the `to` case, and checks
that the output matches eager.
- The rest of `exir/tests/test_passes.py`, `exir/emit/test/test_emit.py`
and `exir/tests/test_quant_fusion_pass.py`. Five tests in those files
fail the same way with and without this change, because they need the
quantized and custom op libraries.

(cherry picked from commit cedc66f)
@pytorch-bot

pytorch-bot Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/24224

Note: Links to docs will display an error until the docs builds have been completed.

✅ No Failures

As of commit 9f8a6e9 with merge base 4db778e (image):
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 28, 2026

This branch was previously deployed

1 inactive deployment
cadence — 9f8a6e90 Deployed Oct 28, 2026 by pytorchbot via hifi-op-test / hifi4 #34993
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants