Skip to content

Commit 9afb903

Browse files
committed
fix(#172): prevent OUT_DIR escape for '..' file paths
Restore ParentDir check lost in #931 refactoring. Paths with '..' now hashed to stay within OUT_DIR. - src/command_helpers: re-add Component::ParentDir check - tests: 3 new regression tests
1 parent 9ec00e4 commit 9afb903

File tree

2 files changed

+89
-0
lines changed

2 files changed

+89
-0
lines changed

src/command_helpers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ pub(crate) fn objects_from_files(files: &[Arc<Path>], dst: &Path) -> Result<Vec<
323323
if let Some(extension) = file.extension() {
324324
hasher.write(extension.to_string_lossy().as_bytes());
325325
}
326+
326327
let obj = dst
327328
.join(format!("{:016x}-{}", hasher.finish(), basename))
328329
.with_extension("o");

tests/test.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,94 @@ fn clang_android() {
879879
}
880880
}
881881

882+
#[test]
883+
fn parent_dir_file_path() {
884+
// Regression test for issue #172
885+
// https://github.com/rust-lang/cc-rs/issues/172
886+
// Ensures that files referenced with parent directory components (..)
887+
// have their object files placed within OUT_DIR, not in parent directories
888+
889+
reset_env();
890+
let test = Test::gnu();
891+
892+
let intermediates = test
893+
.gcc()
894+
.file("../external_lib/test.c")
895+
.compile_intermediates();
896+
897+
// Verify we got an object file back
898+
assert_eq!(
899+
intermediates.len(),
900+
1,
901+
"Expected exactly one intermediate object file"
902+
);
903+
904+
let obj_path = &intermediates[0];
905+
let out_dir = test.td.path();
906+
907+
// Verify the object file is actually within OUT_DIR
908+
assert!(
909+
obj_path.starts_with(out_dir),
910+
"Object file {:?} is not within OUT_DIR {:?}. This indicates the file path \
911+
with parent directory components (..) caused the object file to escape OUT_DIR.",
912+
obj_path,
913+
out_dir
914+
);
915+
}
916+
917+
#[test]
918+
fn multiple_parent_dir_references() {
919+
// Test deeply nested parent directory references
920+
// e.g., ../../deep/path/../file.c
921+
922+
reset_env();
923+
let test = Test::gnu();
924+
925+
let intermediates = test
926+
.gcc()
927+
.file("a/b/c/../../b/c/deep.c")
928+
.compile_intermediates();
929+
930+
assert_eq!(intermediates.len(), 1);
931+
let obj_path = &intermediates[0];
932+
let out_dir = test.td.path();
933+
934+
// Must be within OUT_DIR
935+
assert!(
936+
obj_path.starts_with(out_dir),
937+
"Object file with multiple parent refs {:?} escaped OUT_DIR {:?}",
938+
obj_path,
939+
out_dir
940+
);
941+
}
942+
943+
#[test]
944+
fn parent_dir_with_multiple_files() {
945+
// Test that multiple files with parent directory references
946+
// all get properly contained in OUT_DIR
947+
948+
reset_env();
949+
let test = Test::gnu();
950+
951+
let intermediates = test
952+
.gcc()
953+
.file("src1/../src1/file1.c")
954+
.file("src2/../src2/file2.c")
955+
.compile_intermediates();
956+
957+
assert_eq!(intermediates.len(), 2, "Expected two object files");
958+
959+
let out_dir = test.td.path();
960+
for obj_path in &intermediates {
961+
assert!(
962+
obj_path.starts_with(out_dir),
963+
"Object file {:?} is not within OUT_DIR {:?}",
964+
obj_path,
965+
out_dir
966+
);
967+
}
968+
}
969+
882970
#[cfg(windows)]
883971
#[cfg(not(disable_clang_cl_tests))]
884972
mod msvc_clang_cl_tests {

0 commit comments

Comments
 (0)