forced_align (CPU) segfaults when frames * (2*targets+1) exceeds 2^31: 32-bit loop index overflow
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 2.9k
- Forks
- 799
- Avg merge
- 58m
- Merged PRs (30d)
- 3
Description
🐛 Describe the bug
torchaudio.functional.forced_align (CPU) crashes the whole process with SIGSEGV when frames * (2 * target_length + 1) exceeds 2^31. This is reachable with realistic inputs: character-level CTC alignment (WhisperX-style) of a ~20-minute chunk of dense speech at 50 fps crosses the limit (we hit it in production aligning a German podcast).
Repro
# needs ~2.2 GB RAM; crashes the interpreter (run in a subprocess)
import torch, torchaudio
T, L, C = 70_000, 15_500, 30 # T*(2L+1) = 2.17e9 > 2^31
g = torch.Generator().manual_seed(0)
emission = torch.log_softmax(torch.rand((T, C), generator=g), dim=-1)
targets = torch.randint(1, C, (1, L), generator=g, dtype=torch.int32)
torchaudio.functional.forced_align(emission.unsqueeze(0), targets, blank=0)
# -> SIGSEGV / SIGBUS
Observed behaviour (torchaudio 2.11.0, macOS arm64):
T * (2L+1) |
targets dtype | result |
|---|---|---|
| 2.17e9 (> 2^31) | int32 | 💥 SIGSEGV |
| 2.17e9 (> 2^31) | int64 | 💥 SIGSEGV (no dtype workaround) |
| 2.10e9 (< 2^31) | int32 | ✅ correct result, ~8 s |
Root cause
src/libtorchaudio/forced_align/cpu/compute.cpp, the backPtr_a init loop uses a 32-bit loop index against a 64-bit trip count:
auto backPtr_a = new int8_t[T * S]; // T, S are int64_t -- allocation is fine
for (int i = 0; i < T * S; i++) { // int i overflows at 2^31 (UB)
backPtr_a[i] = -1;
}
Once i wraps to INT_MIN, the store lands at backPtr_a - 2^31 bytes. The macOS crash report confirms this exactly: fault address = buffer base − 0x80000000, as a byte write inside forced_align_impl<float, int>:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000892e94000
x0/x19 (buffer): 0x0000000912e94000 <- base - fault = 0x80000000
0 libtorchaudio.abi3.so forced_align_impl<float, int>(...) + 316
1 libtorchaudio.abi3.so torchaudio::alignment::cpu::compute(...) + 1384
This also explains why int64 targets crash identically — the dispatch only changes target_t, not the init loop. The alphas_a init loop two lines above uses the same int i < 2 * S idiom (not practically reachable today, but the same latent pattern).
The bug is platform-independent (plain C++ signed-overflow UB); it is present in current main (c0cbdb9).
Correction (2026-08-04): an earlier version of this line said the bug went back to 2.8. It does not. #4021 (ea7855b), which introduced the raw array and the int fill loop, merged 2025-08-11 — five days after v2.8.0 shipped on 2025-08-06. v2.8.0 still carries the safe torch::Tensor backPtr = torch::empty({T, S}, torch::kInt8).fill_(-1). The affected range is 2.9.0 through 2.11.0.
Fix
One-liner: make the loop indices int64_t. PR incoming.
Versions
- torchaudio 2.11.0 (also inspected current main, c0cbdb9)
- torch 2.13.0
- Python 3.12.8, macOS 26.5 (arm64, M1 Max) — but the overflow is platform-independent
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/libtorchaudio/forced_align/cpu/compute.cpp and inspect the backPtr_a and alphas_a initialization loops in forced_align_impl. Confirm the loop index types are safe for their 64-bit trip counts, then validate the reported large-input reproduction or an equivalent regression check. Done means the overflow no longer permits out-of-bounds writes for the described dimensions.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, python
- Domain
- machine-learning
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 55/100