From f34b99cb138cdba389e697cc5a4b0cd629ac6b2f Mon Sep 17 00:00:00 2001 From: Dhanush Varma Date: Sun, 5 Apr 2026 05:32:20 +0530 Subject: [PATCH 1/3] fix: move C0 bounds check before match, improve C1 warn message - C0 handler: bounds check was after the match, meaning process_p16(&block[1..]) could panic with an index out of bounds before the guard ran. Moved the check before the match to prevent this. - C1 handler: improved the warn message to include command code, name, and lengths for easier debugging. Fixes #1407 --- src/rust/src/decoder/service_decoder.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/rust/src/decoder/service_decoder.rs b/src/rust/src/decoder/service_decoder.rs index f57ab2c2b..6b9019b63 100644 --- a/src/rust/src/decoder/service_decoder.rs +++ b/src/rust/src/decoder/service_decoder.rs @@ -77,6 +77,15 @@ impl dtvcc_service_decoder { let code = block[0]; let C0Command { command, length } = C0Command::new(code); debug!("C0: [{:?}] ({})", command, block.len()); + if length as usize > block.len() { + warn!( + "dtvcc_handle_C0: command {:#04X} needs {} bytes but block only has {}; skipping", + code, + length, + block.len() + ); + return -1; + } match command { // NUL command does nothing C0CodeSet::NUL => {} @@ -90,14 +99,6 @@ impl dtvcc_service_decoder { C0CodeSet::P16 => self.process_p16(&block[1..]), C0CodeSet::RESERVED => {} } - if length as usize > block.len() { - warn!( - "dtvcc_handle_C0: command is {} bytes long but we only have {}", - length, - block.len() - ); - return -1; - } length as i32 } @@ -286,7 +287,13 @@ impl dtvcc_service_decoder { } = C1Command::new(code); if length as usize > block.len() { - warn!("Warning: Not enough bytes for command."); + warn!( + "dtvcc_handle_C1: command {:#04X} ({}) needs {} bytes but block only has {}; skipping", + code, + name, + length, + block.len() + ); return -1; } From c3f17df073b79bde2190d0077ec9e944f38056e9 Mon Sep 17 00:00:00 2001 From: Dhanush Varma Date: Sun, 5 Apr 2026 05:33:27 +0530 Subject: [PATCH 2/3] docs: update CHANGES.TXT for #1407 fix --- docs/CHANGES.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 4d114298f..611f48879 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 0.96.7 (unreleased) ------------------- +- Fix: Move C0 bounds check before match in CEA-708 Rust decoder to prevent process_p16 index-out-of-bounds panic on truncated ATSC1.0 TS blocks; improve C1 warn message with command code and lengths (#1407) - New: Allow output \0 terminated frames via --null-terminated - New: Added ASS/SSA \pos-based positioning for CEA-608 captions when layout is simple (1–2 rows) (#1726) - Fix: Remove strdup() memory leaks in WebVTT styling encoder, fix invalid CSS rgba(0,256,0) green value, fix missing free(unescaped) on write-error path (#2154) From 0ecbdd36612883ae6339608635da049b1d8f7458 Mon Sep 17 00:00:00 2001 From: Dhanush Varma Date: Mon, 6 Apr 2026 10:26:40 +0530 Subject: [PATCH 3/3] style: cargo fmt --- src/rust/lib_ccxr/src/teletext.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/rust/lib_ccxr/src/teletext.rs b/src/rust/lib_ccxr/src/teletext.rs index 906183bc8..b9802ea6b 100644 --- a/src/rust/lib_ccxr/src/teletext.rs +++ b/src/rust/lib_ccxr/src/teletext.rs @@ -1004,16 +1004,8 @@ impl<'a> TeletextContext<'a> { let mut line_count: u8 = 0; let mut time_reported = false; // Negative timestamps occur with wrap-around/uninitialized PTS in broadcast captures - let timecode_show = self - .page_buffer - .show_timestamp - .to_srt_time() - .ok()?; - let timecode_hide = self - .page_buffer - .hide_timestamp - .to_srt_time() - .ok()?; + let timecode_show = self.page_buffer.show_timestamp.to_srt_time().ok()?; + let timecode_hide = self.page_buffer.hide_timestamp.to_srt_time().ok()?; // process data for row in 1..25 {