Skip to content

Commit 8beee3f

Browse files
committed
Forbid relative paths in rust-project.json
1 parent 60f4b3e commit 8beee3f

File tree

6 files changed

+63
-31
lines changed

6 files changed

+63
-31
lines changed

crates/paths/src/lib.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,8 @@ impl AbsPath {
166166
AbsPathBuf::try_from(self.0.to_path_buf()).unwrap()
167167
}
168168

169-
/// Equivalent of [`Path::canonicalize`] for `AbsPath`.
170-
pub fn canonicalize(&self) -> Result<AbsPathBuf, std::io::Error> {
171-
Ok(self.as_ref().canonicalize()?.try_into().unwrap())
169+
pub fn canonicalize(&self) -> ! {
170+
panic!("We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430")
172171
}
173172

174173
/// Equivalent of [`Path::strip_prefix`] for `AbsPath`.

crates/project-model/src/manifest_path.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,8 @@ impl ManifestPath {
3535
self.file.parent().unwrap()
3636
}
3737

38-
/// Equivalent of [`Path::canonicalize`] for `ManifestPath`.
39-
pub fn canonicalize(&self) -> Result<ManifestPath, std::io::Error> {
40-
Ok((&**self).canonicalize()?.try_into().unwrap())
38+
pub fn canonicalize(&self) -> ! {
39+
(&**self).canonicalize()
4140
}
4241
}
4342

crates/project-model/src/project_json.rs

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@
4949
//! user explores them belongs to that extension (it's totally valid to change
5050
//! rust-project.json over time via configuration request!)
5151
52-
use std::path::PathBuf;
53-
52+
use anyhow::Result;
5453
use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition};
5554
use la_arena::RawIdx;
5655
use paths::{AbsPath, AbsPathBuf};
5756
use rustc_hash::FxHashMap;
5857
use serde::{de, Deserialize};
58+
use std::path::PathBuf;
5959

6060
use crate::cfg_flag::CfgFlag;
6161

