From f543689eb65aeacb6ec85c07f0c82800174d21c1 Mon Sep 17 00:00:00 2001 From: Russell Cohen Date: Thu, 2 Apr 2020 00:08:58 -0400 Subject: [PATCH] Handle unterminated raw strings with no #s properly The modified code to handle parsing raw strings didn't properly account for the case where there was no "#" on either end and erroneously reported this strings as complete. This lead to a panic trying to read off the end of the file. --- src/librustc_lexer/src/lib.rs | 9 ++++++- src/librustc_lexer/src/tests.rs | 27 +++++++++++++++++++ ...77-panic-on-unterminated-raw-str-at-eof.rs | 5 ++++ ...anic-on-unterminated-raw-str-at-eof.stderr | 9 +++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs create mode 100644 src/test/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.stderr diff --git a/src/librustc_lexer/src/lib.rs b/src/librustc_lexer/src/lib.rs index fcb7475cc2e89..5ccfc1b276bfa 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/src/librustc_lexer/src/lib.rs @@ -148,6 +148,10 @@ pub enum LiteralKind { pub struct UnvalidatedRawStr { /// The prefix (`r###"`) is valid valid_start: bool, + + /// The postfix (`"###`) is valid + valid_end: bool, + /// The number of leading `#` n_start_hashes: usize, /// The number of trailing `#`. `n_end_hashes` <= `n_start_hashes` @@ -197,7 +201,7 @@ impl UnvalidatedRawStr { let n_start_safe: u16 = self.n_start_hashes.try_into().map_err(|_| LexRawStrError::TooManyDelimiters)?; - if self.n_start_hashes > self.n_end_hashes { + if self.n_start_hashes > self.n_end_hashes || !self.valid_end { Err(LexRawStrError::NoTerminator { expected: self.n_start_hashes, found: self.n_end_hashes, @@ -687,6 +691,7 @@ impl Cursor<'_> { _ => { return UnvalidatedRawStr { valid_start, + valid_end: false, n_start_hashes, n_end_hashes: 0, possible_terminator_offset, @@ -702,6 +707,7 @@ impl Cursor<'_> { if self.is_eof() { return UnvalidatedRawStr { valid_start, + valid_end: false, n_start_hashes, n_end_hashes: max_hashes, possible_terminator_offset, @@ -727,6 +733,7 @@ impl Cursor<'_> { if n_end_hashes == n_start_hashes { return UnvalidatedRawStr { valid_start, + valid_end: true, n_start_hashes, n_end_hashes, possible_terminator_offset: None, diff --git a/src/librustc_lexer/src/tests.rs b/src/librustc_lexer/src/tests.rs index 4af435536f011..06fc159fe2516 100644 --- a/src/librustc_lexer/src/tests.rs +++ b/src/librustc_lexer/src/tests.rs @@ -23,6 +23,7 @@ mod tests { n_start_hashes: 0, n_end_hashes: 0, valid_start: true, + valid_end: true, possible_terminator_offset: None, }, Ok(ValidatedRawStr { n_hashes: 0 }), @@ -37,6 +38,7 @@ mod tests { n_start_hashes: 0, n_end_hashes: 0, valid_start: true, + valid_end: true, possible_terminator_offset: None, }, Ok(ValidatedRawStr { n_hashes: 0 }), @@ -51,6 +53,7 @@ mod tests { UnvalidatedRawStr { n_start_hashes: 1, n_end_hashes: 1, + valid_end: true, valid_start: true, possible_terminator_offset: None, }, @@ -65,6 +68,7 @@ mod tests { UnvalidatedRawStr { n_start_hashes: 1, n_end_hashes: 0, + valid_end: false, valid_start: true, possible_terminator_offset: None, }, @@ -80,6 +84,7 @@ mod tests { n_start_hashes: 2, n_end_hashes: 1, valid_start: true, + valid_end: false, possible_terminator_offset: Some(7), }, Err(LexRawStrError::NoTerminator { @@ -95,6 +100,7 @@ mod tests { n_start_hashes: 2, n_end_hashes: 0, valid_start: true, + valid_end: false, possible_terminator_offset: None, }, Err(LexRawStrError::NoTerminator { @@ -113,9 +119,30 @@ mod tests { n_start_hashes: 1, n_end_hashes: 0, valid_start: false, + valid_end: false, possible_terminator_offset: None, }, Err(LexRawStrError::InvalidStarter), ); } + + #[test] + fn test_unterminated_no_pound() { + // https://github.com/rust-lang/rust/issues/70677 + check_raw_str( + r#"""#, + UnvalidatedRawStr { + n_start_hashes: 0, + n_end_hashes: 0, + valid_start: true, + valid_end: false, + possible_terminator_offset: None, + }, + Err(LexRawStrError::NoTerminator { + expected: 0, + found: 0, + possible_terminator_offset: None, + }), + ); + } } diff --git a/src/test/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs b/src/test/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs new file mode 100644 index 0000000000000..bdfc29a3d57ab --- /dev/null +++ b/src/test/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs @@ -0,0 +1,5 @@ +// This won't actually panic because of the error comment -- the `"` needs to be +// the last byte in the file (including not having a trailing newline) +// Prior to the fix you get the error: 'expected item, found `r" ...`' +// because the string being unterminated wasn't properly detected. +r" //~ unterminated raw string diff --git a/src/test/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.stderr b/src/test/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.stderr new file mode 100644 index 0000000000000..3a7e2a4b14afb --- /dev/null +++ b/src/test/ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.stderr @@ -0,0 +1,9 @@ +error[E0748]: unterminated raw string + --> $DIR/issue-70677-panic-on-unterminated-raw-str-at-eof.rs:5:1 + | +LL | r" + | ^ unterminated raw string + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0748`.