Guard against overflow in codemap::span_to_lines
.
Make `span_to_lines` to return a `Result`. (This is better than just asserting internally, since it allows caller to decide if they can recover from the problem.) Added type alias for `FileLinesResult` returned by `span_to_lines`. Update embedded unit test to reflect `span_to_lines` signature change. In diagnostic, catch `Err` from `span_to_lines` and print `"(internal compiler error: unprintable span)"` instead. ---- There a number of recent issues that report the bug here. See e.g. #24761 and #24954. This change *might* fix them. However, that is not its main goal. The main goals are: 1. Make it possible for callers to recover from an error here, and 2. Insert a more conservative check, in that we are also checking that the files match up.
This commit is contained in:
parent
42cb2de139
commit
939e4c9ea9
2 changed files with 45 additions and 8 deletions
|
@ -667,9 +667,22 @@ impl CodeMap {
|
||||||
self.lookup_char_pos(sp.lo).file.name.to_string()
|
self.lookup_char_pos(sp.lo).file.name.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn span_to_lines(&self, sp: Span) -> FileLines {
|
pub fn span_to_lines(&self, sp: Span) -> FileLinesResult {
|
||||||
|
if sp.lo > sp.hi {
|
||||||
|
return Err(SpanLinesError::IllFormedSpan(sp));
|
||||||
|
}
|
||||||
|
|
||||||
let lo = self.lookup_char_pos(sp.lo);
|
let lo = self.lookup_char_pos(sp.lo);
|
||||||
let hi = self.lookup_char_pos(sp.hi);
|
let hi = self.lookup_char_pos(sp.hi);
|
||||||
|
|
||||||
|
if lo.file.start_pos != hi.file.start_pos {
|
||||||
|
return Err(SpanLinesError::DistinctSources(DistinctSources {
|
||||||
|
begin: (lo.file.name.clone(), lo.file.start_pos),
|
||||||
|
end: (hi.file.name.clone(), hi.file.start_pos),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
assert!(hi.line >= lo.line);
|
||||||
|
|
||||||
let mut lines = Vec::with_capacity(hi.line - lo.line + 1);
|
let mut lines = Vec::with_capacity(hi.line - lo.line + 1);
|
||||||
|
|
||||||
// The span starts partway through the first line,
|
// The span starts partway through the first line,
|
||||||
|
@ -693,7 +706,7 @@ impl CodeMap {
|
||||||
start_col: start_col,
|
start_col: start_col,
|
||||||
end_col: hi.col });
|
end_col: hi.col });
|
||||||
|
|
||||||
FileLines {file: lo.file, lines: lines}
|
Ok(FileLines {file: lo.file, lines: lines})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
|
pub fn span_to_snippet(&self, sp: Span) -> Result<String, SpanSnippetError> {
|
||||||
|
@ -918,9 +931,17 @@ impl CodeMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
// _____________________________________________________________________________
|
// _____________________________________________________________________________
|
||||||
// SpanSnippetError, DistinctSources, MalformedCodemapPositions
|
// SpanLinesError, SpanSnippetError, DistinctSources, MalformedCodemapPositions
|
||||||
//
|
//
|
||||||
|
|
||||||
|
pub type FileLinesResult = Result<FileLines, SpanLinesError>;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub enum SpanLinesError {
|
||||||
|
IllFormedSpan(Span),
|
||||||
|
DistinctSources(DistinctSources),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
pub enum SpanSnippetError {
|
pub enum SpanSnippetError {
|
||||||
IllFormedSpan(Span),
|
IllFormedSpan(Span),
|
||||||
|
@ -1086,7 +1107,7 @@ mod tests {
|
||||||
// Test span_to_lines for a span ending at the end of filemap
|
// Test span_to_lines for a span ending at the end of filemap
|
||||||
let cm = init_code_map();
|
let cm = init_code_map();
|
||||||
let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
|
let span = Span {lo: BytePos(12), hi: BytePos(23), expn_id: NO_EXPANSION};
|
||||||
let file_lines = cm.span_to_lines(span);
|
let file_lines = cm.span_to_lines(span).unwrap();
|
||||||
|
|
||||||
assert_eq!(file_lines.file.name, "blork.rs");
|
assert_eq!(file_lines.file.name, "blork.rs");
|
||||||
assert_eq!(file_lines.lines.len(), 1);
|
assert_eq!(file_lines.lines.len(), 1);
|
||||||
|
@ -1131,7 +1152,7 @@ mod tests {
|
||||||
assert_eq!(&cm.span_to_snippet(span).unwrap(), "BB\nCCC\nDDDDD");
|
assert_eq!(&cm.span_to_snippet(span).unwrap(), "BB\nCCC\nDDDDD");
|
||||||
|
|
||||||
// check that span_to_lines gives us the complete result with the lines/cols we expected
|
// check that span_to_lines gives us the complete result with the lines/cols we expected
|
||||||
let lines = cm.span_to_lines(span);
|
let lines = cm.span_to_lines(span).unwrap();
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) },
|
LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) },
|
||||||
LineInfo { line_index: 2, start_col: CharPos(0), end_col: CharPos(3) },
|
LineInfo { line_index: 2, start_col: CharPos(0), end_col: CharPos(3) },
|
||||||
|
|
|
@ -522,7 +522,7 @@ fn highlight_suggestion(err: &mut EmitterWriter,
|
||||||
suggestion: &str)
|
suggestion: &str)
|
||||||
-> io::Result<()>
|
-> io::Result<()>
|
||||||
{
|
{
|
||||||
let lines = cm.span_to_lines(sp);
|
let lines = cm.span_to_lines(sp).unwrap();
|
||||||
assert!(!lines.lines.is_empty());
|
assert!(!lines.lines.is_empty());
|
||||||
|
|
||||||
// To build up the result, we want to take the snippet from the first
|
// To build up the result, we want to take the snippet from the first
|
||||||
|
@ -567,9 +567,17 @@ fn highlight_lines(err: &mut EmitterWriter,
|
||||||
cm: &codemap::CodeMap,
|
cm: &codemap::CodeMap,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
lines: codemap::FileLines)
|
lines: codemap::FileLinesResult)
|
||||||
-> io::Result<()>
|
-> io::Result<()>
|
||||||
{
|
{
|
||||||
|
let lines = match lines {
|
||||||
|
Ok(lines) => lines,
|
||||||
|
Err(_) => {
|
||||||
|
try!(write!(&mut err.dst, "(internal compiler error: unprintable span)\n"));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let fm = &*lines.file;
|
let fm = &*lines.file;
|
||||||
|
|
||||||
let line_strings: Option<Vec<&str>> =
|
let line_strings: Option<Vec<&str>> =
|
||||||
|
@ -690,8 +698,16 @@ fn end_highlight_lines(w: &mut EmitterWriter,
|
||||||
cm: &codemap::CodeMap,
|
cm: &codemap::CodeMap,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
lvl: Level,
|
lvl: Level,
|
||||||
lines: codemap::FileLines)
|
lines: codemap::FileLinesResult)
|
||||||
-> io::Result<()> {
|
-> io::Result<()> {
|
||||||
|
let lines = match lines {
|
||||||
|
Ok(lines) => lines,
|
||||||
|
Err(_) => {
|
||||||
|
try!(write!(&mut w.dst, "(internal compiler error: unprintable span)\n"));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let fm = &*lines.file;
|
let fm = &*lines.file;
|
||||||
|
|
||||||
let lines = &lines.lines[..];
|
let lines = &lines.lines[..];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue