From aee804cb2955e2caa11f60c3dc756bfaf62230c4 Mon Sep 17 00:00:00 2001 From: kirito Date: Thu, 26 Mar 2026 17:55:30 +0800 Subject: [PATCH] fix: guard against non-advancing parse loops in parse_array --- src/lib.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index efd563d..25b9010 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -523,6 +523,8 @@ impl JsonRepairParser { let mut needs_comma = false; loop { + let pos_before = self.pos; // Safety check for infinite loops + self.skip_whitespace(); self.skip_comments(); self.skip_whitespace(); @@ -561,6 +563,12 @@ impl JsonRepairParser { needs_comma = true; } } + + // Safety check: ensure we're making progress + if self.pos == pos_before && self.pos < self.input.len() { + // We're stuck - advance one character to avoid infinite loop + self.advance(); + } } self.pop_state(); @@ -810,6 +818,24 @@ mod tests { assert_eq!(result, r#"[1,2,3]"#); } + #[test] + fn test_array_with_colon_does_not_loop() { + let options = RepairOptions::default(); + + let result = repair_json(r#"{"filepath":"a","edits":[old_string":"x"#, &options).unwrap(); + let parsed: Value = serde_json::from_str(&result).unwrap(); + assert!(parsed.is_object()); + } + + #[test] + fn test_array_with_object_closer_does_not_loop() { + let options = RepairOptions::default(); + + let result = repair_json(r#"{"items":[}"#, &options).unwrap(); + let parsed: Value = serde_json::from_str(&result).unwrap(); + assert!(parsed.is_object()); + } + #[test] fn test_numbers() { let options = RepairOptions::default();