Skip to content

Commit c0f4632

Browse files
committed
fix(value): retain omitted phi copy sources
1 parent b436b53 commit c0f4632

1 file changed

Lines changed: 90 additions & 21 deletions

File tree

  • dexdec/src/analysis/value_recovery

dexdec/src/analysis/value_recovery/flow.rs

Lines changed: 90 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,17 @@ impl SsaCopyFlow {
217217
value
218218
}
219219

220+
fn omitted_source(&self, mut value: SsaVar) -> SsaVar {
221+
let mut visited = BTreeSet::new();
222+
while self.omitted.contains(&value) && visited.insert(value) {
223+
let Some(source) = self.sources.get(&value).copied() else {
224+
break;
225+
};
226+
value = source;
227+
}
228+
value
229+
}
230+
220231
fn argument(&self, value: SsaVar) -> InsnArg {
221232
InsnArg::reg_ssa(
222233
value.reg_num,
@@ -431,9 +442,14 @@ impl<'ir> ValueFlowGraph<'ir> {
431442
};
432443
for input in &phi.inputs {
433444
self.retained_phi_inputs.insert(input.value);
445+
let source = self.copies.omitted_source(input.value);
446+
self.retained_phi_inputs.insert(source);
434447
if excluded.contains_key(&input.value) {
435448
pending.push(input.value);
436449
}
450+
if source != input.value && excluded.contains_key(&source) {
451+
pending.push(source);
452+
}
437453
}
438454
}
439455
self.phis.retain(|phi| !recovered.contains(&phi.result));
@@ -800,35 +816,52 @@ impl<'ir> ValueFlowGraph<'ir> {
800816
}
801817

802818
fn required_phi_inputs(&self) -> BTreeSet<SsaVar> {
803-
let phis = self
804-
.phis
805-
.iter()
806-
.map(|phi| (phi.result, phi))
807-
.collect::<BTreeMap<_, _>>();
808-
let mut pending = self
819+
let pending = self
809820
.phis
810821
.iter()
811822
.filter(|phi| self.has_reaching_use(phi.result))
812823
.map(|phi| phi.result)
813824
.collect::<Vec<_>>();
814-
let mut required = self.retained_phi_inputs.clone();
815-
let mut visited = BTreeSet::new();
816-
while let Some(result) = pending.pop() {
817-
if !visited.insert(result) {
818-
continue;
825+
required_phi_input_closure(
826+
&self.phis,
827+
&self.copies,
828+
pending,
829+
self.retained_phi_inputs.clone(),
830+
)
831+
}
832+
}
833+
834+
fn required_phi_input_closure(
835+
phis: &[PhiMerge],
836+
copies: &SsaCopyFlow,
837+
mut pending: Vec<SsaVar>,
838+
mut required: BTreeSet<SsaVar>,
839+
) -> BTreeSet<SsaVar> {
840+
let phis = phis
841+
.iter()
842+
.map(|phi| (phi.result, phi))
843+
.collect::<BTreeMap<_, _>>();
844+
let mut visited = BTreeSet::new();
845+
while let Some(result) = pending.pop() {
846+
if !visited.insert(result) {
847+
continue;
848+
}
849+
let Some(phi) = phis.get(&result) else {
850+
continue;
851+
};
852+
for input in &phi.inputs {
853+
required.insert(input.value);
854+
let source = copies.omitted_source(input.value);
855+
required.insert(source);
856+
if phis.contains_key(&input.value) {
857+
pending.push(input.value);
819858
}
820-
let Some(phi) = phis.get(&result) else {
821-
continue;
822-
};
823-
for input in &phi.inputs {
824-
required.insert(input.value);
825-
if phis.contains_key(&input.value) {
826-
pending.push(input.value);
827-
}
859+
if source != input.value && phis.contains_key(&source) {
860+
pending.push(source);
828861
}
829862
}
830-
required
831863
}
864+
required
832865
}
833866

834867
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -875,8 +908,10 @@ impl SemanticVisitor for ControlSymbolClosure {
875908
#[cfg(test)]
876909
mod tests {
877910
use super::*;
911+
use crate::ir::analysis::PhiInput;
878912
use crate::ir::{
879-
InsnNode, InsnType, InstructionId, RegionId, SemanticCatch, SemanticExpression,
913+
BlockId, EdgeKind, InsnNode, InsnType, InstructionId, RegionId, SemanticCatch,
914+
SemanticExpression,
880915
};
881916

882917
fn operation(
@@ -945,4 +980,38 @@ mod tests {
945980

946981
assert!(graph.is_bound(binding));
947982
}
983+
984+
#[test]
985+
fn required_phi_inputs_retain_transitive_copy_sources() {
986+
let headers = SsaVar::new(12, 1);
987+
let handler_copy = SsaVar::new(13, 3);
988+
let null = SsaVar::new(13, 0);
989+
let merged = SsaVar::new(13, 4);
990+
let phis = vec![PhiMerge {
991+
block: BlockId::new(113),
992+
instruction: InstructionId::new(200),
993+
result: merged,
994+
inputs: vec![
995+
PhiInput {
996+
predecessor: BlockId::new(108),
997+
edge_kind: EdgeKind::Normal,
998+
value: handler_copy,
999+
},
1000+
PhiInput {
1001+
predecessor: BlockId::new(110),
1002+
edge_kind: EdgeKind::Normal,
1003+
value: null,
1004+
},
1005+
],
1006+
}];
1007+
let mut copies = SsaCopyFlow::default();
1008+
copies.sources.insert(handler_copy, headers);
1009+
copies.omitted.insert(handler_copy);
1010+
1011+
let required = required_phi_input_closure(&phis, &copies, vec![merged], BTreeSet::new());
1012+
1013+
assert!(required.contains(&handler_copy));
1014+
assert!(required.contains(&headers));
1015+
assert!(required.contains(&null));
1016+
}
9481017
}

0 commit comments

Comments
 (0)