Skip to content

Commit

Permalink
Guard against overflow in codemap::span_to_lines.
Browse files Browse the repository at this point in the history
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
`"(unprintable span)"` instead.

----

There a number of recent issues that report the bug here.  See
e.g. rust-lang#24761 and rust-lang#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.
  • Loading branch information
pnkfelix committed Apr 30, 2015
1 parent 20a256a commit 1dff2c5
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 8 deletions.
31 changes: 26 additions & 5 deletions src/libsyntax/codemap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,9 +667,22 @@ impl CodeMap {
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 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);

// The span starts partway through the first line,
Expand All @@ -693,7 +706,7 @@ impl CodeMap {
start_col: start_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> {
Expand Down Expand Up @@ -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)]
pub enum SpanSnippetError {
IllFormedSpan(Span),
Expand Down Expand Up @@ -1086,7 +1107,7 @@ mod tests {
// Test span_to_lines for a span ending at the end of filemap
let cm = init_code_map();
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.lines.len(), 1);
Expand Down Expand Up @@ -1131,7 +1152,7 @@ mod tests {
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
let lines = cm.span_to_lines(span);
let lines = cm.span_to_lines(span).unwrap();
let expected = vec![
LineInfo { line_index: 1, start_col: CharPos(4), end_col: CharPos(6) },
LineInfo { line_index: 2, start_col: CharPos(0), end_col: CharPos(3) },
Expand Down
22 changes: 19 additions & 3 deletions src/libsyntax/diagnostic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ fn highlight_suggestion(err: &mut EmitterWriter,
suggestion: &str)
-> io::Result<()>
{
let lines = cm.span_to_lines(sp);
let lines = cm.span_to_lines(sp).unwrap();
assert!(!lines.lines.is_empty());

// To build up the result, we want to take the snippet from the first
Expand Down Expand Up @@ -567,9 +567,17 @@ fn highlight_lines(err: &mut EmitterWriter,
cm: &codemap::CodeMap,
sp: Span,
lvl: Level,
lines: codemap::FileLines)
lines: codemap::FileLinesResult)
-> io::Result<()>
{
let lines = match lines {
Ok(lines) => lines,
Err(_) => {
try!(write!(&mut err.dst, "(unprintable span)\n"));
return Ok(());
}
};

let fm = &*lines.file;

let line_strings: Option<Vec<&str>> =
Expand Down Expand Up @@ -690,8 +698,16 @@ fn end_highlight_lines(w: &mut EmitterWriter,
cm: &codemap::CodeMap,
sp: Span,
lvl: Level,
lines: codemap::FileLines)
lines: codemap::FileLinesResult)
-> io::Result<()> {
let lines = match lines {
Ok(lines) => lines,
Err(_) => {
try!(write!(&mut w.dst, "(unprintable span)\n"));
return Ok(());
}
};

let fm = &*lines.file;

let lines = &lines.lines[..];
Expand Down

0 comments on commit 1dff2c5

Please sign in to comment.