diff --git a/rapx/src/analysis/core/range_analysis/default.rs b/rapx/src/analysis/core/range_analysis/default.rs index 4ee1de14..d06b925d 100644 --- a/rapx/src/analysis/core/range_analysis/default.rs +++ b/rapx/src/analysis/core/range_analysis/default.rs @@ -174,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> = @@ -200,8 +204,7 @@ where file.write_all(dot_output.as_bytes()) .expect("Could not write to file"); - println!("Successfully generated graph.dot"); - // println!("Run 'dot -Tpng -o graph.png graph.dot' to generate the image."); + rap_trace!("Successfully generated graph.dot"); } fn only_caller_range_analysis(&mut self) { @@ -216,6 +219,7 @@ where let def_id = local_def_id.to_def_id(); if self.tcx.is_mir_available(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 @@ -223,7 +227,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()); @@ -241,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 efe4195c..77571c87 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); @@ -715,18 +717,92 @@ 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_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, + cmp_op + ); let const_op1 = op1.constant(); let const_op2 = op2.constant(); match (const_op1, const_op2) { @@ -754,8 +830,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 = @@ -817,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)); } } }; @@ -873,26 +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 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)); } @@ -1286,7 +1364,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 +1443,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() { @@ -1548,7 +1625,6 @@ where self.defmap.insert(sink, bop_index); } - fn add_binary_op( &mut self, sink: &'tcx Place<'tcx>, @@ -1559,72 +1635,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/range_analysis/domain/domain.rs b/rapx/src/analysis/core/range_analysis/domain/domain.rs index 50172161..b370ba9b 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![], @@ -438,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/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 3b85b24e..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); + // } + // } + // } + // } + // } } } @@ -95,15 +106,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,17 +124,17 @@ impl<'tcx> Replacer<'tcx> { if let Some(terminator) = &switch_block_data.terminator { if let TerminatorKind::SwitchInt { discr, targets, .. } = &terminator.kind { - { - for (value, target) in targets.iter() { - self.essa_assign_statement(&target, &bb, value, discr, body); - } - let otherwise = targets.otherwise(); + 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); } } } } + fn extract_condition( &self, place: &Place<'tcx>, @@ -143,35 +145,69 @@ impl<'tcx> Replacer<'tcx> { &stmt.kind { 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 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)); } } } 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, + } + } + 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. fn essa_assign_statement( &mut self, bb: &BasicBlock, @@ -182,106 +218,55 @@ 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), - })); + 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 { + // 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) { + 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(); 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(), + // 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)))); - _ => 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(), - }; 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(), @@ -295,38 +280,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( @@ -337,52 +327,100 @@ 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); + rap_trace!( + "Inserted eSSA statement {:?} in block {:?}", + essa_in_body, + magic_number_operand + ); } } _ => 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; + + // 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()); + } - let place = match op1 { - Operand::Copy(p) | Operand::Move(p) => Place::from(p), - _ => panic!("Expected a place"), - }; - 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( + operand.push(magic_number_operand.clone()); + 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 _; + + rap_trace!( + "Inserted eSSA statement {:?} in block {:?}", + essa_in_body, + magic_number_operand + ); } (Some(_), Some(_)) => {} @@ -434,14 +472,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); @@ -453,74 +487,48 @@ 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.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); } } - pub fn process_essa_statments( + fn rename_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(); - } - } - _ => {} + // 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() { + // 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; + } + + // 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, + ); } } } @@ -529,54 +537,63 @@ 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)); 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 f251e60a..dbc42f18 100644 --- a/rapx/src/analysis/core/ssa_transform/SSATransformer.rs +++ b/rapx/src/analysis/core/ssa_transform/SSATransformer.rs @@ -27,9 +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_statements: HashMap<*const Statement<'tcx>, bool>, - pub essa_statements: HashMap<*const Statement<'tcx>, bool>, + pub phi_index: HashMap, 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 93a88f93..2706563a 100644 --- a/rapx/src/preprocess/ssa_preprocess.rs +++ b/rapx/src/preprocess/ssa_preprocess.rs @@ -32,6 +32,7 @@ pub(crate) fn create_ssa_struct(_krate: &mut Crate, build_std: bool) { ("op1", Symbol::intern("i128")), ("op2", Symbol::intern("i128")), ("cmp", Symbol::intern("i128")), + ("switch_bb", Symbol::intern("i128")), ], build_std, ); 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 81896811..a4e81a21 100644 --- a/rapx/tests/range/range_5/src/main.rs +++ b/rapx/tests/range/range_5/src/main.rs @@ -1,7 +1,50 @@ -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') +} +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, + 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 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..116c459c --- /dev/null +++ b/rapx/tests/range/range_6/src/main.rs @@ -0,0 +1,18 @@ + +pub fn main(){ + let pieces = [42; 8]; + let mut i = 0; + 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 { + val+=1; + // i *= 2; + } else { + i *= 21; + } + }} \ No newline at end of file diff --git a/rapx/tests/range/run_range_tests.sh b/rapx/tests/range/run_range_tests.sh new file mode 100755 index 00000000..b0f2250d --- /dev/null +++ b/rapx/tests/range/run_range_tests.sh @@ -0,0 +1,97 @@ +#!/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..." + ( + cd "$RAP_ROOT" || exit + ./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