From a9f917d3f6682761a381d88eb1520449e2b2786f Mon Sep 17 00:00:00 2001 From: Guillaume Girol Date: Sun, 13 Jul 2025 12:00:00 +0000 Subject: [PATCH] clang: patch like gcc to mangle store path output by __FILE__ this prevents unwanted references to -dev outputs. A similar patch exists for gcc. tested with ``` printf "# 0 \"/nix/store/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-pppppp-vvvvvvv\" \nconst char * f(void) { return __FILE__; }" | NIX_STORE=/nix/store result/bin/clang -x c - -S -o - ``` --- .../llvm/20/clang/macro_file_mangling.patch | 78 +++++++++++++++++++ .../compilers/llvm/common/clang/default.nix | 1 + .../compilers/llvm/common/patches.nix | 6 ++ 3 files changed, 85 insertions(+) create mode 100644 pkgs/development/compilers/llvm/20/clang/macro_file_mangling.patch diff --git a/pkgs/development/compilers/llvm/20/clang/macro_file_mangling.patch b/pkgs/development/compilers/llvm/20/clang/macro_file_mangling.patch new file mode 100644 index 0000000000000..47a64b6f34d57 --- /dev/null +++ b/pkgs/development/compilers/llvm/20/clang/macro_file_mangling.patch @@ -0,0 +1,78 @@ +Without the change `__FILE__` used in static inline functions in headers +embed paths to header files into executable images. For local headers +it's not a problem, but for headers in `/nix/store` this causes `-dev` +inputs to be retained in runtime closure. + +Typical examples are `nix` -> `nlohmann_json` and `pipewire` -> +`lttng-ust.dev`. + +For this reason we want to remove the occurrences of hashes in the +expansion of `__FILE__`. `nuke-references` does it by replacing hashes +by `eeeeee...`. It is handy to be able to invert the transformation to +go back to the original store path. The chosen solution is to make the +hash uppercase: +- it does not trigger runtime references (except for all digit hashes, + which are unlikely enough) +- it visually looks like a bogus store path +- it is easy to find the original store path if required + +Ideally we would like to use `-fmacro-prefix-map=` feature of `gcc` and `clang` as: + + -fmacro-prefix-map=/nix/store/$hash1-nlohmann-json-ver=/nix/store/$HASH1-nlohmann-json-ver + -fmacro-prefix-map=/nix/... + +In practice it quickly exhausts argument length limit due to `gcc` +deficiency: https://gcc.gnu.org/PR111527 +This patch to `clang` is a copy of the corresponding `gcc` patch so the same +approach was kept. + +This patch hardcode header mangling if $NIX_STORE variable +is present in the environment. + +Tested as: + + $ printf "# 0 \"/nix/store/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-pppppp-vvvvvvv\" \nconst char * f(void) { return __FILE__; }" | NIX_STORE=/nix/store ./gcc/xgcc -Bgcc -x c - -S -o - + ... + .string "/nix/store/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA-pppppp-vvvvvvv" + ... + +Mangled successfully. + +To reverse the effect of the mangle use new `NIX_CLANG_DONT_MANGLE_PREFIX_MAP` +environment variable. It should not normally be needed. + +The ability to go back to the original store path is relied on by +nixseparatedebuginfod, for example. +--- clang/lib/Basic/LangOptions.cpp ++++ clang/lib/Basic/LangOptions.cpp +@@ -12,6 +12,8 @@ + + #include "clang/Basic/LangOptions.h" + #include "llvm/Support/Path.h" ++#include ++#include + + using namespace clang; + +@@ -76,6 +78,21 @@ void LangOptions::remapPathPrefix(SmallVectorImpl &Path) const { + for (const auto &Entry : MacroPrefixMap) + if (llvm::sys::path::replace_path_prefix(Path, Entry.first, Entry.second)) + break; ++ if (std::getenv("NIX_CLANG_DONT_MANGLE_PREFIX_MAP") == nullptr) { ++ char* nix_store = getenv("NIX_STORE"); ++ if (nix_store == nullptr) { ++ return; ++ } ++ size_t nix_store_len = strlen(nix_store); ++ if (Path.size() <= nix_store_len + 1 + 32) { ++ return; ++ } ++ if (std::equal(Path.begin(), Path.begin() + nix_store_len, nix_store)) { ++ for (auto c = Path.begin() + nix_store_len + 1; c < Path.begin() + nix_store_len + 1 + 32; c++) { ++ *c = std::toupper(*c); ++ } ++ } ++ } + } + + std::string LangOptions::getOpenCLVersionString() const { diff --git a/pkgs/development/compilers/llvm/common/clang/default.nix b/pkgs/development/compilers/llvm/common/clang/default.nix index f671bf370aa5e..8df3b957df484 100644 --- a/pkgs/development/compilers/llvm/common/clang/default.nix +++ b/pkgs/development/compilers/llvm/common/clang/default.nix @@ -48,6 +48,7 @@ stdenv.mkDerivation ( patches = [ (getVersionFile "clang/purity.patch") + (getVersionFile "clang/macro_file_mangling.patch") # Remove extraneous ".a" suffix from baremetal clang_rt.builtins when compiling for baremetal. # https://reviews.llvm.org/D51899 (getVersionFile "clang/gnu-install-dirs.patch") diff --git a/pkgs/development/compilers/llvm/common/patches.nix b/pkgs/development/compilers/llvm/common/patches.nix index cd4939dcd1195..e2706bf9a4cab 100644 --- a/pkgs/development/compilers/llvm/common/patches.nix +++ b/pkgs/development/compilers/llvm/common/patches.nix @@ -24,6 +24,12 @@ path = ../12; } ]; + "clang/macro_file_mangling.patch" = [ + { + after = "19"; + path = ../20; + } + ]; "clang/aarch64-tblgen.patch" = [ { after = "17";