Skip to content

Commit 57cb6d9

Browse files
committed
Fall back to the unoptimized implementation in read_binary_file if File::metadata lies
1 parent bf1e3f3 commit 57cb6d9

File tree

1 file changed

+23
-1
lines changed

1 file changed

+23
-1
lines changed

compiler/rustc_span/src/source_map.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,29 @@ impl FileLoader for RealFileLoader {
133133
file.read_buf_exact(buf.unfilled())?;
134134
// SAFETY: If the read_buf_exact call returns Ok(()), then we have
135135
// read len bytes and initialized the buffer.
136-
Ok(unsafe { bytes.assume_init() })
136+
let bytes = unsafe { bytes.assume_init() };
137+
138+
// At this point, we've read all the bytes that filesystem metadata reported exist.
139+
// But we are not guaranteed to be at the end of the file, because we did not attempt to do
140+
// a read with a non-zero-sized buffer and get Ok(0).
141+
// So we do small read to a fixed-size buffer. If the read returns no bytes then we're
142+
// already done, and we just return the Lrc we built above.
143+
// If the read returns bytes however, we just fall back to reading into a Vec then turning
144+
// that into an Lrc, losing our nice peak memory behavior. This fallback code path should
145+
// be rarely exercised.
146+
147+
let mut probe = [0u8; 32];
148+
let n = loop {
149+
match file.read(&mut probe) {
150+
Ok(0) => return Ok(bytes),
151+
Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
152+
Err(e) => return Err(e),
153+
Ok(n) => break n,
154+
}
155+
};
156+
let mut bytes: Vec<u8> = bytes.iter().copied().chain(probe[..n].iter().copied()).collect();
157+
file.read_to_end(&mut bytes)?;
158+
Ok(bytes.into())
137159
}
138160
}
139161

0 commit comments

Comments
 (0)