@@ -98,34 +98,62 @@ impl ProjectJson {
9898
/// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`)
9999
/// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
100100
/// configuration.
101-
pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
102-
ProjectJson {
103-
sysroot: data.sysroot.map(|it| base.join(it)),
104-
sysroot_src: data.sysroot_src.map(|it| base.join(it)),
101+
pub fn new(base: &AbsPath, data: ProjectJsonData) -> Result<ProjectJson> {
102+
let absolutize = |p| AbsPathBuf::try_from(p).map(|it| it.normalize());
103+
Ok(ProjectJson {
104+
sysroot: data
105+
.sysroot
106+
.map(absolutize)
107+
.transpose()
108+
.map_err(|path| {
109+
anyhow::format_err!(
110+
"sysroot path is required to be absolute: {}",
111+
path.display()
112+
)
113+
})?,
114+
sysroot_src: data
115+
.sysroot_src
116+
.map(absolutize)
117+
.transpose()
118+
.map_err(|path| {
119+
anyhow::format_err!(
120+
"sysroot-src path is required to be absolute: {}",
121+
path.display()
122+
)
123+
})?,
105124
project_root: base.to_path_buf(),
106125
crates: data
107126
.crates
108127
.into_iter()
109128
.map(|crate_data| {
110-
let is_workspace_member = crate_data.is_workspace_member.unwrap_or_else(|| {
111-
crate_data.root_module.is_relative()
112-
&& !crate_data.root_module.starts_with("..")
113-
|| crate_data.root_module.starts_with(base)
114-
});
115-
let root_module = base.join(crate_data.root_module).normalize();
129+
let root_module = absolutize(crate_data.root_module).map_err(|path| {
130+
anyhow::format_err!(
131+
"crate root module path is required to be absolute: {}",
132+
path.display()
133+
)
134+
})?;
135+
let is_workspace_member = crate_data
136+
.is_workspace_member
137+
.unwrap_or_else(|| root_module.starts_with(base));
116138
let (include, exclude) = match crate_data.source {
117139
Some(src) => {
118140
let absolutize = |dirs: Vec<PathBuf>| {
119141
dirs.into_iter()
120-
.map(|it| base.join(it).normalize())
121-
.collect::<Vec<_>>()
142+
.map(absolutize)
143+
.collect::<Result<Vec<_>, _>>()
144+
.map_err(|path| {
145+
anyhow::format_err!(
146+
"include and exclude paths are required to be absolute: {}",
147+
path.display()
148+
)
149+
})
122150
};
123-
(absolutize(src.include_dirs), absolutize(src.exclude_dirs))
151+
(absolutize(src.include_dirs)?, absolutize(src.exclude_dirs)?)
124152
}
125153
None => (vec![root_module.parent().unwrap().to_path_buf()], Vec::new()),
126154
};
127155

128-
Crate {
156+
Ok(Crate {
129157
display_name: crate_data
130158
.display_name
131159
.map(CrateDisplayName::from_canonical_name),
@@ -147,16 +175,23 @@ impl ProjectJson {
147175
env: crate_data.env,
148176
proc_macro_dylib_path: crate_data
149177
.proc_macro_dylib_path
150-
.map(|it| base.join(it)),
178+
.map(absolutize)
179+
.transpose()
180+
.map_err(|path| {
181+
anyhow::format_err!(
182+
"crate proc macro dylib path is required to be absolute: {}",
183+
path.display()
184+
)
185+
})?,
151186
is_workspace_member,
152187
include,
153188
exclude,
154189
is_proc_macro: crate_data.is_proc_macro,
155190
repository: crate_data.repository,
156-
}
191+
})
157192
})
158-
.collect::<Vec<_>>(),
159-
}
193+
.collect::<Result<Vec<_>>>()?,
194+
})
160195
}
161196

162197
/// Returns the number of crates in the project.
@@ -243,7 +278,7 @@ struct CrateSource {
243278
exclude_dirs: Vec<PathBuf>,
244279
}
245280

246-
fn deserialize_crate_name<'de, D>(de: D) -> Result<CrateName, D::Error>
281+
fn deserialize_crate_name<'de, D>(de: D) -> std::result::Result<CrateName, D::Error>
247282
where
248283
D: de::Deserializer<'de>,
249284
{

crates/project-model/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
133133
replace_root(&mut root, true);
134134
let path = Path::new(&root);
135135
let base = AbsPath::assert(path);
136-
ProjectJson::new(base, data)
136+
ProjectJson::new(base, data).unwrap()
137137
}
138138

139139
fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacroPaths) {

crates/project-model/src/workspace.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,6 @@ impl ProjectWorkspace {
179179
};
180180
let res = match manifest {
181181
ProjectManifest::ProjectJson(project_json) => {
182-
let project_json = project_json.canonicalize()?;
183182
let file = fs::read_to_string(&project_json).with_context(|| {
184183
format!("Failed to read json file {}", project_json.display())
185184
})?;
@@ -188,7 +187,7 @@ impl ProjectWorkspace {
188187
})?;
189188
let project_location = project_json.parent().to_path_buf();
190189
let toolchain = version(&*project_location, toolchain::rustc(), "rustc ")?;
191-
let project_json = ProjectJson::new(&project_location, data);
190+
let project_json = ProjectJson::new(&project_location, data)?;
192191
ProjectWorkspace::load_inline(
193192
project_json,
194193
config.target.as_deref(),

crates/rust-analyzer/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -898,7 +898,7 @@ impl Config {
898898
.map(Into::into)
899899
}
900900
ManifestOrProjectJson::ProjectJson(it) => {
901-
Some(ProjectJson::new(&self.root_path, it.clone()).into())
901+
ProjectJson::new(&self.root_path, it.clone()).ok().map(Into::into)
902902
}
903903
})
904904
.collect(),

0 commit comments

Comments
 (0)