From da5fd487db3506d8dc14e58564239fd8efd8571c Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 18 Aug 2026 03:07:40 +0000 Subject: [PATCH] =?UTF-8?q?Pin=20r2sleigh=20to=20Rust=201.97.1,=20matching?= =?UTF-8?q?=20ruff=20=E2=80=94=20and=20fix=20the=209=20clippy=20lints=20th?= =?UTF-8?q?at=20surfaces?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two repos were split: ruff pinned 1.97.1, r2sleigh 1.93.0. That split was already fictional in one direction — `ruff_r2il` lives inside the ruff tree, so rustup's directory walk gives it ruff's 1.97.1, and it path-deps these crates. r2sleigh's source was therefore ALREADY being compiled under 1.97.1 whenever the intake arm built; the pin just didn't say so. Building from inside r2sleigh's own directory was the only place 1.93.0 applied. Measured before changing anything: - `cargo fmt --all --check` is clean under BOTH 1.93.0 and 1.97.1, so the bump costs zero reformatting churn. (This was the actual question — rustfmt output does differ across these versions in general; here it does not.) - `cargo clippy --workspace --all-features -- -D warnings` under 1.97.1 was NOT clean: 9 lints across 4 crates, revealed one crate at a time because cargo stops at the first failure. r2ssa (4) → r2sym (2) → r2dec (2) → r2plugin (1). Every fix is behavior-identical, hand-applied, no `cargo clippy --fix`: - `while_let_loop` (r2ssa/function.rs): `loop { let Some(x) = .. else { break }; }` → `while let Some(x) = .. { }`. - `unnecessary_sort_by` (r2ssa/phi.rs): `sort_unstable_by(|(a,_),(b,_)| a.cmp(b))` → `sort_unstable_by_key(|(a,_)| *a)`. - `question_mark` (r2ssa/semantic.rs): an `else if let .. else { return None }` chain → `strip_prefix("ram:")?`. - `manual_checked_ops` (r2sym/value.rs): an explicit `if *b == 0` guard around `*a / *b` → `a.checked_div(*b)`. Safe because `value` is **u64** — on unsigned, `checked_div` returns None only for a zero divisor, exactly matching the guard. (On signed it would ALSO catch `MIN / -1`, which would be a behavior change.) - `collapsible_match` ×5 (r2ssa/semantic.rs, r2sym/value.rs, r2dec ×2, r2plugin): `Pat => { if C { BODY } }` → `Pat if C => { BODY }`. That last one is the only class that can silently change behavior, because a false guard now falls through to a LATER arm. Each of the five was verified individually before collapsing: four had no `else` at all with `_ => {}` as the fallthrough (a no-op either way), and the fifth (r2sym/value.rs concat) had an `else` body BYTE-IDENTICAL to the `_` arm's body. None were collapsed on faith. Verified after: clippy 0 errors, `cargo fmt --all --check` clean, and 541 tests green across the three changed non-z3 crates (r2ssa 371+59+99, r2dec, r2il). Downstream `ruff_r2il` still passes 43/43 against these crates. Not covered locally, and pre-existing: `r2sym` and `r2sleigh-plugin` cannot LINK in this container — `unable to find library -lz3`. Confirmed identical under the old 1.93.0 toolchain, so it is a missing system Z3, not a consequence of this bump; CI installs it. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01AGVLyRZNEKKBSfBDJfbY3V --- crates/r2dec/src/analysis/use_info.rs | 6 ++--- crates/r2dec/src/fold/op_lower/mod.rs | 12 +++++----- crates/r2ssa/src/function.rs | 5 +---- crates/r2ssa/src/phi.rs | 2 +- crates/r2ssa/src/semantic.rs | 24 +++++++++----------- crates/r2sym/src/value.rs | 32 ++++++++++----------------- r2plugin/src/lib.rs | 8 +++---- rust-toolchain.toml | 2 +- 8 files changed, 38 insertions(+), 53 deletions(-) diff --git a/crates/r2dec/src/analysis/use_info.rs b/crates/r2dec/src/analysis/use_info.rs index e1e9ad56e..a991330f5 100644 --- a/crates/r2dec/src/analysis/use_info.rs +++ b/crates/r2dec/src/analysis/use_info.rs @@ -1955,10 +1955,8 @@ fn arg_slot_for_value_ref( .. }, .. - } => { - if root.var != value_ref.var { - return arg_slot_for_value_ref(info, root, env, arg_slot_map, depth + 1); - } + } if root.var != value_ref.var => { + return arg_slot_for_value_ref(info, root, env, arg_slot_map, depth + 1); } _ => {} } diff --git a/crates/r2dec/src/fold/op_lower/mod.rs b/crates/r2dec/src/fold/op_lower/mod.rs index 9712e5219..e77d990aa 100644 --- a/crates/r2dec/src/fold/op_lower/mod.rs +++ b/crates/r2dec/src/fold/op_lower/mod.rs @@ -918,12 +918,12 @@ impl<'a> FoldingContext<'a> { branches_to_exit = true; } } - SSAOp::Store { addr, .. } => { - if branches_to_exit || self.is_current_return_context_candidate(block.addr) { - let offset = self.stack_slot_offset_for_var(addr); - if offset.is_some() { - return offset; - } + SSAOp::Store { addr, .. } + if branches_to_exit || self.is_current_return_context_candidate(block.addr) => + { + let offset = self.stack_slot_offset_for_var(addr); + if offset.is_some() { + return offset; } } _ => {} diff --git a/crates/r2ssa/src/function.rs b/crates/r2ssa/src/function.rs index 6277cf1f9..75c88180d 100644 --- a/crates/r2ssa/src/function.rs +++ b/crates/r2ssa/src/function.rs @@ -2076,10 +2076,7 @@ fn canonicalize_value_root(root: &SSAVar, roots: &BTreeMap) -> S let mut current = root.clone(); let mut seen = HashSet::new(); - loop { - let Some(next) = roots.get(¤t) else { - break; - }; + while let Some(next) = roots.get(¤t) { if *next == current || !seen.insert(current.clone()) { break; } diff --git a/crates/r2ssa/src/phi.rs b/crates/r2ssa/src/phi.rs index 0cb01645a..e4629a4eb 100644 --- a/crates/r2ssa/src/phi.rs +++ b/crates/r2ssa/src/phi.rs @@ -51,7 +51,7 @@ impl PhiPlacement { let mut placement = Self::new(); let mut defs_by_name: Vec<(&String, &HashSet)> = defs.iter().collect(); - defs_by_name.sort_unstable_by(|(lhs, _), (rhs, _)| lhs.cmp(rhs)); + defs_by_name.sort_unstable_by_key(|(lhs, _)| *lhs); for (var_name, def_blocks) in defs_by_name { let mut def_list: Vec = def_blocks.iter().copied().collect(); diff --git a/crates/r2ssa/src/semantic.rs b/crates/r2ssa/src/semantic.rs index 579fe9749..b77472db0 100644 --- a/crates/r2ssa/src/semantic.rs +++ b/crates/r2ssa/src/semantic.rs @@ -456,16 +456,16 @@ fn collect_access_summaries( uses.push(location); defs.push(location); } - SSAOp::Call { .. } | SSAOp::CallInd { .. } => { - if call_sites.by_inst.contains_key(&inst_id) { - let location = MemoryLocation { - object: escaped_unknown, - offset: 0, - size: 0, - }; - uses.push(location); - defs.push(location); - } + SSAOp::Call { .. } | SSAOp::CallInd { .. } + if call_sites.by_inst.contains_key(&inst_id) => + { + let location = MemoryLocation { + object: escaped_unknown, + offset: 0, + size: 0, + }; + uses.push(location); + defs.push(location); } _ => {} } @@ -899,10 +899,8 @@ fn canonical_value_root<'a>(facts: Option<&'a DecompilePrepFacts>, var: &'a SSAV fn const_value(var: &SSAVar) -> Option { let value_str = if let Some(value) = var.name.strip_prefix("const:") { value - } else if let Some(value) = var.name.strip_prefix("ram:") { - value } else { - return None; + var.name.strip_prefix("ram:")? }; let value_str = value_str.split('_').next().unwrap_or(value_str); if let Some(dec) = value_str diff --git a/crates/r2sym/src/value.rs b/crates/r2sym/src/value.rs index f466c765b..39006359f 100644 --- a/crates/r2sym/src/value.rs +++ b/crates/r2sym/src/value.rs @@ -430,19 +430,12 @@ impl<'ctx> SymValue<'ctx> { bits: lo_bits, .. }, - ) => { - if new_bits <= 64 { - let new_value = (*hi << *lo_bits) | *lo; - Self::Concrete { - value: new_value, - bits: new_bits, - taint, - } - } else { - let hi_bv = self.to_bv(ctx); - let lo_bv = other.to_bv(ctx); - let new_ast = hi_bv.concat(&lo_bv); - Self::symbolic_tainted(new_ast, new_bits, taint) + ) if new_bits <= 64 => { + let new_value = (*hi << *lo_bits) | *lo; + Self::Concrete { + value: new_value, + bits: new_bits, + taint, } } _ => { @@ -577,17 +570,16 @@ impl<'ctx> SymValue<'ctx> { }, ) => { let result_bits = (*bits).max(*b_bits); - if *b == 0 { - Self::Unknown { + match a.checked_div(*b) { + Some(value) => Self::Concrete { + value, bits: result_bits, taint, - } - } else { - Self::Concrete { - value: *a / *b, + }, + None => Self::Unknown { bits: result_bits, taint, - } + }, } } _ => { diff --git a/r2plugin/src/lib.rs b/r2plugin/src/lib.rs index 927479d84..75e571d23 100644 --- a/r2plugin/src/lib.rs +++ b/r2plugin/src/lib.rs @@ -894,11 +894,11 @@ pub extern "C" fn r2il_block_jump(block: *const R2ILBlock) -> u64 { match op { R2ILOp::Branch { target } | R2ILOp::Call { target } - | R2ILOp::CBranch { target, .. } => { + | R2ILOp::CBranch { target, .. } // Only return if target is a constant (direct jump) - if target.space == r2il::SpaceId::Const || target.space == r2il::SpaceId::Ram { - return target.offset; - } + if target.space == r2il::SpaceId::Const || target.space == r2il::SpaceId::Ram => + { + return target.offset; } _ => {} } diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 0e152a800..8565ca6bc 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.93.0" +channel = "1.97.1" components = ["rustfmt", "clippy"]