EagerEval: Fix broken expression type comparison. (#6734)

This is a bug introduced by the Rusty AIL migration.
This commit is contained in:
Fish 2026-07-29 00:05:07 -07:00 committed by GitHub
parent 659f3d7f5d
commit a7ae033c69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 21 additions and 1 deletions

View file

@ -2,6 +2,8 @@ from __future__ import annotations
import logging
from angr.rustylib.ailment import ExpressionKind
from . import expression, statement
from .block import Block
from .block_walker import AILBlockRewriter, AILBlockViewer, AILBlockWalker
@ -69,6 +71,7 @@ __all__ = [
"Const",
"Expr",
"Expression",
"ExpressionKind",
"IRSBConverter",
"Manager",
"NoOp",

View file

@ -2,6 +2,7 @@ from __future__ import annotations
from math import gcd
from angr.ailment import ExpressionKind
from angr.ailment.expression import BinaryOp, Const, Convert, StackBaseOffset, UnaryOp
from angr.utils.bits import sign_extend
@ -216,7 +217,7 @@ class EagerEvaluation(PeepholeOptimizationExprBase):
# constant multiplication
mask = (1 << expr.bits) - 1
return Const(expr.idx, (op0.value * op1.value) & mask, expr.bits, **expr.tags)
if {type(op0), type(op1)} == {BinaryOp, Const}:
if {op0.pykind, op1.pykind} == {ExpressionKind.BinaryOp, ExpressionKind.Const}:
op0, op1 = expr.operands
const_, x0 = (op0, op1) if isinstance(op0, Const) else (op1, op0)
if x0.op == "Mul" and (isinstance(x0.operands[0], Const) or isinstance(x0.operands[1], Const)):

View file

@ -177,6 +177,22 @@ class TestPeepholeOptimizations(unittest.TestCase):
)
assert opt.optimize(expr) is None
def test_eager_eval_var_mul_a_mul_b(self):
bin_path = os.path.join(test_location, "x86_64", "ls_ubuntu_2004")
proj = angr.Project(bin_path)
_ = proj.analyses.CFGFast(normalize=True, regions=[(0x410FC0, 0x410FC0 + 1000)])
f = proj.kb.functions[0x410FC0]
d = proj.analyses.Decompiler(f, fail_fast=True)
assert d.codegen is not None and d.codegen.text is not None
# a * 2 * 5 ==> a * 10
# we should see `a * 10`` or `a % 10` in the output
if "* 2" in d.codegen.text or "* 5" in d.codegen.text:
raise AssertionError(
"The decompiler output should not contain `* 2` or `* 5` after peephole optimization, but it does."
)
assert "* 10" in d.codegen.text or "% 10" in d.codegen.text
def test_cmp_masked_shift(self):
proj = angr.load_shellcode(b"\x90", "AMD64")
manager = Manager()