]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
fix: Avoid expanding symlinks in relative path candidates
authorJoel Rosdahl <joel@rosdahl.net>
Tue, 9 Sep 2025 16:34:34 +0000 (18:34 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Tue, 9 Sep 2025 19:04:20 +0000 (21:04 +0200)
Commit 8223ed38abd9cf75ab75cb19dc2081c44bf568d0 changed
make_relative_path to also try matching real_path(path) against the
apparent/actual CWD, assuming that an absolute path p could be
substituted with real_path(p).

This assumption is incorrect for source files: if the source file
includes a file via a relative path, expanding symlinks may cause the
include file to be searched in the wrong directory.

Fix by reverting that change. The new test case "Symlink to source file,
longer symlink path" fails without this fix.

Note: this effectively reverts #724.

Fixes #1620.

src/ccache/util/path.cpp
test/suites/basedir.bash
unittest/test_util_path.cpp

index 4f58eb79233a948e46914fda184c76fb8d79d821..855dc587491f47138012aaf0b499aac08685e798 100644 (file)
@@ -91,18 +91,11 @@ make_relative_path(const fs::path& actual_cwd,
     closest_existing_path = closest_existing_path.parent_path();
   }
 
-  const auto add_relpath_candidates = [&](auto p) {
-    relpath_candidates.push_back(p.lexically_relative(actual_cwd));
-    if (apparent_cwd != actual_cwd) {
-      relpath_candidates.emplace_back(p.lexically_relative(apparent_cwd));
-    }
-  };
-
-  add_relpath_candidates(closest_existing_path);
-  const fs::path real_closest_existing_path =
-    fs::canonical(closest_existing_path).value_or(closest_existing_path);
-  if (real_closest_existing_path != closest_existing_path) {
-    add_relpath_candidates(real_closest_existing_path);
+  relpath_candidates.push_back(
+    closest_existing_path.lexically_relative(actual_cwd));
+  if (apparent_cwd != actual_cwd) {
+    relpath_candidates.emplace_back(
+      closest_existing_path.lexically_relative(apparent_cwd));
   }
 
   // Find best (i.e. shortest existing) match:
index 9f237422264780a41af81d80c998c15551a3a77f..122e1c66b78a2cc643921a70f9ef07d962eb01fc 100644 (file)
@@ -117,7 +117,7 @@ fi
 
     # -------------------------------------------------------------------------
 if ! $HOST_OS_WINDOWS && ! $HOST_OS_CYGWIN; then
-    TEST "Symlink to source file"
+    TEST "Symlink to source file, shorter symlink path"
 
     mkdir dir
     cd dir
@@ -138,6 +138,29 @@ EOF
     fi
 fi
 
+    # -------------------------------------------------------------------------
+if ! $HOST_OS_WINDOWS && ! $HOST_OS_CYGWIN; then
+    TEST "Symlink to source file, longer symlink path"
+
+    mkdir dir
+    cd dir
+    mkdir d
+    echo '#define A "BUG"' >h.h
+    cat <<EOF >c.c
+#include <stdio.h>
+#include "h.h"
+int main() { printf("%s\n", A); }
+EOF
+    echo '#define A "OK"' >d/h.h
+    ln -s ../c.c d/c.c
+
+    CCACHE_BASEDIR=/ $CCACHE_COMPILE -c $PWD/d/c.c
+    $COMPILER c.o -o c
+    if [ "$(./c)" != OK ]; then
+        test_failed "Incorrect header file used"
+    fi
+fi
+
     # -------------------------------------------------------------------------
 if ! $HOST_OS_WINDOWS && ! $HOST_OS_CYGWIN; then
     TEST "Symlinked build dir inside source dir"
@@ -411,13 +434,13 @@ fi
     TEST "Relative PWD"
 
     cd dir1
-    CCACHE_BASEDIR="$(pwd)" PWD=. $CCACHE_COMPILE -I$(pwd)/include -c src/test.c
+    CCACHE_BASEDIR="$(pwd -P)" PWD=. $CCACHE_COMPILE -I$(pwd -P)/include -c src/test.c
     expect_stat direct_cache_hit 0
     expect_stat preprocessed_cache_hit 0
     expect_stat cache_miss 1
 
     cd ../dir2
-    CCACHE_BASEDIR="$(pwd)" PWD=. $CCACHE_COMPILE -I$(pwd)/include -c src/test.c
+    CCACHE_BASEDIR="$(pwd -P)" PWD=. $CCACHE_COMPILE -I$(pwd -P)/include -c src/test.c
     expect_stat direct_cache_hit 1
     expect_stat preprocessed_cache_hit 0
     expect_stat cache_miss 1
@@ -428,13 +451,13 @@ fi
     unset PWD
 
     cd dir1
-    CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -I$(pwd)/include -c src/test.c
+    CCACHE_BASEDIR="$(pwd -P)" $CCACHE_COMPILE -I$(pwd -P)/include -c src/test.c
     expect_stat direct_cache_hit 0
     expect_stat preprocessed_cache_hit 0
     expect_stat cache_miss 1
 
     cd ../dir2
-    CCACHE_BASEDIR="$(pwd)" $CCACHE_COMPILE -I$(pwd)/include -c src/test.c
+    CCACHE_BASEDIR="$(pwd -P)" $CCACHE_COMPILE -I$(pwd -P)/include -c src/test.c
     expect_stat direct_cache_hit 1
     expect_stat preprocessed_cache_hit 0
     expect_stat cache_miss 1
index 838571ea88d7dd6c2ec8a400e951e5f7d3979847..9ecddbcd71e04f8376609e72264bd9feb554dc82 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2021-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2021-2025 Joel Rosdahl and other contributors
 //
 // See doc/AUTHORS.adoc for a complete list of contributors.
 //
@@ -140,12 +140,6 @@ TEST_CASE("util::make_relative_path")
     CHECK(make_relative_path(actual_cwd, apparent_cwd, apparent_cwd + "/x")
           == "x");
   }
-
-  SUBCASE("Match if using resolved (using realpath(3)) path")
-  {
-    CHECK(make_relative_path(actual_cwd, actual_cwd, apparent_cwd + "/x")
-          == "x");
-  }
 #endif
 }