about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-04-13 07:16:20 -0700
committerbors <bors@rust-lang.org>2016-04-13 07:16:20 -0700
commit525aa6102250ec2a33c7066dfb966524f0ce3e21 (patch)
tree4d7f35086f2506f52e014269a04ec7483659dbcc /src
parent6136a86291b12f5441910d56d5bc0dfbc7eecdeb (diff)
parentcc3b6f24b7604880279918b3c1a58ef62fb06b36 (diff)
Auto merge of #32828 - vadimcn:symlinks, r=alexcrichton
Do not rely on file extensions after path canonicalization.

Rustc does not recognize libraries which are symlinked to files having extension other than .rlib. The problem is that find_library_crate calls fs::canonicalize on found library paths, but then the resulting path is passed to get_metadata_section, which assumes it will end in ".rlib" if it's an rlib (from https://internals.rust-lang.org/t/is-library-path-canonicalization-worth-it/3206).

cc #29433
Diffstat (limited to 'src')
-rw-r--r--src/librustc_metadata/loader.rs40
-rw-r--r--src/test/run-make/symlinked-rlib/Makefile14
-rw-r--r--src/test/run-make/symlinked-rlib/bar.rs15
-rw-r--r--src/test/run-make/symlinked-rlib/foo.rs11
4 files changed, 69 insertions, 11 deletions
diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs
index c7cd8ae2dd7..be1e194efc3 100644
--- a/src/librustc_metadata/loader.rs
+++ b/src/librustc_metadata/loader.rs
@@ -231,6 +231,7 @@ use rustc_back::target::Target;
 
 use std::cmp;
 use std::collections::HashMap;
+use std::fmt;
 use std::fs;
 use std::io::prelude::*;
 use std::io;
@@ -283,6 +284,21 @@ pub struct CratePaths {
 
 pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";
 
+#[derive(Copy, Clone, PartialEq)]
+enum CrateFlavor {
+    Rlib,
+    Dylib
+}
+
+impl fmt::Display for CrateFlavor {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.write_str(match *self {
+            CrateFlavor::Rlib => "rlib",
+            CrateFlavor::Dylib => "dylib"
+        })
+    }
+}
+
 impl CratePaths {
     fn paths(&self) -> Vec<PathBuf> {
         match (&self.dylib, &self.rlib) {
@@ -457,8 +473,8 @@ impl<'a> Context<'a> {
         let mut libraries = Vec::new();
         for (_hash, (rlibs, dylibs)) in candidates {
             let mut metadata = None;
-            let rlib = self.extract_one(rlibs, "rlib", &mut metadata);
-            let dylib = self.extract_one(dylibs, "dylib", &mut metadata);
+            let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut metadata);
+            let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut metadata);
             match metadata {
                 Some(metadata) => {
                     libraries.push(Library {
@@ -515,7 +531,7 @@ impl<'a> Context<'a> {
     // read the metadata from it if `*slot` is `None`. If the metadata couldn't
     // be read, it is assumed that the file isn't a valid rust library (no
     // errors are emitted).
-    fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: &str,
+    fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: CrateFlavor,
                    slot: &mut Option<MetadataBlob>) -> Option<(PathBuf, PathKind)> {
         let mut ret = None::<(PathBuf, PathKind)>;
         let mut error = 0;
@@ -535,7 +551,7 @@ impl<'a> Context<'a> {
         let mut err: Option<DiagnosticBuilder> = None;
         for (lib, kind) in m {
             info!("{} reading metadata from: {}", flavor, lib.display());
-            let metadata = match get_metadata_section(self.target, &lib) {
+            let metadata = match get_metadata_section(self.target, flavor, &lib) {
                 Ok(blob) => {
                     if self.crate_matches(blob.as_slice(), &lib) {
                         blob
@@ -702,8 +718,8 @@ impl<'a> Context<'a> {
 
         // Extract the rlib/dylib pair.
         let mut metadata = None;
-        let rlib = self.extract_one(rlibs, "rlib", &mut metadata);
-        let dylib = self.extract_one(dylibs, "dylib", &mut metadata);
+        let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut metadata);
+        let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut metadata);
 
         if rlib.is_none() && dylib.is_none() { return None }
         match metadata {
@@ -746,21 +762,21 @@ impl ArchiveMetadata {
 }
 
 // Just a small wrapper to time how long reading metadata takes.
-fn get_metadata_section(target: &Target, filename: &Path)
+fn get_metadata_section(target: &Target, flavor: CrateFlavor, filename: &Path)
                         -> Result<MetadataBlob, String> {
     let start = Instant::now();
-    let ret = get_metadata_section_imp(target, filename);
+    let ret = get_metadata_section_imp(target, flavor, filename);
     info!("reading {:?} => {:?}", filename.file_name().unwrap(),
           start.elapsed());
     return ret
 }
 
-fn get_metadata_section_imp(target: &Target, filename: &Path)
+fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Path)
                             -> Result<MetadataBlob, String> {
     if !filename.exists() {
         return Err(format!("no such file: '{}'", filename.display()));
     }
-    if filename.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
+    if flavor == CrateFlavor::Rlib {
         // Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
         // internally to read the file. We also avoid even using a memcpy by
         // just keeping the archive along while the metadata is in use.
@@ -864,7 +880,9 @@ pub fn read_meta_section_name(target: &Target) -> &'static str {
 // A diagnostic function for dumping crate metadata to an output stream
 pub fn list_file_metadata(target: &Target, path: &Path,
                           out: &mut io::Write) -> io::Result<()> {
-    match get_metadata_section(target, path) {
+    let filename = path.file_name().unwrap().to_str().unwrap();
+    let flavor = if filename.ends_with(".rlib") { CrateFlavor::Rlib } else { CrateFlavor::Dylib };
+    match get_metadata_section(target, flavor, path) {
         Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out),
         Err(msg) => {
             write!(out, "{}\n", msg)
diff --git a/src/test/run-make/symlinked-rlib/Makefile b/src/test/run-make/symlinked-rlib/Makefile
new file mode 100644
index 00000000000..2709f786e0a
--- /dev/null
+++ b/src/test/run-make/symlinked-rlib/Makefile
@@ -0,0 +1,14 @@
+-include ../tools.mk
+
+# ignore windows: `ln` is actually `cp` on msys.
+ifndef IS_WINDOWS
+
+all:
+	$(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo.xxx
+	ln -nsf $(TMPDIR)/foo.xxx $(TMPDIR)/libfoo.rlib
+	$(RUSTC) bar.rs -L $(TMPDIR)
+
+else
+all:
+
+endif
diff --git a/src/test/run-make/symlinked-rlib/bar.rs b/src/test/run-make/symlinked-rlib/bar.rs
new file mode 100644
index 00000000000..e8f06680862
--- /dev/null
+++ b/src/test/run-make/symlinked-rlib/bar.rs
@@ -0,0 +1,15 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate foo;
+
+fn main() {
+    foo::bar();
+}
diff --git a/src/test/run-make/symlinked-rlib/foo.rs b/src/test/run-make/symlinked-rlib/foo.rs
new file mode 100644
index 00000000000..5abbb1dcbce
--- /dev/null
+++ b/src/test/run-make/symlinked-rlib/foo.rs
@@ -0,0 +1,11 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn bar() {}