Skip to content

Commit

Permalink
rustc: Check that the output file is writeable before linking
Browse files Browse the repository at this point in the history
This is because on Linux, the linker will silently overwrite
a read-only file.
  • Loading branch information
catamorphism committed Oct 19, 2013
1 parent 1cf029c commit 4dbef01
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 26 deletions.
25 changes: 25 additions & 0 deletions src/librustc/back/link.rs
Expand Up @@ -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,
Expand All @@ -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
Expand Down
8 changes: 4 additions & 4 deletions src/librustpkg/rustpkg.rs
Expand Up @@ -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()));
Expand Down Expand Up @@ -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));
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustpkg/tests.rs
Expand Up @@ -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"));
}
}
Expand Down
36 changes: 15 additions & 21 deletions src/librustpkg/util.rs
Expand Up @@ -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));
Expand Down Expand Up @@ -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());
Expand All @@ -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());
}
}
Expand Down

0 comments on commit 4dbef01

Please sign in to comment.