linkage: display executables with missing rpath
An executable that links against @rpath-prefixed dylibs must include at least one runtime path. This will prevent issues like the one resolved in #91485. Caveats: 1. This won't find executables that have only recursive dylib dependencies with @rpath prefixes. 2. This makes no attempt to resolve @rpath, @executable_path or @loader_path dylibs, or to verify the correctness of any LC_RPATH entries, or to otherwise simulate dlopen logic. 3. Weakly-linked dylibs are still excluded from the search for broken linkage. The scope is narrow in order to focus on this particular problem. It is meant only as a sanity check.
This commit is contained in:
parent
96137bc19e
commit
caf310038f
@ -451,6 +451,11 @@ class Pathname
|
||||
def dylib?
|
||||
false
|
||||
end
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
def rpaths
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
require "extend/os/pathname"
|
||||
|
||||
@ -32,6 +32,7 @@ class LinkageChecker
|
||||
@unnecessary_deps = []
|
||||
@unwanted_system_dylibs = []
|
||||
@version_conflict_deps = []
|
||||
@executables_missing_rpaths = []
|
||||
|
||||
check_dylibs(rebuild_cache: rebuild_cache)
|
||||
end
|
||||
@ -46,6 +47,7 @@ class LinkageChecker
|
||||
display_items "Undeclared dependencies with linkage", @undeclared_deps
|
||||
display_items "Dependencies with no linkage", @unnecessary_deps
|
||||
display_items "Unwanted system libraries", @unwanted_system_dylibs
|
||||
display_items "Executables with missing rpath", @executables_missing_rpaths
|
||||
end
|
||||
|
||||
def display_reverse_output
|
||||
@ -69,11 +71,12 @@ class LinkageChecker
|
||||
display_items "Unwanted system libraries", @unwanted_system_dylibs, puts_output: puts_output
|
||||
display_items "Conflicting libraries", @version_conflict_deps, puts_output: puts_output
|
||||
display_items "Undeclared dependencies with linkage", @undeclared_deps, puts_output: puts_output if strict
|
||||
display_items "Executables with missing rpath", @executables_missing_rpaths, puts_output: puts_output
|
||||
end
|
||||
|
||||
sig { params(strict: T::Boolean).returns(T::Boolean) }
|
||||
def broken_library_linkage?(strict: false)
|
||||
issues = [@broken_deps, @unwanted_system_dylibs, @version_conflict_deps]
|
||||
issues = [@broken_deps, @unwanted_system_dylibs, @version_conflict_deps, @executables_missing_rpaths]
|
||||
issues << @undeclared_deps if strict
|
||||
[issues, unexpected_broken_dylibs, unexpected_present_dylibs].flatten.any?(&:present?)
|
||||
end
|
||||
@ -152,9 +155,18 @@ class LinkageChecker
|
||||
checked_dylibs = Set.new
|
||||
|
||||
keg_files_dylibs.each do |file, dylibs|
|
||||
file_has_any_rpath_dylibs = T.let(false, T::Boolean)
|
||||
dylibs.each do |dylib|
|
||||
@reverse_links[dylib] << file
|
||||
|
||||
# Binary executables that link @rpath-prefixed dylibs must include at
|
||||
# least one rpath in order to resolve it.
|
||||
if !file_has_any_rpath_dylibs && (dylib.start_with? "@rpath/")
|
||||
file_has_any_rpath_dylibs = true
|
||||
pathname = Pathname(file)
|
||||
@executables_missing_rpaths << file if pathname.binary_executable? && pathname.rpaths.empty?
|
||||
end
|
||||
|
||||
next if checked_dylibs.include? dylib
|
||||
|
||||
checked_dylibs << dylib
|
||||
|
||||
@ -86,12 +86,20 @@ module ELFShim
|
||||
elf_type == :executable
|
||||
end
|
||||
|
||||
# The runtime search path, such as:
|
||||
# "/lib:/usr/lib:/usr/local/lib"
|
||||
def rpath
|
||||
return @rpath if defined? @rpath
|
||||
|
||||
@rpath = rpath_using_patchelf_rb
|
||||
end
|
||||
|
||||
# An array of runtime search path entries, such as:
|
||||
# ["/lib", "/usr/lib", "/usr/local/lib"]
|
||||
def rpaths
|
||||
rpath.split(":")
|
||||
end
|
||||
|
||||
def interpreter
|
||||
return @interpreter if defined? @interpreter
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user