angr / angr/angr

SSA and dephication rewriting engines drop vector_count and vector_size when rebuilding a BinaryOp

Aberta
#7,013 0 comentários 0 reações 0 responsáveis Ver no GitHub
Linguagem predominante
Python
Estrelas
9.1k
Forks
1.2k
Merge médio
16h 20min
PRs com merge (30d)
169

Descrição

THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS

### Description

The SSA and dephication rewriting engines rebuild an AIL `BinaryOp` when one of its
operands is rewritten, and neither passes `vector_count` or `vector_size`.

`angr/analyses/decompiler/ssailification/rewriting_engine.py`, lines 423-441 at
`0e18fa25e`:

```python
def _handle_expr_BinaryOp(self, expr: BinaryOp) -> BinaryOp | None:
new_op0 = self._expr(expr.operands[0])
new_op1 = self._expr(expr.operands[1])

if new_op0 is not None or new_op1 is not None:
return BinaryOp(
expr.idx,
expr.op,
[
expr.operands[0] if new_op0 is None else new_op0,
expr.operands[1] if new_op1 is None else new_op1,
],
expr.signed,
bits=expr.bits,
floating_point=expr.floating_point,
rounding_mode=expr.rounding_mode,
**expr.tags,
)
return None
```

`angr/analyses/decompiler/dephication/rewriting_engine.py`, lines 350-368, is the same
code.

`BinaryOp.__new__` defaults both to `None` (`angr/ailment/expression.py`, lines 323-324),
so the metadata is not preserved but silently replaced:

```
original : bits 128 vector_size 8 vector_count 16
after rebuild : bits 128 vector_size None vector_count None
```

(constructing an `InterleaveLOV` over two 128-bit registers and passing it through the
rebuild above verbatim).

`bits` is passed and does survive. Only the vector shape is lost.

### Consequence

**This does not affect #6988.** Every `_handle_binop_default` that PR introduces or
renames reads `expr.bits` and nothing else, so an operator routed to a default is
unaffected by the loss.

It matters for the first handler that models a vector operator's real semantics, which is
the natural follow-up once operators like `CatEvenLanesV` reach the engines. The concrete
consequence is already in the tree: `SimEngineAILSimState._handle_binop_InterleaveLOV`
(`angr/engines/ail/engine_light.py`, line 895) opens with

```python
assert expr.vector_size is not None
assert expr.vector_count is not None
```

and computes lane slices from both. A handler written on that shape works pre-SSA and
asserts post-SSA, and the failure will look like a bug in the new handler rather than in
the rewrite.

`SimplifierAILEngine._handle_binop_default`
(`angr/analyses/decompiler/optimization_passes/engine_base.py`, lines 397-409) is the
model that gets it right — it rebuilds with the same argument list plus:

```python
vector_count=expr.vector_count,
vector_size=expr.vector_size,
```

### How this was established

By reading the three rebuild sites, then constructing a `BinaryOp("InterleaveLOV", ...,
bits=128, vector_count=16, vector_size=8)` and passing it through the rewriting engines'
argument list verbatim, which returns `vector_size=None, vector_count=None`. No
decompilation is needed to show it, and I am not claiming an observed wrong result today —
no in-tree handler reads the metadata after this point.

### Duplicate search performed

Diff level, not title. `gh pr list -R angr/angr --state all` over the recent range, with
every candidate touching `ssailification/`, `dephication/` or AIL expression construction
grepped for `vector_count`, `vector_size` and `_handle_expr_BinaryOp`. `git log --all -S`
on the literal `vector_count=expr.vector_count` matches only the simplifier engine's
existing use. No open or closed issue mentions vector metadata loss across a rewrite, and
the sibling worktrees under `features/` all carry both rebuild sites unchanged.

### Suggested fix

Add the two arguments at both sites, matching the simplifier.

### Context

Found while investigating the `KeyError` class that #6988 closes: the AIL binop dispatch
had no entry for the NEON lane operators `CatEvenLanesV`, `CatOddLanesV` and `GetElemV`,
which over a local decompilation sweep measured at 2026-08-28 14:41:17 UTC accounted for
168 distinct functions decompiling to an empty body across 162 distinct objects. (Each
failing function records the `KeyError` twice, so counting error occurrences rather than
functions doubles that figure.) Asking whether those operators could be given real lane
semantics rather than an opaque result is what surfaced this.

session: crazybins

Guia de contribuição

Nenhum guia de contribuição indexado para este repositório

Avaliação

Esta issue ainda não foi avaliada.

Receba novas issues na sua caixa de entrada

Um resumo curto de issues do GitHub para quem está começando.