Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package patchelf for openSUSE:Factory checked in at 2026-08-01 18:29:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/patchelf (Old) and /work/SRC/openSUSE:Factory/.patchelf.new.16738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "patchelf" Sat Aug 1 18:29:03 2026 rev:25 rq:1368552 version:0.19.1 Changes: -------- --- /work/SRC/openSUSE:Factory/patchelf/patchelf.changes 2026-07-08 17:32:42.377454677 +0200 +++ /work/SRC/openSUSE:Factory/.patchelf.new.16738/patchelf.changes 2026-08-01 18:29:52.840896718 +0200 @@ -1,0 +2,7 @@ +Tue Jul 28 11:36:10 CEST 2026 - Arvin Schnell <[email protected]> + +- update to 0.19.1: + * The --build-resolution-cache flag now preserves run-path + search order + +------------------------------------------------------------------- Old: ---- patchelf-0.19.0.tar.bz2 New: ---- patchelf-0.19.1.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ patchelf.spec ++++++ --- /var/tmp/diff_new_pack.ufcC8j/_old 2026-08-01 18:29:53.328913330 +0200 +++ /var/tmp/diff_new_pack.ufcC8j/_new 2026-08-01 18:29:53.332913465 +0200 @@ -17,7 +17,7 @@ Name: patchelf -Version: 0.19.0 +Version: 0.19.1 Release: 0 Summary: A utility for patching ELF binaries License: GPL-3.0-only ++++++ patchelf-0.19.0.tar.bz2 -> patchelf-0.19.1.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/patchelf-0.19.0/configure new/patchelf-0.19.1/configure --- old/patchelf-0.19.0/configure 2026-06-26 17:22:06.000000000 +0200 +++ new/patchelf-0.19.1/configure 2026-07-06 23:38:06.000000000 +0200 @@ -1,6 +1,6 @@ #!/bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for patchelf 0.19.0. +# Generated by GNU Autoconf 2.72 for patchelf 0.19.1. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2023 Free Software Foundation, @@ -600,8 +600,8 @@ # Identity of this package. PACKAGE_NAME='patchelf' PACKAGE_TARNAME='patchelf' -PACKAGE_VERSION='0.19.0' -PACKAGE_STRING='patchelf 0.19.0' +PACKAGE_VERSION='0.19.1' +PACKAGE_STRING='patchelf 0.19.1' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1287,7 +1287,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures patchelf 0.19.0 to adapt to many kinds of systems. +'configure' configures patchelf 0.19.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1354,7 +1354,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of patchelf 0.19.0:";; + short | recursive ) echo "Configuration of patchelf 0.19.1:";; esac cat <<\_ACEOF @@ -1458,7 +1458,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -patchelf configure 0.19.0 +patchelf configure 0.19.1 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -1575,7 +1575,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by patchelf $as_me 0.19.0, which was +It was created by patchelf $as_me 0.19.1, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3076,7 +3076,7 @@ # Define the identity of the package. PACKAGE='patchelf' - VERSION='0.19.0' + VERSION='0.19.1' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h @@ -7246,7 +7246,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by patchelf $as_me 0.19.0, which was +This file was extended by patchelf $as_me 0.19.1, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7305,7 +7305,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -patchelf config.status 0.19.0 +patchelf config.status 0.19.1 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/patchelf-0.19.0/patchelf.1 new/patchelf-0.19.1/patchelf.1 --- old/patchelf-0.19.0/patchelf.1 1970-01-01 01:00:01.000000000 +0100 +++ new/patchelf-0.19.1/patchelf.1 1970-01-01 01:00:01.000000000 +0100 @@ -106,10 +106,12 @@ Resolves each DT_NEEDED dependency against the object's run path at patch time and records the result in a \fB.note.nixos.ldcache\fR note, so that a loader which understands the note can skip the run-path search at startup. Directories -that cannot be resolved ahead of time (those containing dynamic-string tokens -such as \fB$ORIGIN\fR, or a \fBglibc-hwcaps\fR subdirectory) are stored as a -search hint instead of an exact path. The cache is built once from an unpatched -binary; this option cannot be combined with \fB--force-rpath\fR. +that cannot be resolved ahead of time (empty or relative components, those +containing dynamic-string tokens such as \fB$ORIGIN\fR or a \fBglibc-hwcaps\fR +subdirectory, and paths that cannot be searched at patch time because they are +missing, not a directory, or not accessible) are stored as a search hint +instead of an exact path. The cache is built once from an unpatched binary; +this option cannot be combined with \fB--force-rpath\fR. .IP "--no-sort" Do not sort program headers or section headers. This is useful when diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/patchelf-0.19.0/patchelf.spec new/patchelf-0.19.1/patchelf.spec --- old/patchelf-0.19.0/patchelf.spec 2026-06-26 17:22:07.000000000 +0200 +++ new/patchelf-0.19.1/patchelf.spec 2026-07-06 23:38:08.000000000 +0200 @@ -1,7 +1,7 @@ Summary: A utility for patching ELF binaries Name: patchelf -Version: 0.19.0 +Version: 0.19.1 Release: 1 License: GPL Group: Development/Tools diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/patchelf-0.19.0/src/patchelf.cc new/patchelf-0.19.1/src/patchelf.cc --- old/patchelf-0.19.0/src/patchelf.cc 1970-01-01 01:00:01.000000000 +0100 +++ new/patchelf-0.19.1/src/patchelf.cc 1970-01-01 01:00:01.000000000 +0100 @@ -78,7 +78,9 @@ #define EM_LOONGARCH 258 #endif -[[nodiscard]] static std::vector<std::string> splitColonDelimitedString(std::string_view s) +/* A trailing ':' is a final current-directory search position under run-path + semantics, kept only when keepTrailingEmpty is set. */ +[[nodiscard]] static std::vector<std::string> splitColonDelimitedString(std::string_view s, bool keepTrailingEmpty = false) { std::vector<std::string> parts; @@ -88,7 +90,7 @@ s = s.substr(pos + 1); } - if (!s.empty()) + if (keepTrailingEmpty || !s.empty()) parts.emplace_back(s); return parts; @@ -2227,12 +2229,30 @@ patch in Nixpkgs that reads it; keep them in sync. The descriptor is a sequence of NUL-terminated (needed, path-list) string pairs, where each path-list entry is "=<absolute-path>" for a directly resolved library or - "?<dir>" for a directory the loader must still search itself (used for - $ORIGIN-style and glibc-hwcaps directories). */ + "?<dir>" for a directory the loader must still search itself. */ static const char ldCacheNoteName[] = "NixOS"; static const char ldCacheSectionName[] = ".note.nixos.ldcache"; static constexpr uint32_t NT_NIXOS_LD_CACHE = 0x63a86cb6; +/* A run-path component that can't be exhaustively searched at patch time gets + a hint keeping its run-path position, so a later exact entry can't bypass + it. This covers empty/relative components and dynamic-string tokens the + loader expands, absolute paths that are missing or unsearchable at patch + time but may appear at run time (e.g. /run/opengl-driver/lib on NixOS), and + glibc-hwcaps directories the loader probes for. */ +[[nodiscard]] static bool needsSearchHint(const std::string & dir) +{ + if (dir.empty() || dir[0] != '/') + return true; + if (dir.find('$') != std::string::npos) + return true; + struct stat st; + if (stat(dir.c_str(), &st) != 0 || !S_ISDIR(st.st_mode) + || access(dir.c_str(), X_OK) != 0) + return true; + return access((dir + "/glibc-hwcaps").c_str(), F_OK) == 0; +} + template<ElfFileParams> void ElfFile<ElfFileParamNames>::removeResolutionCache() { @@ -2336,8 +2356,10 @@ } /* DT_RUNPATH takes precedence over DT_RPATH, as in the loader. */ const char * runPathStr = dtRunPath ? dtRunPath : dtRPath; - std::vector<std::string> runPath = - runPathStr ? splitColonDelimitedString(runPathStr) : std::vector<std::string>{}; + /* Keep a trailing empty component; an empty run-path string has none. */ + std::vector<std::string> runPath = runPathStr && *runPathStr + ? splitColonDelimitedString(runPathStr, /* keepTrailingEmpty */ true) + : std::vector<std::string>{}; if (needed.empty() || runPath.empty()) { failIfStale(); fprintf(stderr, "warning: --build-resolution-cache: no DT_NEEDED entries or run path to resolve; no cache written\n"); @@ -2345,9 +2367,8 @@ } /* Resolve each soname against the run path, first match wins (as the - loader does). Directories containing dynamic-string tokens or a - glibc-hwcaps subdirectory can't be resolved at patch time, so record - them as a search hint for the loader instead of an exact path. */ + loader does). Components that only resolve at run time are recorded as a + search hint instead of an exact path. */ std::map<std::string, std::string> cache; auto addEntry = [&](const std::string & lib, const std::string & resolved) { auto & entry = cache[lib]; @@ -2362,13 +2383,7 @@ return lib.find('/') == std::string::npos; }; for (const auto & dir : runPath) { - /* The loader reads an empty run-path component as the current working - directory, which is meaningless to bake in at patch time. */ - if (dir.empty()) - continue; - const bool hasToken = dir.find('$') != std::string::npos; - const bool hasHwcaps = access((dir + "/glibc-hwcaps").c_str(), F_OK) == 0; - if (hasToken || hasHwcaps) { + if (needsSearchHint(dir)) { const std::string hint = "?" + dir; for (const auto & lib : needed) if (isSearched(lib)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/patchelf-0.19.0/tests/build-resolution-cache-search-hint.sh new/patchelf-0.19.1/tests/build-resolution-cache-search-hint.sh --- old/patchelf-0.19.0/tests/build-resolution-cache-search-hint.sh 1970-01-01 01:00:01.000000000 +0100 +++ new/patchelf-0.19.1/tests/build-resolution-cache-search-hint.sh 1970-01-01 01:00:01.000000000 +0100 @@ -1,7 +1,8 @@ #! /bin/sh -e # Run-path entries that can't be resolved at patch time -- dynamic-string -# tokens ($ORIGIN/$LIB/$PLATFORM) and glibc-hwcaps directories -- must be -# recorded as "?<dir>" search hints, never as absolute "=<path>" entries. +# tokens ($ORIGIN/$LIB/$PLATFORM), glibc-hwcaps directories, and components +# that only resolve or exist at run time -- must be recorded as "?<dir>" +# search hints, never as absolute "=<path>" entries. SCRATCH=scratch/$(basename "$0" .sh) READELF=${READELF:-readelf} PATCHELF=$(readlink -f "../src/patchelf") @@ -11,46 +12,93 @@ cp libfoo.so "${SCRATCH}/libs/" +here=$(pwd) +libs="${here}/${SCRATCH}/libs" + descriptor() { ${READELF} -p .note.nixos.ldcache "$1" } -cp main "${SCRATCH}/main-origin" +# Sets the run path on a fresh copy of main, builds the cache, and leaves the +# descriptor dump in $d for the expect_* helpers. +make_cached() { + cp main "$1" + ${PATCHELF} --set-rpath "$2" "$1" + ${PATCHELF} --build-resolution-cache "$1" + d=$(descriptor "$1") + echo "$d" +} + +expect_entry() { + if ! echo "$d" | grep -qF "$1"; then + echo "FAIL: $2" + exit 1 + fi +} + +expect_no_entry() { + if echo "$d" | grep -qF "$1"; then + echo "FAIL: $2" + exit 1 + fi +} + # $ORIGIN is a literal loader token; it must reach patchelf unexpanded. # shellcheck disable=SC2016 -${PATCHELF} --set-rpath '$ORIGIN/libs' "${SCRATCH}/main-origin" -${PATCHELF} --build-resolution-cache "${SCRATCH}/main-origin" - -d=$(descriptor "${SCRATCH}/main-origin") -echo "$d" +make_cached "${SCRATCH}/main-origin" '$ORIGIN/libs' # shellcheck disable=SC2016 -if ! echo "$d" | grep -qF '?$ORIGIN/libs'; then - echo "FAIL: \$ORIGIN run path was not recorded as a '?' search hint" - exit 1 -fi +expect_entry '?$ORIGIN/libs' "\$ORIGIN run path was not recorded as a '?' search hint" # shellcheck disable=SC2016 -if echo "$d" | grep -qF '=$ORIGIN/libs'; then - echo "FAIL: \$ORIGIN run path was wrongly baked into an absolute '=' path" - exit 1 -fi +expect_no_entry '=$ORIGIN/libs' "\$ORIGIN run path was wrongly baked into an absolute '=' path" -# libfoo.so is present here, so without the hwcaps guard it would resolve to an -# absolute "=path"; the guard must force a "?" hint regardless. +# libfoo.so is present here, so the hwcaps guard must force a "?" hint anyway. mkdir -p "${SCRATCH}/hw/glibc-hwcaps" cp libfoo.so "${SCRATCH}/hw/" -cp main "${SCRATCH}/main-hwcaps" -${PATCHELF} --set-rpath "$(pwd)/${SCRATCH}/hw" "${SCRATCH}/main-hwcaps" -${PATCHELF} --build-resolution-cache "${SCRATCH}/main-hwcaps" - -d=$(descriptor "${SCRATCH}/main-hwcaps") -echo "$d" -if ! echo "$d" | grep -qF "?$(pwd)/${SCRATCH}/hw"; then - echo "FAIL: glibc-hwcaps directory was not recorded as a '?' search hint" - exit 1 -fi -if echo "$d" | grep -qF "=$(pwd)/${SCRATCH}/hw/libfoo.so"; then - echo "FAIL: library under a glibc-hwcaps dir was wrongly resolved to a path" - exit 1 +make_cached "${SCRATCH}/main-hwcaps" "${here}/${SCRATCH}/hw" +expect_entry "?${here}/${SCRATCH}/hw" \ + "glibc-hwcaps directory was not recorded as a '?' search hint" +expect_no_entry "=${here}/${SCRATCH}/hw/libfoo.so" \ + "library under a glibc-hwcaps dir was wrongly resolved to a path" + +# An empty component is the run-time current directory: a bare "?" hint. +make_cached "${SCRATCH}/main-cwd" ":${libs}" +expect_entry "?:=${libs}/libfoo.so" \ + "empty run-path component was not recorded as a '?' hint before the exact entry" + +# A relative component must not be baked in against patchelf's own cwd. +make_cached "${SCRATCH}/main-rel" "relative/dir:${libs}" +expect_entry "?relative/dir:=${libs}/libfoo.so" \ + "relative run-path component was not recorded as a '?' search hint" +expect_no_entry "=relative/dir/libfoo.so" \ + "relative run-path component was wrongly baked into an '=' path" + +# An absent directory may be populated at run time (e.g. /run/opengl-driver/lib +# in a build sandbox): keep it as a "?" hint. +make_cached "${SCRATCH}/main-missing" "${here}/${SCRATCH}/does-not-exist:${libs}" +expect_entry "?${here}/${SCRATCH}/does-not-exist:=${libs}/libfoo.so" \ + "missing run-path directory was not recorded as a '?' hint before the exact entry" + +# A trailing empty component ("libs:") is a final CWD search position: kept as +# a trailing "?" hint, not dropped by the splitter. +make_cached "${SCRATCH}/main-cwd-trailing" "${libs}:" +expect_entry "=${libs}/libfoo.so:?" \ + "trailing empty run-path component was not recorded as a trailing '?' hint" + +# A plain-file entry is not a searchable directory; keep it as a "?" hint. +touch "${SCRATCH}/not-a-dir" +make_cached "${SCRATCH}/main-notdir" "${here}/${SCRATCH}/not-a-dir:${libs}" +expect_entry "?${here}/${SCRATCH}/not-a-dir:=${libs}/libfoo.so" \ + "plain-file run-path entry was not recorded as a '?' hint before the exact entry" + +# A directory unsearchable by the patching user may be readable at run time: +# keep it as a "?" hint. Skip as root, which ignores directory permissions. +if [ "$(id -u)" != 0 ]; then + mkdir -p "${SCRATCH}/no-access" + chmod 000 "${SCRATCH}/no-access" + make_cached "${SCRATCH}/main-noaccess" "${here}/${SCRATCH}/no-access:${libs}" + chmod 700 "${SCRATCH}/no-access" + expect_entry "?${here}/${SCRATCH}/no-access:=${libs}/libfoo.so" \ + "unsearchable run-path directory was not recorded as a '?' hint before the exact entry" fi echo "PASS" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/patchelf-0.19.0/version new/patchelf-0.19.1/version --- old/patchelf-0.19.0/version 2026-06-26 17:22:02.000000000 +0200 +++ new/patchelf-0.19.1/version 2026-07-06 23:38:03.000000000 +0200 @@ -1 +1 @@ -0.19.0 +0.19.1
