From 1461d122816874469ddc5fa57a7e1ed9bd32c5e6 Mon Sep 17 00:00:00 2001 From: Coursant <24210240198@m.fudan.edu.cn> Date: Tue, 13 Jan 2026 05:50:03 +0800 Subject: [PATCH 1/7] tmp --- rapx/Cargo.lock | 2 +- .../core/alias_analysis/default/alias.rs | 11 ++---- .../core/alias_analysis/default/types.rs | 7 +++- .../analysis/core/range_analysis/default.rs | 11 ++++-- .../range_analysis/domain/ConstraintGraph.rs | 25 +++++++----- .../core/range_analysis/domain/domain.rs | 23 ++++++++--- .../analysis/core/ssa_transform/Replacer.rs | 39 ++++++++++++------- rapx/src/analysis/safedrop/alias.rs | 2 +- rapx/tests/range/range_5/src/main.rs | 35 ++++++++++++++--- 9 files changed, 106 insertions(+), 49 deletions(-) diff --git a/rapx/Cargo.lock b/rapx/Cargo.lock index 117482d7..aa8c8441 100644 --- a/rapx/Cargo.lock +++ b/rapx/Cargo.lock @@ -636,7 +636,7 @@ dependencies = [ [[package]] name = "rapx" -version = "0.6.251" +version = "0.6.252" dependencies = [ "annotate-snippets", "cargo_metadata", diff --git a/rapx/src/analysis/core/alias_analysis/default/alias.rs b/rapx/src/analysis/core/alias_analysis/default/alias.rs index 20644594..b62ed291 100644 --- a/rapx/src/analysis/core/alias_analysis/default/alias.rs +++ b/rapx/src/analysis/core/alias_analysis/default/alias.rs @@ -1,15 +1,10 @@ -use super::{ - MopAliasPair, MopFnAliasMap, block::Term, graph::*, types::*, value::*, -}; -use crate::{ - def_id::*, - analysis::graphs::scc::Scc, -}; +use super::{MopAliasPair, MopFnAliasMap, block::Term, graph::*, types::*, value::*}; +use crate::{analysis::graphs::scc::Scc, def_id::*}; use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::{ mir::{Local, Operand, Place, ProjectionElem, TerminatorKind}, - ty::self, + ty, }; use std::collections::HashSet; diff --git a/rapx/src/analysis/core/alias_analysis/default/types.rs b/rapx/src/analysis/core/alias_analysis/default/types.rs index fac92269..525dfa94 100644 --- a/rapx/src/analysis/core/alias_analysis/default/types.rs +++ b/rapx/src/analysis/core/alias_analysis/default/types.rs @@ -34,7 +34,12 @@ pub fn kind(ty: Ty<'_>) -> ValueKind { ty::Adt(adt, _) => { // Use string matching to catch RefCell/RefMut/Rc for special handling. let s = format!("{:?}", adt); - if s.contains("cell::RefMut") || s.contains("cell::Ref") || s.contains("rc::Rc") || s.contains("sync::Arc") || s.contains("sync::Weak") { + if s.contains("cell::RefMut") + || s.contains("cell::Ref") + || s.contains("rc::Rc") + || s.contains("sync::Arc") + || s.contains("sync::Weak") + { ValueKind::SpecialPtr } else { ValueKind::Adt diff --git a/rapx/src/analysis/core/range_analysis/default.rs b/rapx/src/analysis/core/range_analysis/default.rs index 13823357..102614f8 100644 --- a/rapx/src/analysis/core/range_analysis/default.rs +++ b/rapx/src/analysis/core/range_analysis/default.rs @@ -69,8 +69,7 @@ pub struct RangeAnalyzer<'tcx, T: IntervalArithmetic + ConstConvert + Debug> { pub path_constraints: PathConstraintMap<'tcx>, // Path-sensitive constraints } -impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> Analysis - for RangeAnalyzer<'tcx, T> +impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> Analysis for RangeAnalyzer<'tcx, T> where T: IntervalArithmetic + ConstConvert + Debug, { @@ -175,6 +174,10 @@ where } fn build_constraintgraph(&mut self, body_mut_ref: &'tcx Body<'tcx>, def_id: DefId) { + rap_debug!( + "Building ConstraintGraph for function: {}", + self.tcx.def_path_str(def_id) + ); let ssa_def_id = self.ssa_def_id.expect("SSA definition ID is not set"); let essa_def_id = self.essa_def_id.expect("ESSA definition ID is not set"); let mut cg: ConstraintGraph<'tcx, T> = @@ -201,7 +204,7 @@ where file.write_all(dot_output.as_bytes()) .expect("Could not write to file"); - println!("Successfully generated graph.dot"); + rap_trace!("Successfully generated graph.dot"); // println!("Run 'dot -Tpng -o graph.png graph.dot' to generate the image."); } @@ -217,6 +220,7 @@ where let def_id = local_def_id.to_def_id(); if self.tcx.is_mir_available(def_id) { + rap_debug!("Processing function: {}", self.tcx.def_path_str(def_id)); let mut body = self.tcx.optimized_mir(def_id).clone(); let body_mut_ref = unsafe { &mut *(&mut body as *mut Body<'tcx>) }; // Run SSA/ESSA passes @@ -224,7 +228,6 @@ where passrunner.run_pass(body_mut_ref, ssa_def_id, essa_def_id); self.body_map.insert(def_id, body); // Print the MIR after SSA/ESSA passes - rap_debug!("{:#?}", body_mut_ref.local_decls); if self.debug { print_diff(self.tcx, body_mut_ref, def_id.into()); print_mir_graph(self.tcx, body_mut_ref, def_id.into()); diff --git a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs index efe4195c..3175714c 100644 --- a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs +++ b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs @@ -727,6 +727,12 @@ where // let place1: &Place<'tcx>; if let Operand::Copy(place) | Operand::Move(place) = discr { if let Some((op1, op2, cmp_op)) = self.extract_condition(place, block_data) { + rap_trace!( + "build_value_branch_map op1:{:?} op2:{:?} cmp_op:{:?}\n", + op1, + op2, + cmp_op + ); let const_op1 = op1.constant(); let const_op2 = op2.constant(); match (const_op1, const_op2) { @@ -754,8 +760,8 @@ where let value = Self::convert_const(&c.const_).unwrap(); let const_range = Range::new(value.clone(), value.clone(), RangeType::Unknown); - rap_trace!("cmp_op{:?}\n", cmp_op); - rap_trace!("const_in_left{:?}\n", const_in_left); + rap_trace!("cmp_op {:?}\n", cmp_op); + rap_trace!("const_in_left {:?}\n", const_in_left); let mut true_range = self.apply_comparison(value.clone(), cmp_op, true, const_in_left); let mut false_range = @@ -874,11 +880,13 @@ where let mut return_op1: &Operand<'tcx> = &op1; let mut return_op2: &Operand<'tcx> = &op2; for stmt_original in &switch_block.statements { - if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) = - &stmt_original.kind - { - if lhs.clone() == op1.place().unwrap() { - return_op1 = OP1; + if op1.constant().is_none() { + if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) = + &stmt_original.kind + { + if lhs.clone() == op1.place().unwrap() { + return_op1 = OP1; + } } } } @@ -1286,7 +1294,6 @@ where let BI: BasicInterval = BasicInterval::new(Range::default(T::min_value())); let mut source: Option<&'tcx Place<'tcx>> = None; - rap_debug!("wtf {:?}\n", self.vars); match op { Operand::Copy(place) | Operand::Move(place) => { @@ -1366,8 +1373,8 @@ where }; let op = &operands[FieldIdx::from_usize(loc_2)]; let bop_index = self.oprs.len(); - let BI: IntervalType<'_, T>; + rap_trace!("essa_op operand1 {:?}\n", source1.unwrap()); if let Operand::Constant(c) = op { let vbm = self.values_branchmap.get(source1.unwrap()).unwrap(); if block == *vbm.get_bb_true() { diff --git a/rapx/src/analysis/core/range_analysis/domain/domain.rs b/rapx/src/analysis/core/range_analysis/domain/domain.rs index 50172161..62584b58 100644 --- a/rapx/src/analysis/core/range_analysis/domain/domain.rs +++ b/rapx/src/analysis/core/range_analysis/domain/domain.rs @@ -304,17 +304,30 @@ impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> BasicOpKind<'tcx, T> { match self { BasicOpKind::Unary(op) => vec![op.source], BasicOpKind::Binary(op) => { - let mut sources = vec![]; - sources.push(op.source1.unwrap()); - if let Some(source2) = op.source2 { - sources.push(source2); + let mut sources = Vec::new(); + + if let Some(src1) = op.source1 { + sources.push(src1); + } + + if let Some(src2) = op.source2 { + sources.push(src2); } + sources } BasicOpKind::Essa(op) => vec![op.source], BasicOpKind::ControlDep(op) => vec![op.source], BasicOpKind::Phi(op) => op.sources.clone(), - BasicOpKind::Use(op) => vec![op.source.unwrap()], + BasicOpKind::Use(op) => { + let mut sources = Vec::new(); + + if let Some(src1) = op.source { + sources.push(src1); + } + + sources + } BasicOpKind::Call(op) => op.sources.clone(), BasicOpKind::Ref(op) => vec![op.source], BasicOpKind::Aggregate(_) => vec![], diff --git a/rapx/src/analysis/core/ssa_transform/Replacer.rs b/rapx/src/analysis/core/ssa_transform/Replacer.rs index 3b85b24e..60784db6 100644 --- a/rapx/src/analysis/core/ssa_transform/Replacer.rs +++ b/rapx/src/analysis/core/ssa_transform/Replacer.rs @@ -145,12 +145,14 @@ impl<'tcx> Replacer<'tcx> { if lhs == place { let mut return_op1: &Operand<'tcx> = &op1; let mut return_op2: &Operand<'tcx> = &op2; - for stmt_original in &switch_block.statements { - if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) = - &stmt_original.kind - { - if lhs.clone() == op1.place().unwrap() { - return_op1 = OP1; + if op1.constant().is_none() { + for stmt_original in &switch_block.statements { + if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) = + &stmt_original.kind + { + if lhs.clone() == op1.place().unwrap() { + return_op1 = OP1; + } } } } @@ -351,11 +353,22 @@ impl<'tcx> Replacer<'tcx> { } (None, Some(_)) | (Some(_), None) => { let mut operand: IndexVec<_, _> = IndexVec::with_capacity(3); - - let place = match op1 { - Operand::Copy(p) | Operand::Move(p) => Place::from(p), - _ => panic!("Expected a place"), - }; + let place; + // let place = match op1 { + // Operand::Copy(p) | Operand::Move(p) => Place::from(p), + // _ => panic!("Expected a place"), + // }; + if op1.constant().is_none() { + place = match op1 { + Operand::Copy(p) | Operand::Move(p) => Place::from(p), + _ => panic!("Expected a place"), + }; + } else { + place = match op2 { + Operand::Copy(p) | Operand::Move(p) => Place::from(p), + _ => panic!("Expected a place"), + }; + } operand.push(op1.clone()); operand.push(op2.clone()); let rvalue; @@ -434,14 +447,10 @@ impl<'tcx> Replacer<'tcx> { locals_to_add.sort_by_key(|(new_local, _)| new_local.index()); rap_debug!("locals_to_add {:?}", locals_to_add); for (new_local, original_local) in locals_to_add { - // 从原始 local 找到它的声明 let original_decl = &body.local_decls[*original_local]; - // 为新的 local 创建一个完全相同的声明(克隆类型、来源信息等) let new_decl = original_decl.clone(); - // body.local_decls 是一个 IndexVec,可以直接 push - // push 会返回新元素的索引,这个索引应该和你生成的 new_local.index() 一致 let pushed_index = body.local_decls.push(new_decl); rap_debug!("Ok with {:?} {:?}", pushed_index, *new_local); assert_eq!(pushed_index, *new_local); diff --git a/rapx/src/analysis/safedrop/alias.rs b/rapx/src/analysis/safedrop/alias.rs index ea8f9195..171686b1 100644 --- a/rapx/src/analysis/safedrop/alias.rs +++ b/rapx/src/analysis/safedrop/alias.rs @@ -5,7 +5,7 @@ use rustc_middle::{ use super::{drop::*, graph::*}; use crate::analysis::core::alias_analysis::default::{ - MopAliasPair, MopFnAliasMap, alias::is_no_alias_intrinsic, block::Term, types::*, value::* + MopAliasPair, MopFnAliasMap, alias::is_no_alias_intrinsic, block::Term, types::*, value::*, }; use rustc_data_structures::fx::FxHashSet; diff --git a/rapx/tests/range/range_5/src/main.rs b/rapx/tests/range/range_5/src/main.rs index 81896811..ce43589f 100644 --- a/rapx/tests/range/range_5/src/main.rs +++ b/rapx/tests/range/range_5/src/main.rs @@ -1,7 +1,32 @@ -fn main() { - let mut i =0; - while i<10{ - i+=1; +#[inline] +pub fn starts_with_ascii_alpha(string: &str) -> bool { + matches!(string.as_bytes()[0], b'a'..=b'z' | b'A'..=b'Z') +} +#[derive(PartialEq, Eq)] +pub enum Context { + UrlParser, + Setter, +} +pub fn parse_scheme<'a>(input: &'a str, context: Context) -> Option<(String, &'a str)> { + if input.is_empty() || !starts_with_ascii_alpha(input) { + return None + } + for (i, c) in input.char_indices() { + match c { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '+' | '-' | '.' => (), + ':' => return Some(( + input[..i].to_ascii_lowercase(), + &input[i + 1..], + )), + _ => return None, + } + } + // EOF before ':' + match context { + Context::Setter => Some((input.to_ascii_lowercase(), "")), + Context::UrlParser => None } - } +pub fn main(){ + parse_scheme("http:www.example.com",Context::UrlParser); +} \ No newline at end of file From f9acc74b9d86946f37ac1079077d1bd3c759b452 Mon Sep 17 00:00:00 2001 From: Coursant <24210240198@m.fudan.edu.cn> Date: Wed, 14 Jan 2026 20:06:09 +0800 Subject: [PATCH 2/7] tmp --- .../analysis/core/ssa_transform/Replacer.rs | 220 +++++++++--------- rapx/tests/range/run_range_tests.sh | 94 ++++++++ 2 files changed, 198 insertions(+), 116 deletions(-) create mode 100755 rapx/tests/range/run_range_tests.sh diff --git a/rapx/src/analysis/core/ssa_transform/Replacer.rs b/rapx/src/analysis/core/ssa_transform/Replacer.rs index 60784db6..d6b3e8c1 100644 --- a/rapx/src/analysis/core/ssa_transform/Replacer.rs +++ b/rapx/src/analysis/core/ssa_transform/Replacer.rs @@ -173,7 +173,29 @@ impl<'tcx> Replacer<'tcx> { } None } - // pub + fn make_const_operand(&self, val: u64) -> Operand<'tcx> { + Operand::Constant(Box::new(ConstOperand { + span: rustc_span::DUMMY_SP, + user_ty: None, + const_: Const::from_usize(self.tcx, val), + })) + } + + fn op_to_code(op: BinOp) -> u64 { + match op { + BinOp::Lt => 1, + BinOp::Le => 2, + BinOp::Ge => 3, + BinOp::Gt => 4, + BinOp::Eq => 5, + BinOp::Ne => 6, + _ => 7, + } + } + + // This function inserts eSSA (extended SSA) assignment statements into the basic block. + // These statements capture control flow information by asserting conditions on variables + // based on the outcome of a switch (branching) instruction. fn essa_assign_statement( &mut self, bb: &BasicBlock, @@ -184,49 +206,12 @@ impl<'tcx> Replacer<'tcx> { ) { let switch_block_data = &body.basic_blocks[*switch_block]; - // let mut essa_operands: IndexVec<_, _> = IndexVec::with_capacity(2); - let magic_number = 213134123 as u64; - let magic_number_operand = Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_usize(self.tcx, magic_number), - })); - let Lt_operand = Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_usize(self.tcx, 1), - })); - let Le_operand = Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_usize(self.tcx, 2), - })); - let Ge_operand = Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_usize(self.tcx, 3), - })); - let Gt_operand = Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_usize(self.tcx, 4), - })); - let Eq_operand = Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_usize(self.tcx, 5), - })); - let Ne_operand = Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_usize(self.tcx, 6), - })); - let other_operand = Operand::Constant(Box::new(ConstOperand { - span: rustc_span::DUMMY_SP, - user_ty: None, - const_: Const::from_usize(self.tcx, 7), - })); + // Define a magic number to identify eSSA statements in Place-Place comparisons. + let magic_number_operand = self.make_const_operand(213134123); + + // Helper: verify if the discriminant is a Place (variable). if let Operand::Copy(switch_place) | Operand::Move(switch_place) = discr { + // Attempt to extract the binary condition that led to this switch. if let Some((op1, op2, cmp_op)) = self.extract_condition(switch_place, switch_block_data) { @@ -234,56 +219,25 @@ impl<'tcx> Replacer<'tcx> { let const_op1: Option<&ConstOperand<'_>> = op1.constant(); let const_op2: Option<&ConstOperand<'_>> = op2.constant(); - let cmp_operand: Operand<'_> = match cmp_op.clone() { - BinOp::Lt => Lt_operand.clone(), - BinOp::Le => Le_operand.clone(), - BinOp::Gt => Gt_operand.clone(), - BinOp::Ge => Ge_operand.clone(), - BinOp::Ne => Ne_operand.clone(), - BinOp::Eq => Eq_operand.clone(), - - _ => other_operand.clone(), - }; - - let flip_cmp_operand: Operand<'_> = match Self::flip(cmp_op) { - BinOp::Lt => Lt_operand.clone(), - BinOp::Le => Le_operand.clone(), - BinOp::Gt => Gt_operand.clone(), - BinOp::Ge => Ge_operand.clone(), - BinOp::Eq => Ne_operand.clone(), - BinOp::Ne => Eq_operand.clone(), - - _ => other_operand.clone(), - }; - let reverse_cmp_operand: Operand<'_> = match Self::reverse(cmp_op) { - BinOp::Lt => Lt_operand.clone(), - BinOp::Le => Le_operand.clone(), - BinOp::Gt => Gt_operand.clone(), - BinOp::Ge => Ge_operand.clone(), - BinOp::Ne => Ne_operand.clone(), - BinOp::Eq => Eq_operand.clone(), - - _ => other_operand.clone(), - }; - let flip_reverse_cmp_operand: Operand<'_> = match Self::flip(Self::reverse(cmp_op)) - { - BinOp::Lt => Lt_operand.clone(), - BinOp::Le => Le_operand.clone(), - BinOp::Gt => Gt_operand.clone(), - BinOp::Ge => Ge_operand.clone(), - BinOp::Eq => Ne_operand.clone(), - BinOp::Ne => Eq_operand.clone(), - - _ => other_operand.clone(), - }; + + // Generate operands for the comparison operators. + let cmp_operand = self.make_const_operand(Self::op_to_code(cmp_op)); + let flip_cmp_operand = + self.make_const_operand(Self::op_to_code(Self::flip(cmp_op))); + let reverse_cmp_operand = + self.make_const_operand(Self::op_to_code(Self::reverse(cmp_op))); + let flip_reverse_cmp_operand = + self.make_const_operand(Self::op_to_code(Self::flip(Self::reverse(cmp_op)))); + match (const_op1, const_op2) { + // Case 1: Both operands are places (variables). (None, None) => { match (op1, op2) { ( Operand::Copy(p1) | Operand::Move(p1), Operand::Copy(p2) | Operand::Move(p2), ) => { - let ADT = AggregateKind::Adt( + let adt_kind = AggregateKind::Adt( self.ssatransformer.essa_def_id.clone(), rustc_abi::VariantIdx::from_u32(0), GenericArgs::empty(), @@ -297,38 +251,43 @@ impl<'tcx> Replacer<'tcx> { let mut operand1: IndexVec<_, _> = IndexVec::with_capacity(4); let mut operand2: IndexVec<_, _> = IndexVec::with_capacity(4); + // Determine constraints based on whether the condition was true (value != 0) or false (value == 0). if value == 0 { + // False branch: Use flipped operators. + // For p1: p1 (negated_op) p2 operand1.push(Operand::Copy(Place::from(p1))); operand1.push(Operand::Copy(Place::from(p2))); operand1.push(flip_cmp_operand.clone()); operand1.push(magic_number_operand.clone()); + // For p2: p2 (negated_reversed_op) p1 operand2.push(Operand::Copy(Place::from(p2))); operand2.push(Operand::Copy(Place::from(p1))); operand2.push(flip_reverse_cmp_operand.clone()); operand2.push(magic_number_operand.clone()); - // rvalue1 = - // Rvalue::Aggregate(Box::new(AggregateKind::Tuple), operand1); - // rvalue2 = - // Rvalue::Aggregate(Box::new(AggregateKind::Tuple), operand2); - rvalue1 = Rvalue::Aggregate(Box::new(ADT.clone()), operand1); - rvalue2 = Rvalue::Aggregate(Box::new(ADT.clone()), operand2); + + rvalue1 = + Rvalue::Aggregate(Box::new(adt_kind.clone()), operand1); + rvalue2 = + Rvalue::Aggregate(Box::new(adt_kind.clone()), operand2); } else { + // True branch: Use original operators. + // For p1: p1 (op) p2 operand1.push(Operand::Copy(Place::from(p1))); operand1.push(Operand::Copy(Place::from(p2))); operand1.push(cmp_operand.clone()); operand1.push(magic_number_operand.clone()); + // For p2: p2 (reversed_op) p1 operand2.push(Operand::Copy(Place::from(p2))); operand2.push(Operand::Copy(Place::from(p1))); operand2.push(reverse_cmp_operand.clone()); operand2.push(magic_number_operand.clone()); - // rvalue1 = - // Rvalue::Aggregate(Box::new(AggregateKind::Tuple), operand1); - // rvalue2 = - // Rvalue::Aggregate(Box::new(AggregateKind::Tuple), operand2); - rvalue1 = Rvalue::Aggregate(Box::new(ADT.clone()), operand1); - rvalue2 = Rvalue::Aggregate(Box::new(ADT.clone()), operand2); + + rvalue1 = + Rvalue::Aggregate(Box::new(adt_kind.clone()), operand1); + rvalue2 = + Rvalue::Aggregate(Box::new(adt_kind.clone()), operand2); } let assign_stmt1 = Statement::new( @@ -339,10 +298,22 @@ impl<'tcx> Replacer<'tcx> { SourceInfo::outermost(body.span), StatementKind::Assign(Box::new((place2, rvalue2))), ); - block_data.statements.insert(0, assign_stmt2); - block_data.statements.insert(0, assign_stmt1); - for i in 0..2 { + let mut insert_index = 0; + for (i, stmt) in block_data.statements.iter().enumerate() { + if !SSATransformer::is_essa_statement( + &self.ssatransformer, + stmt, + ) { + break; + } + insert_index = i + 1; + } + + block_data.statements.insert(insert_index, assign_stmt1); + block_data.statements.insert(insert_index + 1, assign_stmt2); + + for i in insert_index..insert_index + 2 { let essa_in_body = block_data.statements.get_mut(i).unwrap(); let essa_ptr = essa_in_body as *const _; self.ssatransformer.essa_statements.insert(essa_ptr, true); @@ -351,51 +322,68 @@ impl<'tcx> Replacer<'tcx> { _ => panic!("Expected a place"), }; } + + // Case 2: One operand is a constant. (None, Some(_)) | (Some(_), None) => { let mut operand: IndexVec<_, _> = IndexVec::with_capacity(3); let place; - // let place = match op1 { - // Operand::Copy(p) | Operand::Move(p) => Place::from(p), - // _ => panic!("Expected a place"), - // }; + + // normalize operands: place always extracted as 'place', and stored first in operand list? + // Actually logic keeps place as the key, but operand order in Aggregate is [Place, Other] or [Other, Place]? + // Looking at logic below: + // If op1 is place: operand.push(op1), operand.push(op2) -> [Place, Const] + // If op2 is place: operand.push(op2), operand.push(op1) -> [Place, Const] + // So the first element in Aggregate is always the Place (variable). + if op1.constant().is_none() { place = match op1 { Operand::Copy(p) | Operand::Move(p) => Place::from(p), _ => panic!("Expected a place"), }; + operand.push(op1.clone()); + operand.push(op2.clone()); } else { place = match op2 { Operand::Copy(p) | Operand::Move(p) => Place::from(p), _ => panic!("Expected a place"), }; + operand.push(op2.clone()); + operand.push(op1.clone()); } - operand.push(op1.clone()); - operand.push(op2.clone()); + let rvalue; if value == 0 { operand.push(flip_cmp_operand.clone()); } else { operand.push(cmp_operand.clone()); } - let ADT = AggregateKind::Adt( + + let adt_kind = AggregateKind::Adt( self.ssatransformer.essa_def_id.clone(), rustc_abi::VariantIdx::from_u32(0), GenericArgs::empty(), None, None, ); - rvalue = Rvalue::Aggregate(Box::new(ADT.clone()), operand); + rvalue = Rvalue::Aggregate(Box::new(adt_kind.clone()), operand); + let assign_stmt = Statement::new( SourceInfo::outermost(body.span), StatementKind::Assign(Box::new((place, rvalue))), ); - block_data.statements.insert(0, assign_stmt); - - for i in 0..1 { - let essa_in_body = block_data.statements.get_mut(i).unwrap(); - let essa_ptr = essa_in_body as *const _; - self.ssatransformer.essa_statements.insert(essa_ptr, true); + let mut insert_index = 0; + for (i, stmt) in block_data.statements.iter().enumerate() { + if !SSATransformer::is_essa_statement(&self.ssatransformer, stmt) { + break; + } + insert_index = i + 1; } + + block_data.statements.insert(insert_index, assign_stmt); + + let essa_in_body = block_data.statements.get_mut(insert_index).unwrap(); + let essa_ptr = essa_in_body as *const _; + self.ssatransformer.essa_statements.insert(essa_ptr, true); } (Some(_), Some(_)) => {} @@ -464,7 +452,7 @@ impl<'tcx> Replacer<'tcx> { let successors: Vec<_> = terminator.successors().collect(); if let TerminatorKind::SwitchInt { .. } = &terminator.kind { for succ_bb in successors.clone() { - self.process_essa_statments(succ_bb, body, bb); + // self.process_essa_statments(succ_bb, body, bb); } } diff --git a/rapx/tests/range/run_range_tests.sh b/rapx/tests/range/run_range_tests.sh new file mode 100755 index 00000000..ab06fcde --- /dev/null +++ b/rapx/tests/range/run_range_tests.sh @@ -0,0 +1,94 @@ +#!/bin/bash + +# RAP root directory +RAP_ROOT="/home/lcc/rust/RAP" +TESTS_DIR="$RAP_ROOT/rapx/tests/range" + +if [ ! -d "$TESTS_DIR" ]; then + echo "Error: Directory $TESTS_DIR does not exist." + exit 1 +fi + +# Get subdirectories +subdirs=($(find "$TESTS_DIR" -maxdepth 1 -type d | grep -v "^$TESTS_DIR$" | sort)) + +if [ ${#subdirs[@]} -eq 0 ]; then + echo "No subdirectories found in $TESTS_DIR." + exit 1 +fi + +# Ask for RAP_LOG level once +echo "Select RAP_LOG level:" +echo "1. INFO (default)" +echo "2. DEBUG" +echo "3. TRACE" +echo "4. WARN" +read -p "Enter choice [1-4]: " log_choice + +case $log_choice in + 2) export RAP_LOG=DEBUG ;; + 3) export RAP_LOG=TRACE ;; + 4) export RAP_LOG=WARN ;; + *) export RAP_LOG=INFO ;; +esac + +echo "RAP_LOG set to $RAP_LOG" + +while true; do + echo -e "\nAvailable range tests:" + for i in "${!subdirs[@]}"; do + echo "$((i+1)). $(basename "${subdirs[$i]}")" + done + echo "0. Exit" + + read -p "Select a test to run (0-${#subdirs[@]}): " choice + + if ! [[ "$choice" =~ ^[0-9]+$ ]]; then + echo "Invalid input. Please enter a number." + continue + fi + + if [ "$choice" -eq 0 ]; then + echo "Exiting." + exit 0 + fi + + if [ "$choice" -lt 1 ] || [ "$choice" -gt ${#subdirs[@]} ]; then + echo "Invalid selection." + continue + fi + + selected_dir="${subdirs[$((choice-1))]}" + test_name=$(basename "$selected_dir") + + echo "========================================" + echo "Running install.sh..." + "$RAP_ROOT/install.sh" + + echo "Running test: $test_name" + echo "Directory: $selected_dir" + echo "Command: cargo rapx -range=print_mir" + echo "========================================" + + ( + cd "$selected_dir" || exit + cargo rapx -range=print_mir + + echo "Generating PNGs from DOT files..." + count=0 + while IFS= read -r f; do + if [ -f "$f" ]; then + dot -Tpng "$f" -o "${f%.dot}.png" + echo "Generated ${f%.dot}.png" + ((count++)) + fi + done < <(find . -type f -name "*.dot") + + if [ $count -eq 0 ]; then + echo "No .dot files found." + fi + ) + + echo "----------------------------------------" + # read -p "Press Enter to continue..." +done From 572eaf76a9aae04b8b9e98324e30d0db0ac1c892 Mon Sep 17 00:00:00 2001 From: Coursant <24210240198@m.fudan.edu.cn> Date: Tue, 20 Jan 2026 09:54:43 +0800 Subject: [PATCH 3/7] essa fixed --- .../analysis/core/range_analysis/default.rs | 5 +- .../range_analysis/domain/ConstraintGraph.rs | 2 +- rapx/src/analysis/core/range_analysis/mod.rs | 3 +- .../analysis/core/ssa_transform/Replacer.rs | 89 ++++++------------- .../core/ssa_transform/SSATransformer.rs | 2 +- rapx/tests/range/range_5/src/main.rs | 17 ++++ rapx/tests/range/run_range_tests.sh | 9 +- 7 files changed, 58 insertions(+), 69 deletions(-) diff --git a/rapx/src/analysis/core/range_analysis/default.rs b/rapx/src/analysis/core/range_analysis/default.rs index 102614f8..d06b925d 100644 --- a/rapx/src/analysis/core/range_analysis/default.rs +++ b/rapx/src/analysis/core/range_analysis/default.rs @@ -205,7 +205,6 @@ where .expect("Could not write to file"); rap_trace!("Successfully generated graph.dot"); - // println!("Run 'dot -Tpng -o graph.png graph.dot' to generate the image."); } fn only_caller_range_analysis(&mut self) { @@ -220,7 +219,7 @@ where let def_id = local_def_id.to_def_id(); if self.tcx.is_mir_available(def_id) { - rap_debug!("Processing function: {}", self.tcx.def_path_str(def_id)); + rap_info!("Processing function: {}", self.tcx.def_path_str(def_id)); let mut body = self.tcx.optimized_mir(def_id).clone(); let body_mut_ref = unsafe { &mut *(&mut body as *mut Body<'tcx>) }; // Run SSA/ESSA passes @@ -245,7 +244,7 @@ where } } } - rap_debug!("PHASE 1 Complete. CallGraph built."); + rap_debug!("PHASE 1 Complete. ConstraintGraphs & CallGraphs built."); // self.callgraph.print_call_graph(); // Optional: for debugging // ==================================================================== diff --git a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs index 3175714c..ff7fe89c 100644 --- a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs +++ b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs @@ -397,7 +397,7 @@ where vars.sort_by_key(|(local, _)| local.local.index()); for (&local, value) in vars { - rap_info!( + rap_debug!( "Var: {:?}. [ {:?} , {:?} ]", local, value.interval.get_lower_expr(), diff --git a/rapx/src/analysis/core/range_analysis/mod.rs b/rapx/src/analysis/core/range_analysis/mod.rs index 8298edfa..b45ac236 100644 --- a/rapx/src/analysis/core/range_analysis/mod.rs +++ b/rapx/src/analysis/core/range_analysis/mod.rs @@ -86,7 +86,7 @@ where T: IntervalArithmetic + Clone + PartialOrd + Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - writeln!(f, "=== Print range analysis resuts ===")?; + writeln!(f, "=== Print range analysis results ===")?; for (def_id, ra_result) in &self.0 { let fn_name = get_fn_name_byid(def_id); writeln!(f, "Function: {:?} =>", fn_name)?; @@ -181,6 +181,7 @@ impl fmt::Display for RangeType { write!(f, "{}", s) } } + #[derive(Debug, Hash, Clone, PartialEq, Eq)] pub struct Range diff --git a/rapx/src/analysis/core/ssa_transform/Replacer.rs b/rapx/src/analysis/core/ssa_transform/Replacer.rs index d6b3e8c1..89cbe8c1 100644 --- a/rapx/src/analysis/core/ssa_transform/Replacer.rs +++ b/rapx/src/analysis/core/ssa_transform/Replacer.rs @@ -122,12 +122,11 @@ impl<'tcx> Replacer<'tcx> { if let Some(terminator) = &switch_block_data.terminator { if let TerminatorKind::SwitchInt { discr, targets, .. } = &terminator.kind { - { + if targets.iter().count() == 2 { for (value, target) in targets.iter() { self.essa_assign_statement(&target, &bb, value, discr, body); } let otherwise = targets.otherwise(); - self.essa_assign_statement(&otherwise, &bb, 1, discr, body); } } @@ -316,7 +315,9 @@ impl<'tcx> Replacer<'tcx> { for i in insert_index..insert_index + 2 { let essa_in_body = block_data.statements.get_mut(i).unwrap(); let essa_ptr = essa_in_body as *const _; - self.ssatransformer.essa_statements.insert(essa_ptr, true); + self.ssatransformer + .essa_statements + .insert(essa_ptr, *switch_block); } } _ => panic!("Expected a place"), @@ -383,7 +384,9 @@ impl<'tcx> Replacer<'tcx> { let essa_in_body = block_data.statements.get_mut(insert_index).unwrap(); let essa_ptr = essa_in_body as *const _; - self.ssatransformer.essa_statements.insert(essa_ptr, true); + self.ssatransformer + .essa_statements + .insert(essa_ptr, *switch_block); } (Some(_), Some(_)) => {} @@ -452,7 +455,7 @@ impl<'tcx> Replacer<'tcx> { let successors: Vec<_> = terminator.successors().collect(); if let TerminatorKind::SwitchInt { .. } = &terminator.kind { for succ_bb in successors.clone() { - // self.process_essa_statments(succ_bb, body, bb); + self.process_essa_statments(succ_bb, body, bb); } } @@ -460,65 +463,31 @@ impl<'tcx> Replacer<'tcx> { self.process_phi_functions(succ_bb, body, bb); } } - pub fn process_essa_statments( + fn process_essa_statments( &mut self, succ_bb: BasicBlock, body: &mut Body<'tcx>, - switch_bb: BasicBlock, + do_bb: BasicBlock, ) { - let switch_block_data = &body.basic_blocks[switch_bb]; - if let Some(terminator) = &switch_block_data.terminator { - if let TerminatorKind::SwitchInt { discr, .. } = &terminator.kind { - if let Operand::Copy(switch_place) | Operand::Move(switch_place) = discr { - if let Some((op1, op2, cmp_op)) = - self.extract_condition(switch_place, switch_block_data) - { - if op2.constant().is_none() { - let essa_statement = body.basic_blocks.as_mut()[succ_bb] - .statements - .get_mut(0) - .unwrap(); - match &mut essa_statement.kind { - StatementKind::Assign(box (place, rvalue)) => { - if let Rvalue::Aggregate(_, operands) = rvalue { - let loc_1: usize = 0; - let loc_2: usize = 1; - - operands[FieldIdx::from_usize(loc_1)] = op1.clone(); - operands[FieldIdx::from_usize(loc_2)] = op2.clone(); - } - } - _ => {} - } - let essa_statement = body.basic_blocks.as_mut()[succ_bb] - .statements - .get_mut(1) - .unwrap(); - match &mut essa_statement.kind { - StatementKind::Assign(box (place, rvalue)) => { - if let Rvalue::Aggregate(_, operands) = rvalue { - let loc_1: usize = 0; - let loc_2: usize = 1; - operands[FieldIdx::from_usize(loc_1)] = op2.clone(); - operands[FieldIdx::from_usize(loc_2)] = op1.clone(); - } - } - _ => {} - } - } else { - let essa_statement = body.basic_blocks.as_mut()[succ_bb] - .statements - .get_mut(0) - .unwrap(); - match &mut essa_statement.kind { - StatementKind::Assign(box (place, rvalue)) => { - if let Rvalue::Aggregate(_, operands) = rvalue { - let loc: usize = 0; - operands[FieldIdx::from_usize(loc)] = op1.clone(); - } - } - _ => {} - } + for statement in body.basic_blocks.as_mut()[succ_bb].statements.iter_mut() { + let sigma_stmt = statement as *const _; + + if SSATransformer::is_essa_statement(&self.ssatransformer, statement) { + if let Some(pred) = self.ssatransformer.essa_statements.get(&sigma_stmt) { + if *pred != do_bb { + continue; + } + } + if let StatementKind::Assign(box (_, rvalue)) = &mut statement.kind { + if let Rvalue::Aggregate(_, operands) = rvalue { + let operand_count = operands.len(); + let index = 0; + + if index < operand_count { + self.replace_operand( + &mut operands[FieldIdx::from_usize(index)], + &do_bb, + ); } } } diff --git a/rapx/src/analysis/core/ssa_transform/SSATransformer.rs b/rapx/src/analysis/core/ssa_transform/SSATransformer.rs index f251e60a..c2332df0 100644 --- a/rapx/src/analysis/core/ssa_transform/SSATransformer.rs +++ b/rapx/src/analysis/core/ssa_transform/SSATransformer.rs @@ -29,7 +29,7 @@ pub struct SSATransformer<'tcx> { pub skipped: HashSet, pub phi_index: HashMap<*const Statement<'tcx>, usize>, pub phi_statements: HashMap<*const Statement<'tcx>, bool>, - pub essa_statements: HashMap<*const Statement<'tcx>, bool>, + pub essa_statements: HashMap<*const Statement<'tcx>, BasicBlock>, pub phi_def_id: DefId, pub essa_def_id: DefId, pub ref_local_map: HashMap, diff --git a/rapx/tests/range/range_5/src/main.rs b/rapx/tests/range/range_5/src/main.rs index ce43589f..b7cbd2cf 100644 --- a/rapx/tests/range/range_5/src/main.rs +++ b/rapx/tests/range/range_5/src/main.rs @@ -2,6 +2,23 @@ pub fn starts_with_ascii_alpha(string: &str) -> bool { matches!(string.as_bytes()[0], b'a'..=b'z' | b'A'..=b'Z') } +fn is_url_code_point(c: char) -> bool { + matches!(c, + 'a'..='z' | + 'A'..='Z' | + '0'..='9' | + '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | + '.' | '/' | ':' | ';' | '=' | '?' | '@' | '_' | '~' | + '\u{A0}'..='\u{D7FF}' | '\u{E000}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' | + '\u{10000}'..='\u{1FFFD}' | '\u{20000}'..='\u{2FFFD}' | + '\u{30000}'..='\u{3FFFD}' | '\u{40000}'..='\u{4FFFD}' | + '\u{50000}'..='\u{5FFFD}' | '\u{60000}'..='\u{6FFFD}' | + '\u{70000}'..='\u{7FFFD}' | '\u{80000}'..='\u{8FFFD}' | + '\u{90000}'..='\u{9FFFD}' | '\u{A0000}'..='\u{AFFFD}' | + '\u{B0000}'..='\u{BFFFD}' | '\u{C0000}'..='\u{CFFFD}' | + '\u{D0000}'..='\u{DFFFD}' | '\u{E1000}'..='\u{EFFFD}' | + '\u{F0000}'..='\u{FFFFD}' | '\u{100000}'..='\u{10FFFD}') +} #[derive(PartialEq, Eq)] pub enum Context { UrlParser, diff --git a/rapx/tests/range/run_range_tests.sh b/rapx/tests/range/run_range_tests.sh index ab06fcde..b0f2250d 100755 --- a/rapx/tests/range/run_range_tests.sh +++ b/rapx/tests/range/run_range_tests.sh @@ -63,8 +63,11 @@ while true; do echo "========================================" echo "Running install.sh..." - "$RAP_ROOT/install.sh" - + ( + cd "$RAP_ROOT" || exit + ./install.sh + ) + echo "Running test: $test_name" echo "Directory: $selected_dir" echo "Command: cargo rapx -range=print_mir" @@ -72,7 +75,7 @@ while true; do ( cd "$selected_dir" || exit - cargo rapx -range=print_mir + cargo rapx -range=print_mir echo "Generating PNGs from DOT files..." count=0 From 5cd21abfaafdc43b2e726e2946a6493adfe85f3d Mon Sep 17 00:00:00 2001 From: Coursant <24210240198@m.fudan.edu.cn> Date: Thu, 22 Jan 2026 06:56:00 +0800 Subject: [PATCH 4/7] fix is_essa --- .../range_analysis/domain/ConstraintGraph.rs | 4 +- .../analysis/core/ssa_transform/Replacer.rs | 96 +++++++++++-------- .../core/ssa_transform/SSATransformer.rs | 55 ++++++++--- rapx/src/preprocess/ssa_preprocess.rs | 1 + rapx/tests/range/range_5/Cargo.lock | 2 +- rapx/tests/range/range_5/Cargo.toml | 2 +- rapx/tests/range/range_5/src/main.rs | 75 ++++++++------- 7 files changed, 140 insertions(+), 95 deletions(-) diff --git a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs index ff7fe89c..81ba1c30 100644 --- a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs +++ b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs @@ -698,7 +698,9 @@ where if let Some(terminator) = &block_data.terminator { match &terminator.kind { TerminatorKind::SwitchInt { discr, targets } => { - self.build_value_branch_map(body, discr, targets, bb, block_data); + if targets.iter().count() == 1 { + self.build_value_branch_map(body, discr, targets, bb, block_data); + } } TerminatorKind::Goto { target } => { // self.build_value_goto_map(block_index, *target); diff --git a/rapx/src/analysis/core/ssa_transform/Replacer.rs b/rapx/src/analysis/core/ssa_transform/Replacer.rs index 89cbe8c1..fadc93df 100644 --- a/rapx/src/analysis/core/ssa_transform/Replacer.rs +++ b/rapx/src/analysis/core/ssa_transform/Replacer.rs @@ -95,15 +95,6 @@ impl<'tcx> Replacer<'tcx> { .statements .insert(0, phi_stmt); } - - for i in 0..vars.len() { - let phi_in_body = body.basic_blocks.as_mut()[block] - .statements - .get_mut(i) - .unwrap(); - let phi_ptr = phi_in_body as *const _; - self.ssatransformer.phi_statements.insert(phi_ptr, true); - } } } pub fn insert_essa_statement(&mut self, body: &mut Body<'tcx>) { @@ -122,10 +113,10 @@ impl<'tcx> Replacer<'tcx> { if let Some(terminator) = &switch_block_data.terminator { if let TerminatorKind::SwitchInt { discr, targets, .. } = &terminator.kind { - if targets.iter().count() == 2 { - for (value, target) in targets.iter() { - self.essa_assign_statement(&target, &bb, value, discr, body); - } + if targets.iter().count() == 1 { + let (value, target) = targets.iter().next().unwrap(); + self.essa_assign_statement(&target, &bb, value, discr, body); + let otherwise = targets.otherwise(); self.essa_assign_statement(&otherwise, &bb, 1, discr, body); } @@ -205,8 +196,7 @@ impl<'tcx> Replacer<'tcx> { ) { let switch_block_data = &body.basic_blocks[*switch_block]; - // Define a magic number to identify eSSA statements in Place-Place comparisons. - let magic_number_operand = self.make_const_operand(213134123); + let magic_number_operand = self.make_const_operand(switch_block.as_usize() as u64); // Helper: verify if the discriminant is a Place (variable). if let Operand::Copy(switch_place) | Operand::Move(switch_place) = discr { @@ -314,10 +304,11 @@ impl<'tcx> Replacer<'tcx> { for i in insert_index..insert_index + 2 { let essa_in_body = block_data.statements.get_mut(i).unwrap(); - let essa_ptr = essa_in_body as *const _; - self.ssatransformer - .essa_statements - .insert(essa_ptr, *switch_block); + rap_trace!( + "Inserted eSSA statement {:?} in block {:?}", + essa_in_body, + magic_number_operand + ); } } _ => panic!("Expected a place"), @@ -358,7 +349,7 @@ impl<'tcx> Replacer<'tcx> { } else { operand.push(cmp_operand.clone()); } - + operand.push(magic_number_operand.clone()); let adt_kind = AggregateKind::Adt( self.ssatransformer.essa_def_id.clone(), rustc_abi::VariantIdx::from_u32(0), @@ -384,9 +375,12 @@ impl<'tcx> Replacer<'tcx> { let essa_in_body = block_data.statements.get_mut(insert_index).unwrap(); let essa_ptr = essa_in_body as *const _; - self.ssatransformer - .essa_statements - .insert(essa_ptr, *switch_block); + + rap_trace!( + "Inserted eSSA statement {:?} in block {:?}", + essa_in_body, + magic_number_operand + ); } (Some(_), Some(_)) => {} @@ -453,9 +447,11 @@ impl<'tcx> Replacer<'tcx> { self.rename_terminator(bb, body); let terminator = body.basic_blocks[bb].terminator(); let successors: Vec<_> = terminator.successors().collect(); - if let TerminatorKind::SwitchInt { .. } = &terminator.kind { - for succ_bb in successors.clone() { - self.process_essa_statments(succ_bb, body, bb); + if let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind { + if targets.iter().count() == 1 { + for succ_bb in successors.clone() { + self.process_essa_statments(succ_bb, body, bb); + } } } @@ -469,25 +465,31 @@ impl<'tcx> Replacer<'tcx> { body: &mut Body<'tcx>, do_bb: BasicBlock, ) { + // Iterate through all statements in the successor basic block to find and update ESSA nodes. for statement in body.basic_blocks.as_mut()[succ_bb].statements.iter_mut() { - let sigma_stmt = statement as *const _; - - if SSATransformer::is_essa_statement(&self.ssatransformer, statement) { - if let Some(pred) = self.ssatransformer.essa_statements.get(&sigma_stmt) { - if *pred != do_bb { + // Check if the current statement is an ESSA statement (identified by specific DefId). + if self.ssatransformer.is_essa_statement(statement) { + // Retrieve the source basic block ID encoded in the statement's operands. + // This replaces the unstable pointer-based lookup map. + if let Some(pred_block) = self.ssatransformer.get_essa_source_block(statement) { + // Check if this ESSA statement corresponds to the predecessor block (`do_bb`) + // we are currently processing. If not, skip it. + if pred_block != do_bb { continue; } - } - if let StatementKind::Assign(box (_, rvalue)) = &mut statement.kind { - if let Rvalue::Aggregate(_, operands) = rvalue { - let operand_count = operands.len(); - let index = 0; - if index < operand_count { - self.replace_operand( - &mut operands[FieldIdx::from_usize(index)], - &do_bb, - ); + // Proceed to rename the variable in the ESSA statement. + if let StatementKind::Assign(box (_, rvalue)) = &mut statement.kind { + if let Rvalue::Aggregate(_, operands) = rvalue { + // The first operand (index 0) is the variable that needs to be renamed/replaced. + let index = 0; + if index < operands.len() { + // Replace the operand with the correct SSA version for the current path. + self.replace_operand( + &mut operands[FieldIdx::from_usize(index)], + &do_bb, + ); + } } } } @@ -539,10 +541,22 @@ impl<'tcx> Replacer<'tcx> { // let rc_stat = Rc::new(RefCell::new(statement)); let is_phi = SSATransformer::is_phi_statement(&self.ssatransformer, statement); let is_essa = SSATransformer::is_essa_statement(&self.ssatransformer, statement); + rap_trace!( + "IS in statement at block {:?}: {:?}, is_phi: {}, is_essa: {}", + bb, + statement.clone(), + is_phi, + is_essa + ); match &mut statement.kind { StatementKind::Assign(box (place, rvalue)) => { if !is_phi { if !is_essa { + rap_trace!( + "Renaming in statement at block {:?}: {:?}", + bb, + rvalue.clone() + ); self.replace_rvalue(rvalue, &bb); self.rename_local_def(place, &bb, true); } else { diff --git a/rapx/src/analysis/core/ssa_transform/SSATransformer.rs b/rapx/src/analysis/core/ssa_transform/SSATransformer.rs index c2332df0..d17a4d3f 100644 --- a/rapx/src/analysis/core/ssa_transform/SSATransformer.rs +++ b/rapx/src/analysis/core/ssa_transform/SSATransformer.rs @@ -28,8 +28,6 @@ pub struct SSATransformer<'tcx> { pub local_defination_block: HashMap, pub skipped: HashSet, pub phi_index: HashMap<*const Statement<'tcx>, usize>, - pub phi_statements: HashMap<*const Statement<'tcx>, bool>, - pub essa_statements: HashMap<*const Statement<'tcx>, BasicBlock>, pub phi_def_id: DefId, pub essa_def_id: DefId, pub ref_local_map: HashMap, @@ -102,8 +100,6 @@ impl<'tcx> SSATransformer<'tcx> { local_defination_block: local_defination_block, skipped: skipped, phi_index: HashMap::default(), - phi_statements: HashMap::default(), - essa_statements: HashMap::default(), phi_def_id: ssa_def_id, essa_def_id: essa_def_id, ref_local_map: HashMap::default(), @@ -291,19 +287,50 @@ impl<'tcx> SSATransformer<'tcx> { } pub fn is_phi_statement(&self, statement: &Statement<'tcx>) -> bool { - let phi_stmt = statement as *const Statement<'tcx>; - if self.phi_statements.contains_key(&phi_stmt) { - return true; - } else { - return false; + if let StatementKind::Assign(box (_, rvalue)) = &statement.kind { + if let Rvalue::Aggregate(box aggregate_kind, _) = rvalue { + if let AggregateKind::Adt(def_id, ..) = aggregate_kind { + return *def_id == self.phi_def_id; + } + } } + false } + pub fn is_essa_statement(&self, statement: &Statement<'tcx>) -> bool { - let essa_stmt = statement as *const Statement<'tcx>; - if self.essa_statements.contains_key(&essa_stmt) { - return true; - } else { - return false; + if let StatementKind::Assign(box (_, rvalue)) = &statement.kind { + if let Rvalue::Aggregate(box aggregate_kind, _) = rvalue { + if let AggregateKind::Adt(def_id, ..) = aggregate_kind { + return *def_id == self.essa_def_id; + } + } + } + false + } + pub fn get_essa_source_block(&self, statement: &Statement<'tcx>) -> Option { + if !self.is_essa_statement(statement) { + return None; + } + + if let StatementKind::Assign(box (_, Rvalue::Aggregate(_, operands))) = &statement.kind { + if let Some(last_op) = operands.into_iter().last() { + if let Operand::Constant(box ConstOperand { const_: c, .. }) = last_op { + if let Some(val) = self.try_const_to_usize(c) { + return Some(BasicBlock::from_usize(val as usize)); + } + } + } + } + None + } + + fn try_const_to_usize(&self, c: &Const<'tcx>) -> Option { + if let Some(scalar_int) = c.try_to_scalar_int() { + let size = scalar_int.size(); + if let Ok(bits) = scalar_int.try_to_bits(size) { + return Some(bits as u64); + } } + None } } diff --git a/rapx/src/preprocess/ssa_preprocess.rs b/rapx/src/preprocess/ssa_preprocess.rs index 76e407c8..321f5f64 100644 --- a/rapx/src/preprocess/ssa_preprocess.rs +++ b/rapx/src/preprocess/ssa_preprocess.rs @@ -31,6 +31,7 @@ pub(crate) fn create_ssa_struct(_krate: &mut Crate) { ("op1", Symbol::intern("i128")), ("op2", Symbol::intern("i128")), ("cmp", Symbol::intern("i128")), + ("switch_bb", Symbol::intern("i128")), ], ); diff --git a/rapx/tests/range/range_5/Cargo.lock b/rapx/tests/range/range_5/Cargo.lock index c98ed379..5645ef32 100644 --- a/rapx/tests/range/range_5/Cargo.lock +++ b/rapx/tests/range/range_5/Cargo.lock @@ -3,5 +3,5 @@ version = 4 [[package]] -name = "range_3" +name = "range_5" version = "0.1.0" diff --git a/rapx/tests/range/range_5/Cargo.toml b/rapx/tests/range/range_5/Cargo.toml index 18853bce..fc2e0cc0 100644 --- a/rapx/tests/range/range_5/Cargo.toml +++ b/rapx/tests/range/range_5/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "range_3" +name = "range_5" version = "0.1.0" edition = "2021" diff --git a/rapx/tests/range/range_5/src/main.rs b/rapx/tests/range/range_5/src/main.rs index b7cbd2cf..effdaa5a 100644 --- a/rapx/tests/range/range_5/src/main.rs +++ b/rapx/tests/range/range_5/src/main.rs @@ -7,43 +7,44 @@ fn is_url_code_point(c: char) -> bool { 'a'..='z' | 'A'..='Z' | '0'..='9' | - '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | - '.' | '/' | ':' | ';' | '=' | '?' | '@' | '_' | '~' | - '\u{A0}'..='\u{D7FF}' | '\u{E000}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' | - '\u{10000}'..='\u{1FFFD}' | '\u{20000}'..='\u{2FFFD}' | - '\u{30000}'..='\u{3FFFD}' | '\u{40000}'..='\u{4FFFD}' | - '\u{50000}'..='\u{5FFFD}' | '\u{60000}'..='\u{6FFFD}' | - '\u{70000}'..='\u{7FFFD}' | '\u{80000}'..='\u{8FFFD}' | - '\u{90000}'..='\u{9FFFD}' | '\u{A0000}'..='\u{AFFFD}' | - '\u{B0000}'..='\u{BFFFD}' | '\u{C0000}'..='\u{CFFFD}' | - '\u{D0000}'..='\u{DFFFD}' | '\u{E1000}'..='\u{EFFFD}' | - '\u{F0000}'..='\u{FFFFD}' | '\u{100000}'..='\u{10FFFD}') -} -#[derive(PartialEq, Eq)] -pub enum Context { - UrlParser, - Setter, -} -pub fn parse_scheme<'a>(input: &'a str, context: Context) -> Option<(String, &'a str)> { - if input.is_empty() || !starts_with_ascii_alpha(input) { - return None - } - for (i, c) in input.char_indices() { - match c { - 'a'..='z' | 'A'..='Z' | '0'..='9' | '+' | '-' | '.' => (), - ':' => return Some(( - input[..i].to_ascii_lowercase(), - &input[i + 1..], - )), - _ => return None, - } - } - // EOF before ':' - match context { - Context::Setter => Some((input.to_ascii_lowercase(), "")), - Context::UrlParser => None - } + // '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | + // '.' | '/' | ':' | ';' | '=' | '?' | '@' | '_' | '~' | + // '\u{A0}'..='\u{D7FF}' | '\u{E000}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' | + // '\u{10000}'..='\u{1FFFD}' | '\u{20000}'..='\u{2FFFD}' | + // '\u{30000}'..='\u{3FFFD}' | '\u{40000}'..='\u{4FFFD}' | + // '\u{50000}'..='\u{5FFFD}' | '\u{60000}'..='\u{6FFFD}' | + // '\u{70000}'..='\u{7FFFD}' | '\u{80000}'..='\u{8FFFD}' | + // '\u{90000}'..='\u{9FFFD}' | '\u{A0000}'..='\u{AFFFD}' | + // '\u{B0000}'..='\u{BFFFD}' | '\u{C0000}'..='\u{CFFFD}' | + // '\u{D0000}'..='\u{DFFFD}' | '\u{E1000}'..='\u{EFFFD}' | + // '\u{F0000}'..='\u{FFFFD}' | + '\u{100000}'..='\u{10FFFD}') } +// #[derive(PartialEq, Eq)] +// pub enum Context { +// UrlParser, +// Setter, +// } +// pub fn parse_scheme<'a>(input: &'a str, context: Context) -> Option<(String, &'a str)> { +// if input.is_empty() || !starts_with_ascii_alpha(input) { +// return None +// } +// for (i, c) in input.char_indices() { +// match c { +// 'a'..='z' | 'A'..='Z' | '0'..='9' | '+' | '-' | '.' => (), +// ':' => return Some(( +// input[..i].to_ascii_lowercase(), +// &input[i + 1..], +// )), +// _ => return None, +// } +// } +// // EOF before ':' +// match context { +// Context::Setter => Some((input.to_ascii_lowercase(), "")), +// Context::UrlParser => None +// } +// } pub fn main(){ - parse_scheme("http:www.example.com",Context::UrlParser); + // parse_scheme("http:www.example.com",Context::UrlParser); } \ No newline at end of file From 7f4539ef4fd30d41073bbf3fdabf8d8b28efbc5e Mon Sep 17 00:00:00 2001 From: Coursant <24210240198@m.fudan.edu.cn> Date: Sat, 24 Jan 2026 21:56:53 +0800 Subject: [PATCH 5/7] fix phi_index --- .../range_analysis/domain/ConstraintGraph.rs | 117 +++++++++--------- .../analysis/core/ssa_transform/Replacer.rs | 33 +++-- .../core/ssa_transform/SSATransformer.rs | 2 +- rapx/tests/range/range_6/Cargo.lock | 7 ++ rapx/tests/range/range_6/Cargo.toml | 6 + rapx/tests/range/range_6/src/main.rs | 32 +++++ 6 files changed, 122 insertions(+), 75 deletions(-) create mode 100644 rapx/tests/range/range_6/Cargo.lock create mode 100644 rapx/tests/range/range_6/Cargo.toml create mode 100644 rapx/tests/range/range_6/src/main.rs diff --git a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs index 81ba1c30..1fae4ff6 100644 --- a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs +++ b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs @@ -397,7 +397,7 @@ where vars.sort_by_key(|(local, _)| local.local.index()); for (&local, value) in vars { - rap_debug!( + rap_info!( "Var: {:?}. [ {:?} , {:?} ]", local, value.interval.get_lower_expr(), @@ -1557,7 +1557,6 @@ where self.defmap.insert(sink, bop_index); } - fn add_binary_op( &mut self, sink: &'tcx Place<'tcx>, @@ -1568,72 +1567,78 @@ where bin_op: BinOp, ) { rap_trace!("binary_op{:?}\n", inst); + + // Define the sink node (Def) let sink_node = self.def_add_varnode_sym(sink, rvalue); rap_trace!("addsink_in_binary_op{:?}\n", sink_node); + let bop_index = self.oprs.len(); - let BI: BasicInterval = BasicInterval::new(Range::default(T::min_value())); + let bi: BasicInterval = BasicInterval::new(Range::default(T::min_value())); - let source1_place = match op1 { - Operand::Copy(place) | Operand::Move(place) => { - self.use_add_varnode_sym(place, rvalue); - rap_trace!("addvar_in_binary_op{:?}\n", place); + // Match both operands simultaneously to handle all combinations. + // Goal: Ensure source1 is always a Place if at least one Place exists. + let (source1_place, source2_place, const_val) = match (op1, op2) { + // Case 1: Place + Place + (Operand::Copy(p1) | Operand::Move(p1), Operand::Copy(p2) | Operand::Move(p2)) => { + self.use_add_varnode_sym(p1, rvalue); + self.use_add_varnode_sym(p2, rvalue); + rap_trace!("addvar_in_binary_op p1:{:?}, p2:{:?}\n", p1, p2); - Some(place) + (Some(p1), Some(p2), None) } - Operand::Constant(_) => None, - }; - match op2 { - Operand::Copy(place) | Operand::Move(place) => { - self.use_add_varnode_sym(place, rvalue); - rap_trace!("addvar_in_binary_op{:?}\n", place); - - let source2_place = Some(place); - let BOP = BinaryOp::new( - IntervalType::Basic(BI), - sink, - inst, - source1_place, - source2_place, - None, - bin_op.clone(), - ); - self.oprs.push(BasicOpKind::Binary(BOP)); - // let bop_ref = unsafe { &*(self.oprs.last().unwrap() as *const BasicOp<'tcx, T>) }; - self.defmap.insert(sink, bop_index); - if let Some(place) = source1_place { - self.usemap.entry(place).or_default().insert(bop_index); - } + // Case 2: Place + Constant + (Operand::Copy(p1) | Operand::Move(p1), Operand::Constant(c2)) => { + self.use_add_varnode_sym(p1, rvalue); + rap_trace!("addvar_in_binary_op p1:{:?}\n", p1); - if let Some(place) = source2_place { - self.usemap.entry(place).or_default().insert(bop_index); - } + (Some(p1), None, Some(c2.const_)) } - Operand::Constant(c) => { - // let const_value = Self::convert_const(&c.const_).unwrap(); - let BOP = BinaryOp::new( - IntervalType::Basic(BI), - sink, - inst, - source1_place, - None, - Some(c.const_), - bin_op.clone(), - ); - self.oprs.push(BasicOpKind::Binary(BOP)); - // let bop_ref = unsafe { &*(self.oprs.last().unwrap() as *const BasicOp<'tcx, T>) }; - self.defmap.insert(sink, bop_index); - if let Some(place) = source1_place { - self.usemap.entry(place).or_default().insert(bop_index); - } + + // Case 3: Constant + Place + // Here we normalize: Treat the Place (op2) as source1, and the Constant (op1) as the const value. + // NOTE: Be careful with non-commutative operations (Sub, Div) in your interval logic later, + // as the physical order is swapped here. + (Operand::Constant(c1), Operand::Copy(p2) | Operand::Move(p2)) => { + self.use_add_varnode_sym(p2, rvalue); + rap_trace!("addvar_in_binary_op p2(as source1):{:?}\n", p2); + + // Assign p2 to the first return position to make it source1 + (Some(p2), None, Some(c1.const_)) + } + + // Case 4: Constant + Constant + (Operand::Constant(c1), Operand::Constant(_)) => { + // Logic depends on how you want to handle two constants. + // Usually keeping one is sufficient for the struct signature. + (None, None, Some(c1.const_)) } }; - // rap_trace!("varnodes{:?}\n", self.vars); - // rap_trace!("defmap{:?}\n", self.defmap); - // rap_trace!("usemap{:?}\n", self.usemap); - // rap_trace!("{:?}add_binary_op{:?}\n", inst,sink); - // ... + // Construct the BinaryOp + let bop = BinaryOp::new( + IntervalType::Basic(bi), + sink, + inst, + source1_place, // This is guaranteed to be the Place (if one exists) + source2_place, + const_val, + bin_op.clone(), + ); + + self.oprs.push(BasicOpKind::Binary(bop)); + + // Update DefMap + self.defmap.insert(sink, bop_index); + + // Update UseMap + if let Some(place) = source1_place { + self.usemap.entry(place).or_default().insert(bop_index); + } + + if let Some(place) = source2_place { + self.usemap.entry(place).or_default().insert(bop_index); + } } fn add_ref_op( &mut self, diff --git a/rapx/src/analysis/core/ssa_transform/Replacer.rs b/rapx/src/analysis/core/ssa_transform/Replacer.rs index fadc93df..a6746313 100644 --- a/rapx/src/analysis/core/ssa_transform/Replacer.rs +++ b/rapx/src/analysis/core/ssa_transform/Replacer.rs @@ -450,16 +450,16 @@ impl<'tcx> Replacer<'tcx> { if let TerminatorKind::SwitchInt { targets, .. } = &terminator.kind { if targets.iter().count() == 1 { for succ_bb in successors.clone() { - self.process_essa_statments(succ_bb, body, bb); + self.rename_essa_statments(succ_bb, body, bb); } } } for succ_bb in successors { - self.process_phi_functions(succ_bb, body, bb); + self.rename_phi_functions(succ_bb, body, bb); } } - fn process_essa_statments( + fn rename_essa_statments( &mut self, succ_bb: BasicBlock, body: &mut Body<'tcx>, @@ -497,45 +497,42 @@ impl<'tcx> Replacer<'tcx> { } } - fn process_phi_functions( + fn rename_phi_functions( &mut self, succ_bb: BasicBlock, body: &mut Body<'tcx>, do_bb: BasicBlock, ) { - for statement in body.basic_blocks.as_mut()[succ_bb].statements.iter_mut() { - let phi_stmt = statement as *const _; + for (stmt_idx, statement) in body.basic_blocks.as_mut()[succ_bb] + .statements + .iter_mut() + .enumerate() + { + let location = Location { + block: succ_bb, + statement_index: stmt_idx, + }; if SSATransformer::is_phi_statement(&self.ssatransformer, statement) { if let StatementKind::Assign(box (_, rvalue)) = &mut statement.kind { if let Rvalue::Aggregate(_, operands) = rvalue { let operand_count = operands.len(); - let index = self - .ssatransformer - .phi_index - .entry(phi_stmt) - .or_insert(0) - .clone(); + let index = *self.ssatransformer.phi_index.entry(location).or_insert(0); if index < operand_count { - // self.replace_operand(&mut operands[(index).into()], &succ_bb);s match &mut operands[FieldIdx::from_usize(index)] { Operand::Copy(place) | Operand::Move(place) => { self.replace_place(place, &do_bb); } _ => {} } - *self.ssatransformer.phi_index.entry(phi_stmt).or_insert(0) += 1; - // if *index >= operand_count { - // self.ssatransformer.phi_index.remove(&phi_stmt); - // } + *self.ssatransformer.phi_index.entry(location).or_insert(0) += 1; } } } } } } - pub fn rename_statement(&mut self, bb: BasicBlock, body: &mut Body<'tcx>) { for statement in body.basic_blocks.as_mut()[bb].statements.iter_mut() { // let rc_stat = Rc::new(RefCell::new(statement)); diff --git a/rapx/src/analysis/core/ssa_transform/SSATransformer.rs b/rapx/src/analysis/core/ssa_transform/SSATransformer.rs index d17a4d3f..dbc42f18 100644 --- a/rapx/src/analysis/core/ssa_transform/SSATransformer.rs +++ b/rapx/src/analysis/core/ssa_transform/SSATransformer.rs @@ -27,7 +27,7 @@ pub struct SSATransformer<'tcx> { pub local_index: usize, pub local_defination_block: HashMap, pub skipped: HashSet, - pub phi_index: HashMap<*const Statement<'tcx>, usize>, + pub phi_index: HashMap, pub phi_def_id: DefId, pub essa_def_id: DefId, pub ref_local_map: HashMap, diff --git a/rapx/tests/range/range_6/Cargo.lock b/rapx/tests/range/range_6/Cargo.lock new file mode 100644 index 00000000..5645ef32 --- /dev/null +++ b/rapx/tests/range/range_6/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "range_5" +version = "0.1.0" diff --git a/rapx/tests/range/range_6/Cargo.toml b/rapx/tests/range/range_6/Cargo.toml new file mode 100644 index 00000000..fc2e0cc0 --- /dev/null +++ b/rapx/tests/range/range_6/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "range_5" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/rapx/tests/range/range_6/src/main.rs b/rapx/tests/range/range_6/src/main.rs new file mode 100644 index 00000000..5b6fec0b --- /dev/null +++ b/rapx/tests/range/range_6/src/main.rs @@ -0,0 +1,32 @@ +fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) { + let mut longest = -1; + let mut longest_length = -1; + let mut start = -1; + macro_rules! finish_sequence( + ($end: expr) => { + if start >= 0 { + let length = $end - start; + if length > longest_length { + longest = start; + longest_length = length; + } + } + }; + ); + for i in 0..8 { + if pieces[i as usize] == 0 { + if start < 0 { + start = i; + } + } else { + finish_sequence!(i); + start = -1; + } + } + finish_sequence!(8); + (longest, longest + longest_length) +} +pub fn main(){ + let pieces : [u16; 8]= [42; 8]; + longest_zero_sequence(&pieces); +} \ No newline at end of file From 6eca8fb982d3fc4c4d58510e105e72eb36d6c256 Mon Sep 17 00:00:00 2001 From: Coursant <24210240198@m.fudan.edu.cn> Date: Mon, 26 Jan 2026 22:26:33 +0800 Subject: [PATCH 6/7] add new test --- rapx/tests/range/range_5/src/main.rs | 74 ++++++++++++++-------------- rapx/tests/range/range_6/src/main.rs | 41 +++++---------- 2 files changed, 48 insertions(+), 67 deletions(-) diff --git a/rapx/tests/range/range_5/src/main.rs b/rapx/tests/range/range_5/src/main.rs index effdaa5a..a4e81a21 100644 --- a/rapx/tests/range/range_5/src/main.rs +++ b/rapx/tests/range/range_5/src/main.rs @@ -7,44 +7,44 @@ fn is_url_code_point(c: char) -> bool { 'a'..='z' | 'A'..='Z' | '0'..='9' | - // '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | - // '.' | '/' | ':' | ';' | '=' | '?' | '@' | '_' | '~' | - // '\u{A0}'..='\u{D7FF}' | '\u{E000}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' | - // '\u{10000}'..='\u{1FFFD}' | '\u{20000}'..='\u{2FFFD}' | - // '\u{30000}'..='\u{3FFFD}' | '\u{40000}'..='\u{4FFFD}' | - // '\u{50000}'..='\u{5FFFD}' | '\u{60000}'..='\u{6FFFD}' | - // '\u{70000}'..='\u{7FFFD}' | '\u{80000}'..='\u{8FFFD}' | - // '\u{90000}'..='\u{9FFFD}' | '\u{A0000}'..='\u{AFFFD}' | - // '\u{B0000}'..='\u{BFFFD}' | '\u{C0000}'..='\u{CFFFD}' | - // '\u{D0000}'..='\u{DFFFD}' | '\u{E1000}'..='\u{EFFFD}' | - // '\u{F0000}'..='\u{FFFFD}' | + '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | '-' | + '.' | '/' | ':' | ';' | '=' | '?' | '@' | '_' | '~' | + '\u{A0}'..='\u{D7FF}' | '\u{E000}'..='\u{FDCF}' | '\u{FDF0}'..='\u{FFFD}' | + '\u{10000}'..='\u{1FFFD}' | '\u{20000}'..='\u{2FFFD}' | + '\u{30000}'..='\u{3FFFD}' | '\u{40000}'..='\u{4FFFD}' | + '\u{50000}'..='\u{5FFFD}' | '\u{60000}'..='\u{6FFFD}' | + '\u{70000}'..='\u{7FFFD}' | '\u{80000}'..='\u{8FFFD}' | + '\u{90000}'..='\u{9FFFD}' | '\u{A0000}'..='\u{AFFFD}' | + '\u{B0000}'..='\u{BFFFD}' | '\u{C0000}'..='\u{CFFFD}' | + '\u{D0000}'..='\u{DFFFD}' | '\u{E1000}'..='\u{EFFFD}' | + '\u{F0000}'..='\u{FFFFD}' | '\u{100000}'..='\u{10FFFD}') } -// #[derive(PartialEq, Eq)] -// pub enum Context { -// UrlParser, -// Setter, -// } -// pub fn parse_scheme<'a>(input: &'a str, context: Context) -> Option<(String, &'a str)> { -// if input.is_empty() || !starts_with_ascii_alpha(input) { -// return None -// } -// for (i, c) in input.char_indices() { -// match c { -// 'a'..='z' | 'A'..='Z' | '0'..='9' | '+' | '-' | '.' => (), -// ':' => return Some(( -// input[..i].to_ascii_lowercase(), -// &input[i + 1..], -// )), -// _ => return None, -// } -// } -// // EOF before ':' -// match context { -// Context::Setter => Some((input.to_ascii_lowercase(), "")), -// Context::UrlParser => None -// } -// } +#[derive(PartialEq, Eq)] +pub enum Context { + UrlParser, + Setter, +} +pub fn parse_scheme<'a>(input: &'a str, context: Context) -> Option<(String, &'a str)> { + if input.is_empty() || !starts_with_ascii_alpha(input) { + return None + } + for (i, c) in input.char_indices() { + match c { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '+' | '-' | '.' => (), + ':' => return Some(( + input[..i].to_ascii_lowercase(), + &input[i + 1..], + )), + _ => return None, + } + } + // EOF before ':' + match context { + Context::Setter => Some((input.to_ascii_lowercase(), "")), + Context::UrlParser => None + } +} pub fn main(){ - // parse_scheme("http:www.example.com",Context::UrlParser); + parse_scheme("http:www.example.com",Context::UrlParser); } \ No newline at end of file diff --git a/rapx/tests/range/range_6/src/main.rs b/rapx/tests/range/range_6/src/main.rs index 5b6fec0b..0d95d977 100644 --- a/rapx/tests/range/range_6/src/main.rs +++ b/rapx/tests/range/range_6/src/main.rs @@ -1,32 +1,13 @@ -fn longest_zero_sequence(pieces: &[u16; 8]) -> (isize, isize) { - let mut longest = -1; - let mut longest_length = -1; - let mut start = -1; - macro_rules! finish_sequence( - ($end: expr) => { - if start >= 0 { - let length = $end - start; - if length > longest_length { - longest = start; - longest_length = length; - } - } - }; - ); - for i in 0..8 { - if pieces[i as usize] == 0 { - if start < 0 { - start = i; - } + +pub fn main(){ + let pieces : [u8; 8]= [42; 8]; + let mut i = 0; + let len = pieces.len(); + while i < len { + let val = pieces[i]; + if val > 128 { + i += 2; } else { - finish_sequence!(i); - start = -1; + i += 1; } - } - finish_sequence!(8); - (longest, longest + longest_length) -} -pub fn main(){ - let pieces : [u16; 8]= [42; 8]; - longest_zero_sequence(&pieces); -} \ No newline at end of file + }} \ No newline at end of file From 4dfd963b262c9e65df2904b3f564f39f28d0613e Mon Sep 17 00:00:00 2001 From: Coursant <24210240198@m.fudan.edu.cn> Date: Tue, 27 Jan 2026 08:04:01 +0800 Subject: [PATCH 7/7] tmp --- .../range_analysis/domain/ConstraintGraph.rs | 120 ++++++++++++++---- .../core/range_analysis/domain/domain.rs | 18 +++ .../analysis/core/ssa_transform/Replacer.rs | 98 +++++++++----- rapx/tests/range/range_6/src/main.rs | 17 ++- 4 files changed, 192 insertions(+), 61 deletions(-) diff --git a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs index 1fae4ff6..77571c87 100644 --- a/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs +++ b/rapx/src/analysis/core/range_analysis/domain/ConstraintGraph.rs @@ -717,19 +717,87 @@ where // rap_trace!("value_branchmap{:?}\n", self.values_branchmap); // rap_trace!("varnodes{:?}\n,", self.vars); } + fn trace_operand_source( + &self, + body: &'tcx Body<'tcx>, + mut current_block: BasicBlock, + target_place: Place<'tcx>, + ) -> Option<&'tcx Operand<'tcx>> { + let mut visited = HashSet::new(); + let target_local = target_place.local; + + while visited.insert(current_block) { + let data = &body.basic_blocks[current_block]; + + // 逆序扫描当前块 + for stmt in data.statements.iter().rev() { + if let StatementKind::Assign(box (lhs, rvalue)) = &stmt.kind { + // 只要找到了对目标变量的赋值语句 + if lhs.local == target_local { + rap_debug!( + "Tracing source for {:?} in block {:?} {:?}\n", + target_place, + current_block, + rvalue + ); + return match rvalue { + // 如果右值是 Operand (例如 _2 = _1 或 _2 = const 5) + // 直接返回这个 Operand 的引用,不再往上追 _1 的来源 + Rvalue::Use(op) => Some(op), + + // 如果右值是计算结果 (例如 _2 = Add(_3, _4)) + // 说明 _2 的来源就在这里,但它不是一个独立的 Operand 对象,返回 None + _ => None, + }; + } + } + } + // 当前块没找到,尝试回溯唯一的前驱块 + let preds = &body.basic_blocks.predecessors()[current_block]; + if preds.len() == 1 { + current_block = preds[0]; + } else { + break; + } + } + + None + } pub fn build_value_branch_map( &mut self, - body: &Body<'tcx>, + body: &'tcx Body<'tcx>, discr: &'tcx Operand<'tcx>, targets: &'tcx SwitchTargets, - block: BasicBlock, + switch_block: BasicBlock, block_data: &'tcx BasicBlockData<'tcx>, ) { // let place1: &Place<'tcx>; + let first_target = targets.all_targets()[0]; + let target_data = &body.basic_blocks[first_target]; + if let Operand::Copy(place) | Operand::Move(place) = discr { if let Some((op1, op2, cmp_op)) = self.extract_condition(place, block_data) { - rap_trace!( + rap_debug!( + "extract_condition op1:{:?} op2:{:?} cmp_op:{:?}\n", + op1, + op2, + cmp_op + ); + let op1 = if let Some(p1) = op1.place() { + self.trace_operand_source(body, switch_block, p1) + .unwrap_or(op1) + } else { + op1 + }; + + let op2 = if let Some(p2) = op2.place() { + self.trace_operand_source(body, switch_block, p2) + .unwrap_or(op2) + } else { + op2 + }; + rap_debug!( "build_value_branch_map op1:{:?} op2:{:?} cmp_op:{:?}\n", op1, op2, @@ -825,7 +893,7 @@ where ValueBranchMap::new(p2, &target_vec[0], &target_vec[1], SFOp2, STOp2); self.values_branchmap.insert(&p1, vbm_1); self.values_branchmap.insert(&p2, vbm_2); - self.switchbbs.insert(block, (*p1, *p2)); + self.switchbbs.insert(switch_block, (*p1, *p2)); } } }; @@ -881,28 +949,28 @@ where if lhs == place { let mut return_op1: &Operand<'tcx> = &op1; let mut return_op2: &Operand<'tcx> = &op2; - for stmt_original in &switch_block.statements { - if op1.constant().is_none() { - if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) = - &stmt_original.kind - { - if lhs.clone() == op1.place().unwrap() { - return_op1 = OP1; - } - } - } - } - if op2.constant().is_none() { - for stmt_original in &switch_block.statements { - if let StatementKind::Assign(box (lhs, Rvalue::Use(OP2))) = - &stmt_original.kind - { - if lhs.clone() == op2.place().unwrap() { - return_op2 = OP2; - } - } - } - } + // for stmt_original in &switch_block.statements { + // if op1.constant().is_none() { + // if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) = + // &stmt_original.kind + // { + // if lhs.clone() == op1.place().unwrap() { + // return_op1 = OP1; + // } + // } + // } + // } + // if op2.constant().is_none() { + // for stmt_original in &switch_block.statements { + // if let StatementKind::Assign(box (lhs, Rvalue::Use(OP2))) = + // &stmt_original.kind + // { + // if lhs.clone() == op2.place().unwrap() { + // return_op2 = OP2; + // } + // } + // } + // } return Some((return_op1, return_op2, *bin_op)); } diff --git a/rapx/src/analysis/core/range_analysis/domain/domain.rs b/rapx/src/analysis/core/range_analysis/domain/domain.rs index 62584b58..b370ba9b 100644 --- a/rapx/src/analysis/core/range_analysis/domain/domain.rs +++ b/rapx/src/analysis/core/range_analysis/domain/domain.rs @@ -451,6 +451,24 @@ impl<'tcx, T: IntervalArithmetic + ConstConvert + Debug> CallOp<'tcx, T> { ); return result; } + "std::ops::Index::index" => { + let mut result = Range::default(T::min_value()); + + match self.args.last() { + Some(Operand::Copy(place)) | Some(Operand::Move(place)) => { + result = caller_vars[place].get_range().clone(); + } + Some(Operand::Constant(c)) => {} + None => {} + } + + rap_trace!( + "Index detected on place {:?}, returning its range: {:?}", + self.sink, + result + ); + return result; + } "core::panicking::panic" | "std::panicking::panic" => { rap_trace!("Panic call detected, returning bottom range."); return Range::new(T::max_value(), T::min_value(), RangeType::Empty); diff --git a/rapx/src/analysis/core/ssa_transform/Replacer.rs b/rapx/src/analysis/core/ssa_transform/Replacer.rs index a6746313..4c60bf06 100644 --- a/rapx/src/analysis/core/ssa_transform/Replacer.rs +++ b/rapx/src/analysis/core/ssa_transform/Replacer.rs @@ -38,21 +38,32 @@ impl<'tcx> Replacer<'tcx> { if let Some(def_blocks) = self.ssatransformer.local_assign_blocks.get(var) { let mut worklist: VecDeque = def_blocks.iter().cloned().collect(); let mut processed: HashSet = HashSet::new(); - while let Some(block) = worklist.pop_front() { if let Some(df_blocks) = self.ssatransformer.df.get(&block) { for &df_block in df_blocks { if !processed.contains(&df_block) { phi_functions.get_mut(&df_block).unwrap().insert(*var); processed.insert(df_block); - if self.ssatransformer.local_assign_blocks[var].contains(&df_block) - { - worklist.push_back(df_block); - } + + worklist.push_back(df_block); } } } } + // while let Some(block) = worklist.pop_front() { + // if let Some(df_blocks) = self.ssatransformer.df.get(&block) { + // for &df_block in df_blocks { + // if !processed.contains(&df_block) { + // phi_functions.get_mut(&df_block).unwrap().insert(*var); + // processed.insert(df_block); + // if self.ssatransformer.local_assign_blocks[var].contains(&df_block) + // { + // worklist.push_back(df_block); + // } + // } + // } + // } + // } } } @@ -123,6 +134,7 @@ impl<'tcx> Replacer<'tcx> { } } } + fn extract_condition( &self, place: &Place<'tcx>, @@ -133,30 +145,9 @@ impl<'tcx> Replacer<'tcx> { &stmt.kind { if lhs == place { - let mut return_op1: &Operand<'tcx> = &op1; - let mut return_op2: &Operand<'tcx> = &op2; - if op1.constant().is_none() { - for stmt_original in &switch_block.statements { - if let StatementKind::Assign(box (lhs, Rvalue::Use(OP1))) = - &stmt_original.kind - { - if lhs.clone() == op1.place().unwrap() { - return_op1 = OP1; - } - } - } - } - if op2.constant().is_none() { - for stmt_original in &switch_block.statements { - if let StatementKind::Assign(box (lhs, Rvalue::Use(OP2))) = - &stmt_original.kind - { - if lhs.clone() == op2.place().unwrap() { - return_op2 = OP2; - } - } - } - } + let return_op1: &Operand<'tcx> = &op1; + let return_op2: &Operand<'tcx> = &op2; + return Some((return_op1.clone(), return_op2.clone(), *bin_op)); } } @@ -182,7 +173,38 @@ impl<'tcx> Replacer<'tcx> { _ => 7, } } + fn trace_operand_source( + &self, + body: &Body<'tcx>, + mut current_block: BasicBlock, + target_place: Place<'tcx>, + ) -> Operand<'tcx> { + let mut visited = HashSet::new(); + let current_place = target_place; + + while visited.insert(current_block) { + let data = &body.basic_blocks[current_block]; + for stmt in data.statements.iter().rev() { + if let StatementKind::Assign(box (lhs, rvalue)) = &stmt.kind { + if *lhs == current_place { + match rvalue { + Rvalue::Use(op) => return op.clone(), + _ => return Operand::Copy(current_place), + } + } + } + } + + let preds = &body.basic_blocks.predecessors()[current_block]; + if preds.len() == 1 { + current_block = preds[0]; + } else { + break; + } + } + Operand::Copy(current_place) + } // This function inserts eSSA (extended SSA) assignment statements into the basic block. // These statements capture control flow information by asserting conditions on variables // based on the outcome of a switch (branching) instruction. @@ -204,6 +226,24 @@ impl<'tcx> Replacer<'tcx> { if let Some((op1, op2, cmp_op)) = self.extract_condition(switch_place, switch_block_data) { + let op1 = if let Some(p1) = op1.place() { + self.trace_operand_source(body, *switch_block, p1) + } else { + op1 + }; + + let op2 = if let Some(p2) = op2.place() { + self.trace_operand_source(body, *switch_block, p2) + } else { + op2 + }; + rap_debug!( + "essa trace_operand_source op1:{:?} op2:{:?} cmp_op:{:?} value:{:?}\n", + op1, + op2, + cmp_op, + value + ); let block_data: &mut BasicBlockData<'tcx> = &mut body.basic_blocks.as_mut()[*bb]; let const_op1: Option<&ConstOperand<'_>> = op1.constant(); diff --git a/rapx/tests/range/range_6/src/main.rs b/rapx/tests/range/range_6/src/main.rs index 0d95d977..116c459c 100644 --- a/rapx/tests/range/range_6/src/main.rs +++ b/rapx/tests/range/range_6/src/main.rs @@ -1,13 +1,18 @@ pub fn main(){ - let pieces : [u8; 8]= [42; 8]; + let pieces = [42; 8]; let mut i = 0; - let len = pieces.len(); - while i < len { - let val = pieces[i]; + let slice_index = 8; + + let slice = & pieces[1..slice_index]; + let len = slice.len(); + + while i < 2*len { + let mut val = slice[i]; if val > 128 { - i += 2; + val+=1; + // i *= 2; } else { - i += 1; + i *= 21; } }} \ No newline at end of file