From 2ef8888285326bdb76457e698b3a3fae48dfd725 Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 2 Jun 2025 18:28:50 -0600 Subject: [PATCH 1/2] test: Add a test for out of bounds replacement --- tests/rustc_tests.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index bdffe38b..d5c24af2 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2889,3 +2889,79 @@ $DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for .anonymized_line_numbers(true); assert_data_eq!(renderer.render(input), expected); } + +#[test] +#[should_panic(expected = "range end index 47 out of range for slice of length 26")] +fn rustdoc_ui_diagnostic_width() { + // tests/rustdoc-ui/diagnostic-width.rs + + let source_0 = r#"//@ compile-flags: --diagnostic-width=10 +#![deny(rustdoc::bare_urls)] + +/// This is a long line that contains a http://link.com +pub struct Foo; //~^ ERROR +"#; + let source_1 = r#"/// This is a long line that contains a http://link.com +"#; + + let input = Level::ERROR + .header("this URL is not a hyperlink") + .group( + Group::new() + .element( + Snippet::source(source_0) + .origin("$DIR/diagnostic-width.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(111..126)), + ) + .element( + Level::NOTE + .title("bare URLs are not automatically turned into clickable links"), + ), + ) + .group( + Group::new() + .element(Level::NOTE.title("the lint level is defined here")) + .element( + Snippet::source(source_0) + .origin("$DIR/diagnostic-width.rs") + .fold(true) + .annotation(AnnotationKind::Primary.span(49..67)), + ), + ) + .group( + Group::new() + .element(Level::HELP.title("use an automatic link instead")) + .element( + Snippet::source(source_1) + .origin("$DIR/diagnostic-width.rs") + .line_start(4) + .fold(true) + .patch(Patch::new(40..40, "<")) + .patch(Patch::new(55..55, ">")), + ), + ); + + let expected = str![[r#" +error: this URL is not a hyperlink + --> $DIR/diagnostic-width.rs:4:41 + | +LL | ... a http://link.com + | ^^^^^^^^^^^^^^^ + | + = note: bare URLs are not automatically turned into clickable links +note: the lint level is defined here + --> $DIR/diagnostic-width.rs:2:9 + | +LL | ...ny(ru...are_urls)] + | ^^...^^^^^^^^ +help: use an automatic link instead + | +LL | /// This is a long line that contains a + | + + +"#]]; + let renderer = Renderer::plain() + .anonymized_line_numbers(true) + .term_width(10); + assert_data_eq!(renderer.render(input), expected); +} From 22e1e546822c640cf351a97d41a9733ab627499e Mon Sep 17 00:00:00 2001 From: Scott Schafer Date: Mon, 2 Jun 2025 18:28:50 -0600 Subject: [PATCH 2/2] fix: Don't attempt out of bounds buffer replacments --- src/renderer/styled_buffer.rs | 5 +++++ tests/rustc_tests.rs | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/renderer/styled_buffer.rs b/src/renderer/styled_buffer.rs index 925bb446..f72c58c6 100644 --- a/src/renderer/styled_buffer.rs +++ b/src/renderer/styled_buffer.rs @@ -103,6 +103,11 @@ impl StyledBuffer { if start == end { return; } + // If the replacement range would be out of bounds, do nothing, as we + // can't replace things that don't exist. + if start > self.lines[line].len() || end > self.lines[line].len() { + return; + } let _ = self.lines[line].drain(start..(end - string.chars().count())); for (i, c) in string.chars().enumerate() { self.lines[line][start + i] = StyledChar::new(c, ElementStyle::LineNumber); diff --git a/tests/rustc_tests.rs b/tests/rustc_tests.rs index d5c24af2..13306590 100644 --- a/tests/rustc_tests.rs +++ b/tests/rustc_tests.rs @@ -2891,7 +2891,6 @@ $DIR/short-error-format.rs:8:7: error[E0599]: no method named `salut` found for } #[test] -#[should_panic(expected = "range end index 47 out of range for slice of length 26")] fn rustdoc_ui_diagnostic_width() { // tests/rustdoc-ui/diagnostic-width.rs