Skip to content

Commit 525aa61

Browse files
committed
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
2 parents 6136a86 + cc3b6f2 commit 525aa61

File tree

4 files changed

+69
-11
lines changed

4 files changed

+69
-11
lines changed

Diff for: src/librustc_metadata/loader.rs

+29-11
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ use rustc_back::target::Target;
231231

232232
use std::cmp;
233233
use std::collections::HashMap;
234+
use std::fmt;
234235
use std::fs;
235236
use std::io::prelude::*;
236237
use std::io;
@@ -283,6 +284,21 @@ pub struct CratePaths {
283284

284285
pub const METADATA_FILENAME: &'static str = "rust.metadata.bin";
285286

287+
#[derive(Copy, Clone, PartialEq)]
288+
enum CrateFlavor {
289+
Rlib,
290+
Dylib
291+
}
292+
293+
impl fmt::Display for CrateFlavor {
294+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
295+
f.write_str(match *self {
296+
CrateFlavor::Rlib => "rlib",
297+
CrateFlavor::Dylib => "dylib"
298+
})
299+
}
300+
}
301+
286302
impl CratePaths {
287303
fn paths(&self) -> Vec<PathBuf> {
288304
match (&self.dylib, &self.rlib) {
@@ -457,8 +473,8 @@ impl<'a> Context<'a> {
457473
let mut libraries = Vec::new();
458474
for (_hash, (rlibs, dylibs)) in candidates {
459475
let mut metadata = None;
460-
let rlib = self.extract_one(rlibs, "rlib", &mut metadata);
461-
let dylib = self.extract_one(dylibs, "dylib", &mut metadata);
476+
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut metadata);
477+
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut metadata);
462478
match metadata {
463479
Some(metadata) => {
464480
libraries.push(Library {
@@ -515,7 +531,7 @@ impl<'a> Context<'a> {
515531
// read the metadata from it if `*slot` is `None`. If the metadata couldn't
516532
// be read, it is assumed that the file isn't a valid rust library (no
517533
// errors are emitted).
518-
fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: &str,
534+
fn extract_one(&mut self, m: HashMap<PathBuf, PathKind>, flavor: CrateFlavor,
519535
slot: &mut Option<MetadataBlob>) -> Option<(PathBuf, PathKind)> {
520536
let mut ret = None::<(PathBuf, PathKind)>;
521537
let mut error = 0;
@@ -535,7 +551,7 @@ impl<'a> Context<'a> {
535551
let mut err: Option<DiagnosticBuilder> = None;
536552
for (lib, kind) in m {
537553
info!("{} reading metadata from: {}", flavor, lib.display());
538-
let metadata = match get_metadata_section(self.target, &lib) {
554+
let metadata = match get_metadata_section(self.target, flavor, &lib) {
539555
Ok(blob) => {
540556
if self.crate_matches(blob.as_slice(), &lib) {
541557
blob
@@ -702,8 +718,8 @@ impl<'a> Context<'a> {
702718

703719
// Extract the rlib/dylib pair.
704720
let mut metadata = None;
705-
let rlib = self.extract_one(rlibs, "rlib", &mut metadata);
706-
let dylib = self.extract_one(dylibs, "dylib", &mut metadata);
721+
let rlib = self.extract_one(rlibs, CrateFlavor::Rlib, &mut metadata);
722+
let dylib = self.extract_one(dylibs, CrateFlavor::Dylib, &mut metadata);
707723

708724
if rlib.is_none() && dylib.is_none() { return None }
709725
match metadata {
@@ -746,21 +762,21 @@ impl ArchiveMetadata {
746762
}
747763

748764
// Just a small wrapper to time how long reading metadata takes.
749-
fn get_metadata_section(target: &Target, filename: &Path)
765+
fn get_metadata_section(target: &Target, flavor: CrateFlavor, filename: &Path)
750766
-> Result<MetadataBlob, String> {
751767
let start = Instant::now();
752-
let ret = get_metadata_section_imp(target, filename);
768+
let ret = get_metadata_section_imp(target, flavor, filename);
753769
info!("reading {:?} => {:?}", filename.file_name().unwrap(),
754770
start.elapsed());
755771
return ret
756772
}
757773

758-
fn get_metadata_section_imp(target: &Target, filename: &Path)
774+
fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Path)
759775
-> Result<MetadataBlob, String> {
760776
if !filename.exists() {
761777
return Err(format!("no such file: '{}'", filename.display()));
762778
}
763-
if filename.file_name().unwrap().to_str().unwrap().ends_with(".rlib") {
779+
if flavor == CrateFlavor::Rlib {
764780
// Use ArchiveRO for speed here, it's backed by LLVM and uses mmap
765781
// internally to read the file. We also avoid even using a memcpy by
766782
// 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 {
864880
// A diagnostic function for dumping crate metadata to an output stream
865881
pub fn list_file_metadata(target: &Target, path: &Path,
866882
out: &mut io::Write) -> io::Result<()> {
867-
match get_metadata_section(target, path) {
883+
let filename = path.file_name().unwrap().to_str().unwrap();
884+
let flavor = if filename.ends_with(".rlib") { CrateFlavor::Rlib } else { CrateFlavor::Dylib };
885+
match get_metadata_section(target, flavor, path) {
868886
Ok(bytes) => decoder::list_crate_metadata(bytes.as_slice(), out),
869887
Err(msg) => {
870888
write!(out, "{}\n", msg)

Diff for: src/test/run-make/symlinked-rlib/Makefile

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-include ../tools.mk
2+
3+
# ignore windows: `ln` is actually `cp` on msys.
4+
ifndef IS_WINDOWS
5+
6+
all:
7+
$(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo.xxx
8+
ln -nsf $(TMPDIR)/foo.xxx $(TMPDIR)/libfoo.rlib
9+
$(RUSTC) bar.rs -L $(TMPDIR)
10+
11+
else
12+
all:
13+
14+
endif

Diff for: src/test/run-make/symlinked-rlib/bar.rs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
extern crate foo;
12+
13+
fn main() {
14+
foo::bar();
15+
}

Diff for: src/test/run-make/symlinked-rlib/foo.rs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
pub fn bar() {}

0 commit comments

Comments
 (0)