Skip to content

Commit 5d285dc

Browse files
authored
Rollup merge of #69266 - Zoxc:fix-source-map-race, r=wesleywiser
Fix race condition when allocating source files in SourceMap This makes allocating address space in the source map an atomic operation. `rustc` does not currently do this in parallel, so this bug can't trigger, but parsing files in parallel could trigger it, and that is something we want to do. Fixes #69261. r? @wesleywiser
2 parents d96951f + 437f56e commit 5d285dc

File tree

2 files changed

+47
-19
lines changed

2 files changed

+47
-19
lines changed

src/librustc_span/lib.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,7 @@ impl SourceFile {
10751075
unmapped_path: FileName,
10761076
mut src: String,
10771077
start_pos: BytePos,
1078-
) -> Result<SourceFile, OffsetOverflowError> {
1078+
) -> Self {
10791079
let normalized_pos = normalize_src(&mut src, start_pos);
10801080

10811081
let src_hash = {
@@ -1089,14 +1089,12 @@ impl SourceFile {
10891089
hasher.finish::<u128>()
10901090
};
10911091
let end_pos = start_pos.to_usize() + src.len();
1092-
if end_pos > u32::max_value() as usize {
1093-
return Err(OffsetOverflowError);
1094-
}
1092+
assert!(end_pos <= u32::max_value() as usize);
10951093

10961094
let (lines, multibyte_chars, non_narrow_chars) =
10971095
analyze_source_file::analyze_source_file(&src[..], start_pos);
10981096

1099-
Ok(SourceFile {
1097+
SourceFile {
11001098
name,
11011099
name_was_remapped,
11021100
unmapped_path: Some(unmapped_path),
@@ -1111,7 +1109,7 @@ impl SourceFile {
11111109
non_narrow_chars,
11121110
normalized_pos,
11131111
name_hash,
1114-
})
1112+
}
11151113
}
11161114

11171115
/// Returns the `BytePos` of the beginning of the current line.

src/librustc_span/source_map.rs

+43-13
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ pub use crate::*;
1212

1313
use rustc_data_structures::fx::FxHashMap;
1414
use rustc_data_structures::stable_hasher::StableHasher;
15-
use rustc_data_structures::sync::{Lock, LockGuard, Lrc, MappedLockGuard};
15+
use rustc_data_structures::sync::{AtomicU32, Lock, LockGuard, Lrc, MappedLockGuard};
1616
use std::cmp;
17+
use std::convert::TryFrom;
1718
use std::hash::Hash;
1819
use std::path::{Path, PathBuf};
20+
use std::sync::atomic::Ordering;
1921

2022
use log::debug;
2123
use std::env;
@@ -131,6 +133,9 @@ pub(super) struct SourceMapFiles {
131133
}
132134

133135
pub struct SourceMap {
136+
/// The address space below this value is currently used by the files in the source map.
137+
used_address_space: AtomicU32,
138+
134139
files: Lock<SourceMapFiles>,
135140
file_loader: Box<dyn FileLoader + Sync + Send>,
136141
// This is used to apply the file path remapping as specified via
@@ -140,14 +145,24 @@ pub struct SourceMap {
140145

141146
impl SourceMap {
142147
pub fn new(path_mapping: FilePathMapping) -> SourceMap {
143-
SourceMap { files: Default::default(), file_loader: Box::new(RealFileLoader), path_mapping }
148+
SourceMap {
149+
used_address_space: AtomicU32::new(0),
150+
files: Default::default(),
151+
file_loader: Box::new(RealFileLoader),
152+
path_mapping,
153+
}
144154
}
145155

146156
pub fn with_file_loader(
147157
file_loader: Box<dyn FileLoader + Sync + Send>,
148158
path_mapping: FilePathMapping,
149159
) -> SourceMap {
150-
SourceMap { files: Default::default(), file_loader, path_mapping }
160+
SourceMap {
161+
used_address_space: AtomicU32::new(0),
162+
files: Default::default(),
163+
file_loader,
164+
path_mapping,
165+
}
151166
}
152167

153168
pub fn path_mapping(&self) -> &FilePathMapping {
@@ -194,12 +209,25 @@ impl SourceMap {
194209
self.files.borrow().stable_id_to_source_file.get(&stable_id).map(|sf| sf.clone())
195210
}
196211

197-
fn next_start_pos(&self) -> usize {
198-
match self.files.borrow().source_files.last() {
199-
None => 0,
200-
// Add one so there is some space between files. This lets us distinguish
201-
// positions in the `SourceMap`, even in the presence of zero-length files.
202-
Some(last) => last.end_pos.to_usize() + 1,
212+
fn allocate_address_space(&self, size: usize) -> Result<usize, OffsetOverflowError> {
213+
let size = u32::try_from(size).map_err(|_| OffsetOverflowError)?;
214+
215+
loop {
216+
let current = self.used_address_space.load(Ordering::Relaxed);
217+
let next = current
218+
.checked_add(size)
219+
// Add one so there is some space between files. This lets us distinguish
220+
// positions in the `SourceMap`, even in the presence of zero-length files.
221+
.and_then(|next| next.checked_add(1))
222+
.ok_or(OffsetOverflowError)?;
223+
224+
if self
225+
.used_address_space
226+
.compare_exchange(current, next, Ordering::Relaxed, Ordering::Relaxed)
227+
.is_ok()
228+
{
229+
return Ok(usize::try_from(current).unwrap());
230+
}
203231
}
204232
}
205233

@@ -218,8 +246,6 @@ impl SourceMap {
218246
filename: FileName,
219247
src: String,
220248
) -> Result<Lrc<SourceFile>, OffsetOverflowError> {
221-
let start_pos = self.next_start_pos();
222-
223249
// The path is used to determine the directory for loading submodules and
224250
// include files, so it must be before remapping.
225251
// Note that filename may not be a valid path, eg it may be `<anon>` etc,
@@ -241,13 +267,15 @@ impl SourceMap {
241267
let lrc_sf = match self.source_file_by_stable_id(file_id) {
242268
Some(lrc_sf) => lrc_sf,
243269
None => {
270+
let start_pos = self.allocate_address_space(src.len())?;
271+
244272
let source_file = Lrc::new(SourceFile::new(
245273
filename,
246274
was_remapped,
247275
unmapped_path,
248276
src,
249277
Pos::from_usize(start_pos),
250-
)?);
278+
));
251279

252280
let mut files = self.files.borrow_mut();
253281

@@ -277,7 +305,9 @@ impl SourceMap {
277305
mut file_local_non_narrow_chars: Vec<NonNarrowChar>,
278306
mut file_local_normalized_pos: Vec<NormalizedPos>,
279307
) -> Lrc<SourceFile> {
280-
let start_pos = self.next_start_pos();
308+
let start_pos = self
309+
.allocate_address_space(source_len)
310+
.expect("not enough address space for imported source file");
281311

282312
let end_pos = Pos::from_usize(start_pos + source_len);
283313
let start_pos = Pos::from_usize(start_pos);

0 commit comments

Comments
 (0)