From ff68a27617c1683c6dd19ddc6669600311b940f2 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Sun, 5 Feb 2017 16:15:24 -0500 Subject: [PATCH 1/3] Attempt to solve #3366, regarding spurious shared library search paths. This drops `native_dirs` entries that are not within the target directory when modifying the (DY)LD_LIBRARY_PATH environment variable before running programs. --- src/cargo/ops/cargo_rustc/compilation.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/cargo/ops/cargo_rustc/compilation.rs b/src/cargo/ops/cargo_rustc/compilation.rs index afb8962589b..510b142db8f 100644 --- a/src/cargo/ops/cargo_rustc/compilation.rs +++ b/src/cargo/ops/cargo_rustc/compilation.rs @@ -20,7 +20,7 @@ pub struct Compilation<'cfg> { /// An array of all binaries created. pub binaries: Vec, - /// All directires for the output of native build commands. + /// All directories for the output of native build commands. /// /// This is currently used to drive some entries which are added to the /// LD_LIBRARY_PATH as appropriate. @@ -104,7 +104,10 @@ impl<'cfg> Compilation<'cfg> { } else { let mut search_path = vec![]; - // Add -L arguments, after stripping off prefixes like "native=" or "framework=". + // Add -L arguments, after stripping off prefixes like "native=" + // or "framework=" and filtering out directories *not* inside our + // output directory, since they are likely spurious and can cause + // clashes with system shared libraries (issue #3366). for dir in self.native_dirs.iter() { let dir = match dir.to_str() { Some(s) => { @@ -120,7 +123,10 @@ impl<'cfg> Compilation<'cfg> { } None => dir.clone(), }; - search_path.push(dir); + + if dir.starts_with(&self.root_output) { + search_path.push(dir); + } } search_path.push(self.root_output.clone()); search_path.push(self.deps_output.clone()); From 8913382f9959ece80b625ff86e86cafb63053b22 Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Tue, 7 Feb 2017 00:13:37 -0500 Subject: [PATCH 2/3] Update the 'run_with_library_paths' test to reflect the new filtering. For the library paths to be passed through, they must reside within the build output directory. --- tests/run.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/tests/run.rs b/tests/run.rs index bca7680cf1f..8caa3c7e7e0 100644 --- a/tests/run.rs +++ b/tests/run.rs @@ -597,30 +597,37 @@ hello #[test] fn run_with_library_paths() { - let p = project("foo") - .file("Cargo.toml", r#" + let mut p = project("foo"); + + // Only link search directories within the target output directory are + // propagated through to dylib_path_envvar() (see #3366). + let mut dir1 = p.target_debug_dir(); + dir1.push("foo"); + + let mut dir2 = p.target_debug_dir(); + dir2.push("dir=containing=equal=signs"); + + p = p.file("Cargo.toml", r#" [project] name = "foo" version = "0.0.1" authors = [] build = "build.rs" "#) - .file("build.rs", r#" - fn main() { - println!("cargo:rustc-link-search=native=foo"); - println!("cargo:rustc-link-search=bar"); - println!("cargo:rustc-link-search=/path=containing=equal=signs"); - } - "#) + .file("build.rs", &format!(r#" + fn main() {{ + println!("cargo:rustc-link-search=native={}"); + println!("cargo:rustc-link-search={}"); + }} + "#, dir1.display(), dir2.display())) .file("src/main.rs", &format!(r#" fn main() {{ let search_path = std::env::var_os("{}").unwrap(); let paths = std::env::split_paths(&search_path).collect::>(); - assert!(paths.contains(&"foo".into())); - assert!(paths.contains(&"bar".into())); - assert!(paths.contains(&"/path=containing=equal=signs".into())); + assert!(paths.contains(&"{}".into())); + assert!(paths.contains(&"{}".into())); }} - "#, dylib_path_envvar())); + "#, dylib_path_envvar(), dir1.display(), dir2.display())); assert_that(p.cargo_process("run"), execs().with_status(0)); } From d545a9fe627f63b03aac3298be8f3cb85fa3060d Mon Sep 17 00:00:00 2001 From: Peter Williams Date: Tue, 7 Feb 2017 15:55:36 -0500 Subject: [PATCH 3/3] Attempt to fix the run_with_library_paths test for Windows. I was just pasting the build directories into Rust string literals, so Windows paths with backslashes were being interpreted as having unknown string escapes. Raw string guards should fix this for all but the most pathological of build directories. --- tests/run.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/run.rs b/tests/run.rs index 8caa3c7e7e0..36d2b5a28ac 100644 --- a/tests/run.rs +++ b/tests/run.rs @@ -602,7 +602,7 @@ fn run_with_library_paths() { // Only link search directories within the target output directory are // propagated through to dylib_path_envvar() (see #3366). let mut dir1 = p.target_debug_dir(); - dir1.push("foo"); + dir1.push("foo\\backslash"); let mut dir2 = p.target_debug_dir(); dir2.push("dir=containing=equal=signs"); @@ -614,20 +614,20 @@ fn run_with_library_paths() { authors = [] build = "build.rs" "#) - .file("build.rs", &format!(r#" + .file("build.rs", &format!(r##" fn main() {{ - println!("cargo:rustc-link-search=native={}"); - println!("cargo:rustc-link-search={}"); + println!(r#"cargo:rustc-link-search=native={}"#); + println!(r#"cargo:rustc-link-search={}"#); }} - "#, dir1.display(), dir2.display())) - .file("src/main.rs", &format!(r#" + "##, dir1.display(), dir2.display())) + .file("src/main.rs", &format!(r##" fn main() {{ let search_path = std::env::var_os("{}").unwrap(); let paths = std::env::split_paths(&search_path).collect::>(); - assert!(paths.contains(&"{}".into())); - assert!(paths.contains(&"{}".into())); + assert!(paths.contains(&r#"{}"#.into())); + assert!(paths.contains(&r#"{}"#.into())); }} - "#, dylib_path_envvar(), dir1.display(), dir2.display())); + "##, dylib_path_envvar(), dir1.display(), dir2.display())); assert_that(p.cargo_process("run"), execs().with_status(0)); }