os/linux/elf: bump to typed: strict

Also, clean up an unused method (`elf_parser`) from a previous conflict
resolution.

Co-authored-by: Mike McQuaid <mike@mikemcquaid.com>
This commit is contained in:
Ruoyu Zhong 2025-08-11 22:46:31 +08:00
parent a0d01bc7c4
commit 26021c9e36
No known key found for this signature in database

View File

@ -1,4 +1,4 @@
# typed: true # rubocop:todo Sorbet/StrictSigil # typed: strict
# frozen_string_literal: true # frozen_string_literal: true
require "os/linux/ld" require "os/linux/ld"
@ -44,7 +44,8 @@ module ELFShim
requires_ancestor { Pathname } requires_ancestor { Pathname }
def initialize(*args) sig { params(path: T.anything).void }
def initialize(path)
@elf = T.let(nil, T.nilable(T::Boolean)) @elf = T.let(nil, T.nilable(T::Boolean))
@arch = T.let(nil, T.nilable(Symbol)) @arch = T.let(nil, T.nilable(Symbol))
@elf_type = T.let(nil, T.nilable(Symbol)) @elf_type = T.let(nil, T.nilable(Symbol))
@ -56,10 +57,12 @@ module ELFShim
super super
end end
sig { params(offset: Integer).returns(Integer) }
def read_uint8(offset) def read_uint8(offset)
read(1, offset).unpack1("C") read(1, offset).unpack1("C")
end end
sig { params(offset: Integer).returns(Integer) }
def read_uint16(offset) def read_uint16(offset)
read(2, offset).unpack1("v") read(2, offset).unpack1("v")
end end
@ -90,6 +93,7 @@ module ELFShim
end end
end end
sig { params(wanted_arch: Symbol).returns(T::Boolean) }
def arch_compatible?(wanted_arch) def arch_compatible?(wanted_arch)
return true unless elf? return true unless elf?
@ -110,10 +114,12 @@ module ELFShim
end end
end end
sig { returns(T::Boolean) }
def dylib? def dylib?
elf_type == :dylib elf_type == :dylib
end end
sig { returns(T::Boolean) }
def binary_executable? def binary_executable?
elf_type == :executable elf_type == :executable
end end
@ -127,6 +133,7 @@ module ELFShim
# An array of runtime search path entries, such as: # An array of runtime search path entries, such as:
# ["/lib", "/usr/lib", "/usr/local/lib"] # ["/lib", "/usr/lib", "/usr/local/lib"]
sig { returns(T::Array[String]) }
def rpaths def rpaths
Array(rpath&.split(":")) Array(rpath&.split(":"))
end end
@ -136,16 +143,13 @@ module ELFShim
metadata.interpreter metadata.interpreter
end end
sig { params(interpreter: T.nilable(String), rpath: T.nilable(String)).void }
def patch!(interpreter: nil, rpath: nil) def patch!(interpreter: nil, rpath: nil)
return if interpreter.blank? && rpath.blank? return if interpreter.blank? && rpath.blank?
save_using_patchelf_rb interpreter, rpath save_using_patchelf_rb interpreter, rpath
end end
def elf_parser
@elf_parser ||= patchelf_patcher.elf
end
sig { returns(T::Boolean) } sig { returns(T::Boolean) }
def dynamic_elf? def dynamic_elf?
metadata.dynamic_elf? metadata.dynamic_elf?
@ -186,20 +190,21 @@ module ELFShim
@path = T.let(path, ELFShim) @path = T.let(path, ELFShim)
@dylibs = T.let(nil, T.nilable(T::Array[String])) @dylibs = T.let(nil, T.nilable(T::Array[String]))
@dylib_id = T.let(nil, T.nilable(String)) @dylib_id = T.let(nil, T.nilable(String))
@needed = T.let([], T::Array[String])
dynamic_segment = patcher.elf.segment_by_type(:dynamic) dynamic_segment = patcher.elf.segment_by_type(:dynamic)
@dynamic_elf = dynamic_segment.present? @dynamic_elf = T.let(dynamic_segment.present?, T::Boolean)
@dylib_id, @needed = if @dynamic_elf @dylib_id, @needed = if @dynamic_elf
[patcher.soname, patcher.needed] [patcher.soname, patcher.needed]
else else
[nil, []] [nil, []]
end end
@interpreter = patcher.interpreter @interpreter = T.let(patcher.interpreter, T.nilable(String))
@rpath = patcher.runpath || patcher.rpath @rpath = T.let(patcher.runpath || patcher.rpath, T.nilable(String))
@section_names = patcher.elf.sections.map(&:name).compact_blank @section_names = T.let(patcher.elf.sections.map(&:name).compact_blank, T::Array[String])
@dt_flags_1 = dynamic_segment&.tag_by_type(:flags_1)&.value @dt_flags_1 = T.let(dynamic_segment&.tag_by_type(:flags_1)&.value, T.nilable(Integer))
end end
sig { returns(T::Array[String]) } sig { returns(T::Array[String]) }
@ -209,7 +214,9 @@ module ELFShim
private private
sig { params(basename: String).returns(Pathname) }
def find_full_lib_path(basename) def find_full_lib_path(basename)
basename = Pathname(basename)
local_paths = rpath&.split(":") local_paths = rpath&.split(":")
# Search for dependencies in the runpath/rpath first # Search for dependencies in the runpath/rpath first
@ -257,6 +264,7 @@ module ELFShim
end end
private_constant :Metadata private_constant :Metadata
sig { params(new_interpreter: T.nilable(String), new_rpath: T.nilable(String)).void }
def save_using_patchelf_rb(new_interpreter, new_rpath) def save_using_patchelf_rb(new_interpreter, new_rpath)
patcher = patchelf_patcher patcher = patchelf_patcher
patcher.interpreter = new_interpreter if new_interpreter.present? patcher.interpreter = new_interpreter if new_interpreter.present?
@ -267,6 +275,7 @@ module ELFShim
# Don't cache the patcher; it keeps the ELF file open so long as it is alive. # Don't cache the patcher; it keeps the ELF file open so long as it is alive.
# Instead, for read-only access to the ELF file's metadata, fetch it and cache # Instead, for read-only access to the ELF file's metadata, fetch it and cache
# it with {Metadata}. # it with {Metadata}.
sig { returns(::PatchELF::Patcher) }
def patchelf_patcher def patchelf_patcher
require "patchelf" require "patchelf"
::PatchELF::Patcher.new to_s, on_error: :silent ::PatchELF::Patcher.new to_s, on_error: :silent
@ -278,11 +287,13 @@ module ELFShim
end end
private :metadata private :metadata
sig { returns(T.nilable(String)) }
def dylib_id def dylib_id
metadata.dylib_id metadata.dylib_id
end end
def dynamically_linked_libraries(*) sig { params(except: Symbol, resolve_variable_references: T::Boolean).returns(T::Array[String]) }
def dynamically_linked_libraries(except: :none, resolve_variable_references: true)
metadata.dylibs metadata.dylibs
end end
end end