Skip to content

Commit 2397185

Browse files
MikeMcQuaidclaude
andcommitted
Fix file descriptor leak in Linux LD library path parsing
The library_paths method was using readlines which could leave file descriptors open due to Ruby's garbage collection behavior. When processing many packages during 'brew upgrade' or 'brew linkage', this caused "Too many open files" errors on Linux systems. Changes: - Replace readlines with explicit file.open block to ensure proper closure - Add caching to avoid repeatedly reading /etc/ld.so.conf during a session - Cache included files as well to optimize recursive include processing Fixes: #19866, #20302, #19177, #20223 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent f037420 commit 2397185

File tree

1 file changed

+24
-16
lines changed
  • Library/Homebrew/os/linux

1 file changed

+24
-16
lines changed

Library/Homebrew/os/linux/ld.rb

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,37 @@ def self.library_paths(conf_path = Pathname(sysconfdir)/"ld.so.conf")
5050
conf_file = Pathname(conf_path)
5151
return [] unless conf_file.exist?
5252

53+
@library_paths_cache ||= T.let({}, T.nilable(T::Hash[String, T::Array[String]]))
54+
cache_key = conf_file.to_s
55+
if (cached_library_path_contents = @library_paths_cache[cache_key])
56+
return cached_library_path_contents
57+
end
58+
5359
paths = Set.new
5460
directory = conf_file.realpath.dirname
5561

56-
conf_file.readlines.each do |line|
57-
# Remove comments and leading/trailing whitespace
58-
line.strip!
59-
line.sub!(/\s*#.*$/, "")
60-
61-
if line.start_with?(/\s*include\s+/)
62-
include_path = Pathname(line.sub(/^\s*include\s+/, "")).expand_path
63-
wildcard = include_path.absolute? ? include_path : directory/include_path
64-
65-
Dir.glob(wildcard.to_s).each do |include_file|
66-
paths += library_paths(include_file)
62+
conf_file.open("r") do |file|
63+
file.each_line do |line|
64+
# Remove comments and leading/trailing whitespace
65+
line.strip!
66+
line.sub!(/\s*#.*$/, "")
67+
68+
if line.start_with?(/\s*include\s+/)
69+
include_path = Pathname(line.sub(/^\s*include\s+/, "")).expand_path
70+
wildcard = include_path.absolute? ? include_path : directory/include_path
71+
72+
Dir.glob(wildcard.to_s).each do |include_file|
73+
paths += library_paths(include_file)
74+
end
75+
elsif line.empty?
76+
next
77+
else
78+
paths << line
6779
end
68-
elsif line.empty?
69-
next
70-
else
71-
paths << line
7280
end
7381
end
7482

75-
paths.to_a
83+
@library_paths_cache[cache_key] = paths.to_a
7684
end
7785
end
7886
end

0 commit comments

Comments
 (0)