rustc: Check that the output file is writeable before linking

This is because on Linux, the linker will silently overwrite
a read-only file.
This commit is contained in:
Tim Chevalier 2013-10-02 18:17:46 -07:00
parent 1cf029c229
commit 4dbef017dd
4 changed files with 45 additions and 26 deletions

View file

@ -959,6 +959,16 @@ pub fn link_binary(sess: Session,
}
}
fn is_writeable(p: &Path) -> bool {
use std::libc::consts::os::posix88::S_IWUSR;
!os::path_exists(p) ||
(match p.get_mode() {
None => false,
Some(m) => m & S_IWUSR as uint == S_IWUSR as uint
})
}
pub fn link_args(sess: Session,
obj_filename: &Path,
out_filename: &Path,
@ -982,6 +992,21 @@ pub fn link_args(sess: Session,
out_filename.clone()
};
// Make sure the output and obj_filename are both writeable.
// Mac, FreeBSD, and Windows system linkers check this already --
// however, the Linux linker will happily overwrite a read-only file.
// We should be consistent.
let obj_is_writeable = is_writeable(obj_filename);
let out_is_writeable = is_writeable(&output);
if !out_is_writeable {
sess.fatal(format!("Output file {} is not writeable -- check its permissions.",
output.display()));
}
else if !obj_is_writeable {
sess.fatal(format!("Object file {} is not writeable -- check its permissions.",
obj_filename.display()));
}
// The default library location, we need this to find the runtime.
// The location of crates will be determined as needed.
// FIXME (#9639): This needs to handle non-utf8 paths

View file

@ -556,7 +556,7 @@ impl CtxMethods for BuildContext {
debug2!("In declare inputs for {}", id.to_str());
for cs in to_do.iter() {
for c in cs.iter() {
let path = pkg_src.start_dir.join(&c.file).normalize();
let path = pkg_src.start_dir.join(&c.file);
debug2!("Recording input: {}", path.display());
// FIXME (#9639): This needs to handle non-utf8 paths
inputs.push((~"file", path.as_str().unwrap().to_owned()));
@ -623,19 +623,19 @@ impl CtxMethods for BuildContext {
// Declare all the *inputs* to the declared input too, as inputs
for executable in subex.iter() {
exe_thing.discover_input("binary",
executable.to_str(),
executable.as_str().unwrap().to_owned(),
workcache_support::digest_only_date(executable));
}
for library in sublib.iter() {
exe_thing.discover_input("binary",
library.to_str(),
library.as_str().unwrap().to_owned(),
workcache_support::digest_only_date(library));
}
for transitive_dependency in sub_build_inputs.iter() {
exe_thing.discover_input(
"file",
transitive_dependency.to_str(),
transitive_dependency.as_str().unwrap().to_owned(),
workcache_support::digest_file_with_date(transitive_dependency));
}

View file

@ -516,7 +516,7 @@ fn touch_source_file(workspace: &Path, pkgid: &PkgId) {
// should be able to do this w/o a process
// FIXME (#9639): This needs to handle non-utf8 paths
// n.b. Bumps time up by 2 seconds to get around granularity issues
if run::process_output("touch", [~"-A", ~"02", p.to_str()]).status != 0 {
if run::process_output("touch", [~"-A", ~"02", p.as_str().unwrap().to_owned()]).status != 0 {
let _ = cond.raise((pkg_src_dir.clone(), ~"Bad path"));
}
}

View file

@ -441,8 +441,8 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
// Now we know that this crate has a discovered dependency on
// installed_path
// FIXME (#9639): This needs to handle non-utf8 paths
add_dep(self.deps, self.parent_crate.to_str(),
(~"binary", installed_path.to_str()));
add_dep(self.deps, self.parent_crate.as_str().unwrap().to_owned(),
(~"binary", installed_path.as_str().unwrap().to_owned()));
self.exec.discover_input("binary",
installed_path.as_str().unwrap(),
digest_only_date(installed_path));
@ -492,6 +492,10 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
self.exec.discover_input("binary",
dep.as_str().unwrap(),
digest_only_date(dep));
add_dep(self.deps,
self.parent_crate.as_str().unwrap().to_owned(),
(~"binary", dep.as_str().unwrap().to_owned()));
// Also, add an additional search path
let dep_dir = dep.dir_path();
debug2!("Installed {} into {}", dep.display(), dep_dir.display());
@ -502,41 +506,31 @@ impl<'self> Visitor<()> for ViewItemVisitor<'self> {
lib_name, outputs_disc.len(), inputs_disc.len());
// It must have installed *something*...
assert!(!outputs_disc.is_empty());
let target_workspace = outputs_disc[0].pop();
for dep in outputs_disc.iter() {
debug2!("Discovering a binary input: {}", dep.to_str());
self.exec.discover_input("binary", dep.to_str(),
digest_only_date(dep));
add_dep(self.deps,
self.parent_crate.to_str(),
(~"binary", dep.to_str()));
}
let mut target_workspace = outputs_disc[0].clone();
target_workspace.pop();
for &(ref what, ref dep) in inputs_disc.iter() {
if *what == ~"file" {
add_dep(self.deps,
self.parent_crate.to_str(),
(~"file", dep.to_str()));
self.parent_crate.as_str().unwrap().to_owned(),
(~"file", dep.clone()));
self.exec.discover_input(*what,
*dep,
digest_file_with_date(
&Path::new(dep.as_slice())));
}
else if *what == ~"binary" {
} else if *what == ~"binary" {
add_dep(self.deps,
self.parent_crate.to_str(),
(~"binary", dep.to_str()));
self.parent_crate.as_str().unwrap().to_owned(),
(~"binary", dep.clone()));
self.exec.discover_input(*what,
*dep,
digest_only_date(
&Path::new(dep.as_slice())));
}
else {
} else {
fail2!("Bad kind: {}", *what);
}
// Also, add an additional search path
debug2!("Installed {} into {}",
lib_name, target_workspace.to_str());
lib_name, target_workspace.as_str().unwrap().to_owned());
(self.save)(target_workspace.clone());
}
}