-
Notifications
You must be signed in to change notification settings - Fork 45
Description
First, thanks a ton for creating and maintaining this library (and apologies for the mouthful of a issue title).
I'm reporting this based on user behavior observed in zizmorcore/zizmor#1065 -- we use annotate-snippets
to render static analysis findings, and a user observed a crash on an input that appears to be well-formed and is only accessed via valid UTF-8 spans within the application code itself.
The conditions for the panic are pretty subtle:
- The snippet's source must contain multiple lines, but the final line shouldn't have a trailing linefeed;
- The snippet must have multiple annotations;
- The last character in the snippet should be multibyte (e.g. an emoji).
When put together, these conditions cause a panic when rendering multiple annotations that span to the end of the snippet's source. This panic doesn't happen when the snippet's source ends in a final linefeed.
Here's my attempt at a minified reproducer for the above, with the latest release of annotated-snippets
(0.11.5):
use annotate_snippets::{Level, Renderer, Snippet}; fn main() { let good = r#"foobar foobar 🚀 "#; let snippet = Snippet::source(good) .fold(true) .line_start(1) .origin("whatever") .annotation(Level::Warning.span(0..good.len()).label("blah")) .annotation(Level::Warning.span(0..good.len()).label("blah")); let message = Level::Warning.title("whatever").snippet(snippet); let renderer = Renderer::styled(); println!("{}", renderer.render(message)); let bad = r#"foobar foobar 🚀"#; let snippet = Snippet::source(bad) .fold(true) .line_start(1) .origin("whatever") .annotation(Level::Warning.span(0..bad.len()).label("blah")) .annotation(Level::Warning.span(0..bad.len()).label("blah")); let message = Level::Warning.title("whatever").snippet(snippet); let renderer = Renderer::styled(); println!("{}", renderer.render(message)); }
Observe that the only difference between good
and bad
is that good
has a trailing linefeed, while bad
does not. In both cases, the annotation spans are valid UTF-8 slices.
Here's what the panic looks like (after a successful render of good
first):
$ ./target/debug/repro
warning: whatever
--> whatever:1:1
|
1 | / foobar
2 | |
3 | | foobar 🚀
| | -
| |______________________|
| blah
| blah
|
thread 'main' panicked at /home/william/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/annotate-snippets-0.11.5/src/renderer/display_list.rs:1440:29:
byte index 22 is not a char boundary; it is inside '🚀' (bytes 19..23) of ` foobar 🚀`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Specifically, it looks like the panicking slice happens here:
annotate-snippets-rs/src/renderer/display_list.rs
Line 1440 in 72dd8c7
It looks like this file no longer exists on main
, so it's possible this bug has been addressed in a refactor that hasn't been put in a release yet. If so, I apologize for the noise!