Skip to content

Commit bb565b7

Browse files
committed
Skip line if rewrite rules cleared all frames
1 parent ad156c8 commit bb565b7

1 file changed

Lines changed: 93 additions & 0 deletions

File tree

src/mapper.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,19 @@ impl<'s> ProguardMapper<'s> {
620620
self.prepare_frame_for_mapping(&frame, &mut carried_outline_pos);
621621

622622
let mut collected = self.collect_remapped_frames(&effective_frame);
623+
let had_frames = !collected.frames.is_empty();
623624
if next_frame_can_rewrite {
624625
apply_rewrite_rules(&mut collected, current_exception_descriptor.as_deref());
625626
}
626627

627628
next_frame_can_rewrite = false;
628629
current_exception_descriptor = None;
629630

631+
// If rewrite rules cleared all frames, skip entirely
632+
if had_frames && collected.frames.is_empty() {
633+
continue;
634+
}
635+
630636
format_frames(&mut stacktrace, line, collected.frames.into_iter())?;
631637
continue;
632638
}
@@ -678,11 +684,17 @@ impl<'s> ProguardMapper<'s> {
678684

679685
let effective = self.prepare_frame_for_mapping(f, &mut carried_outline_pos);
680686
let mut collected = self.collect_remapped_frames(&effective);
687+
let had_frames = !collected.frames.is_empty();
681688
if next_frame_can_rewrite {
682689
apply_rewrite_rules(&mut collected, exception_descriptor.as_deref());
683690
}
684691
next_frame_can_rewrite = false;
685692

693+
// If rewrite rules cleared all frames, skip entirely
694+
if had_frames && collected.frames.is_empty() {
695+
continue;
696+
}
697+
686698
if collected.frames.is_empty() {
687699
frames_out.push(f.clone());
688700
} else {
@@ -977,4 +989,85 @@ java.lang.RuntimeException: boom
977989

978990
assert_eq!(mapper.remap_stacktrace(input).unwrap(), expected);
979991
}
992+
993+
#[test]
994+
fn rewrite_frame_removes_all_frames_skips_line() {
995+
// When rewrite rules remove ALL frames, the line should be skipped entirely
996+
// (not fall back to original obfuscated frame)
997+
let mapping = "\
998+
some.Class -> a:
999+
4:4:void inlined():10:10 -> call
1000+
4:4:void outer():20 -> call
1001+
# {\"id\":\"com.android.tools.r8.rewriteFrame\",\"conditions\":[\"throws(Ljava/lang/NullPointerException;)\"],\"actions\":[\"removeInnerFrames(2)\"]}
1002+
some.Other -> b:
1003+
5:5:void method():30 -> run
1004+
";
1005+
let mapper = ProguardMapper::from(mapping);
1006+
1007+
let input = "\
1008+
java.lang.NullPointerException: Boom
1009+
at a.call(SourceFile:4)
1010+
at b.run(SourceFile:5)
1011+
";
1012+
1013+
// The first frame (a.call) should be completely removed by rewrite rules,
1014+
// not replaced with the original "at a.call(SourceFile:4)"
1015+
let expected = "\
1016+
java.lang.NullPointerException: Boom
1017+
at some.Other.method(SourceFile:30)
1018+
";
1019+
1020+
let actual = mapper.remap_stacktrace(input).unwrap();
1021+
assert_eq!(actual, expected);
1022+
}
1023+
1024+
#[test]
1025+
fn rewrite_frame_removes_all_frames_skips_line_typed() {
1026+
// When rewrite rules remove ALL frames, the frame should be skipped entirely
1027+
// (not fall back to original obfuscated frame)
1028+
let mapping = "\
1029+
some.Class -> a:
1030+
4:4:void inlined():10:10 -> call
1031+
4:4:void outer():20 -> call
1032+
# {\"id\":\"com.android.tools.r8.rewriteFrame\",\"conditions\":[\"throws(Ljava/lang/NullPointerException;)\"],\"actions\":[\"removeInnerFrames(2)\"]}
1033+
some.Other -> b:
1034+
5:5:void method():30 -> run
1035+
";
1036+
let mapper = ProguardMapper::from(mapping);
1037+
1038+
let trace = StackTrace {
1039+
exception: Some(Throwable {
1040+
class: "java.lang.NullPointerException",
1041+
message: Some("Boom"),
1042+
}),
1043+
frames: vec![
1044+
StackFrame {
1045+
class: "a",
1046+
method: "call",
1047+
line: 4,
1048+
file: Some("SourceFile"),
1049+
parameters: None,
1050+
method_synthesized: false,
1051+
},
1052+
StackFrame {
1053+
class: "b",
1054+
method: "run",
1055+
line: 5,
1056+
file: Some("SourceFile"),
1057+
parameters: None,
1058+
method_synthesized: false,
1059+
},
1060+
],
1061+
cause: None,
1062+
};
1063+
1064+
let remapped = mapper.remap_stacktrace_typed(&trace);
1065+
1066+
// The first frame should be completely removed by rewrite rules,
1067+
// leaving only the second frame
1068+
assert_eq!(remapped.frames.len(), 1);
1069+
assert_eq!(remapped.frames[0].class, "some.Other");
1070+
assert_eq!(remapped.frames[0].method, "method");
1071+
assert_eq!(remapped.frames[0].line, 30);
1072+
}
9801073
}

0 commit comments

Comments
 (0)