From 4dbef017dd2bdc34a6ddfb0914244946c01f9d97 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 2 Oct 2013 18:17:46 -0700 Subject: [PATCH] rustc: Check that the output file is writeable before linking This is because on Linux, the linker will silently overwrite a read-only file. --- src/librustc/back/link.rs | 25 +++++++++++++++++++++++++ src/librustpkg/rustpkg.rs | 8 ++++---- src/librustpkg/tests.rs | 2 +- src/librustpkg/util.rs | 36 +++++++++++++++--------------------- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 404efa25ff3..7028d8c4219 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -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 diff --git a/src/librustpkg/rustpkg.rs b/src/librustpkg/rustpkg.rs index affd5321665..e806e515c80 100644 --- a/src/librustpkg/rustpkg.rs +++ b/src/librustpkg/rustpkg.rs @@ -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)); } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index d522bfb15e4..8722a638c45 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -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")); } } diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 12b4ce2a881..345518eddc7 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -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()); } }