From 6abab49029dacfaa616b726f49817213adc1065b Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 26 Mar 2016 00:13:54 +0200 Subject: [PATCH 1/2] syntax: Prevent bumping the parser EOF to stop infinite loops. --- src/libsyntax/parse/parser.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 82715f263c96d..c6a237d382790 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -254,6 +254,7 @@ pub struct Parser<'a> { /// the previous token or None (only stashed sometimes). pub last_token: Option>, last_token_interpolated: bool, + last_token_eof: bool, pub buffer: [TokenAndSpan; 4], pub buffer_start: isize, pub buffer_end: isize, @@ -366,6 +367,7 @@ impl<'a> Parser<'a> { last_span: span, last_token: None, last_token_interpolated: false, + last_token_eof: false, buffer: [ placeholder.clone(), placeholder.clone(), @@ -998,6 +1000,15 @@ impl<'a> Parser<'a> { /// Advance the parser by one token pub fn bump(&mut self) { + if self.last_token_eof { + // Bumping after EOF is a bad sign, usually an infinite loop. + self.bug("attempted to bump the parser past EOF (may be stuck in a loop)"); + } + + if self.token == token::Eof { + self.last_token_eof = true; + } + self.last_span = self.span; // Stash token for error recovery (sometimes; clone is not necessarily cheap). self.last_token = if self.token.is_ident() || From 221d0fbad0b201ef9264d3c9a30cd8c143ed51b2 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 26 Mar 2016 21:37:53 +0200 Subject: [PATCH 2/2] syntax: Stop the bump loop for trait items at } and EOF. --- src/libsyntax/parse/parser.rs | 26 ++++++++++++------- src/test/compile-fail/issue-10636-2.rs | 3 +-- .../compile-fail/token-error-correct-3.rs | 3 ++- src/test/parse-fail/issue-32446.rs | 16 ++++++++++++ src/test/parse-fail/pat-lt-bracket-6.rs | 2 +- src/test/parse-fail/pat-lt-bracket-7.rs | 2 +- 6 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 src/test/parse-fail/issue-32446.rs diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index c6a237d382790..b1af576c144b5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -957,7 +957,9 @@ impl<'a> Parser<'a> { { self.expect(bra)?; let result = self.parse_seq_to_before_end(ket, sep, f); - self.bump(); + if self.token == *ket { + self.bump(); + } Ok(result) } @@ -1292,15 +1294,21 @@ impl<'a> Parser<'a> { Ok(cua) => cua, Err(e) => { loop { - p.bump(); - if p.token == token::Semi { - p.bump(); - break; - } + match p.token { + token::Eof => break, + + token::CloseDelim(token::Brace) | + token::Semi => { + p.bump(); + break; + } + + token::OpenDelim(token::Brace) => { + p.parse_token_tree()?; + break; + } - if p.token == token::OpenDelim(token::DelimToken::Brace) { - p.parse_token_tree()?; - break; + _ => p.bump() } } diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/compile-fail/issue-10636-2.rs index eaccaf3cdbd27..747252d59241e 100644 --- a/src/test/compile-fail/issue-10636-2.rs +++ b/src/test/compile-fail/issue-10636-2.rs @@ -14,6 +14,5 @@ pub fn trace_option(option: Option) { option.map(|some| 42; //~ NOTE: unclosed delimiter //~^ ERROR: expected one of - //~^^ ERROR: mismatched types } //~ ERROR: incorrect close delimiter -//~^ ERROR: expected one of +//~^ ERROR: unexpected token diff --git a/src/test/compile-fail/token-error-correct-3.rs b/src/test/compile-fail/token-error-correct-3.rs index fe8c9f690139f..f42c8d09a9c09 100644 --- a/src/test/compile-fail/token-error-correct-3.rs +++ b/src/test/compile-fail/token-error-correct-3.rs @@ -21,8 +21,9 @@ pub mod raw { if !is_directory(path.as_ref()) { //~ ERROR: unresolved name `is_directory` callback(path.as_ref(); //~ NOTE: unclosed delimiter //~^ ERROR: expected one of - fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: expected one of + fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types } else { //~ ERROR: incorrect close delimiter: `}` + //~^ ERROR: expected one of Ok(false); } diff --git a/src/test/parse-fail/issue-32446.rs b/src/test/parse-fail/issue-32446.rs new file mode 100644 index 0000000000000..90b9a4aae8b5b --- /dev/null +++ b/src/test/parse-fail/issue-32446.rs @@ -0,0 +1,16 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z parse-only + +fn main() {} + +// This used to end up in an infite loop trying to bump past EOF. +trait T { ... } //~ ERROR diff --git a/src/test/parse-fail/pat-lt-bracket-6.rs b/src/test/parse-fail/pat-lt-bracket-6.rs index bc27aedb627ee..5ed8f6dee8cd8 100644 --- a/src/test/parse-fail/pat-lt-bracket-6.rs +++ b/src/test/parse-fail/pat-lt-bracket-6.rs @@ -10,5 +10,5 @@ fn main() { let Test(&desc[..]) = x; //~ error: expected one of `,` or `@`, found `[` - //~^ ERROR expected one of `:`, `;`, or `=`, found `..` + //~^ ERROR expected one of `:`, `;`, `=`, or `@`, found `[` } diff --git a/src/test/parse-fail/pat-lt-bracket-7.rs b/src/test/parse-fail/pat-lt-bracket-7.rs index 3e9478da44de5..00681e6149785 100644 --- a/src/test/parse-fail/pat-lt-bracket-7.rs +++ b/src/test/parse-fail/pat-lt-bracket-7.rs @@ -10,5 +10,5 @@ fn main() { for thing(x[]) in foo {} //~ error: expected one of `,` or `@`, found `[` - //~^ ERROR: expected `in`, found `]` + //~^ ERROR expected one of `@` or `in`, found `[` }