[DRE-maint] Bug#1114552: ruby-sys-filesystem: does not work and causes crash on s390x

Aurelien Jarno aurel32 at debian.org
Sun Sep 14 21:35:17 BST 2025


control: tag -1 + pending

Dear maintainer,

On 2025-09-06 22:33, Aurelien Jarno wrote:
> Source: ruby-sys-filesystem
> Version: 1.4.4-1
> Severity: grave
> Tags: upstream
> Justification: renders package unusable
> X-Debbugs-Cc: debian-s390 at lists.debian.org, dsa at debian.org
> User: debian-s390 at lists.debian.org
> Usertags: s390x
> Control: affects -1 facter
> 
> Hi,
> 
> Following the upgrade of ruby-sys-filesystem from bookworm (1.4.3-1) to
> trixie (1.4.4-1), ruby-sys-filesystem causes facter to crash:
> 
> | # facter
> | malloc(): invalid size (unsorted)
> | Aborted
> 
> As pointed out by Chris Hofstaedtler, upstream has changed the method to
> detect the host bitness, and use the corresponding statvfs structure
> through libffi. It now assumes that all 64-bit architectures have a "64"
> in there architecture name, which is not true for s390x (and also for
> alpha in ports). This causes the crash.
> 
> >From a quick search it seems a better way would be to look at the size
> of a pointer, but I am not a ruby expert at all:
> 
> | [nil].pack('p').size == 8

As the bug has been fixed upstream (thanks Chris for reporting it 
there), I have backported the patch to the debian package. I have
uploaded the result to DELAYED/2, you will find the diff of the NMU 
attached.

Please feel free to ask me to cancel the NMU or delay it further.

Regards
Aurelien

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
aurelien at aurel32.net                     http://aurel32.net
-------------- next part --------------
diff -Nru ruby-sys-filesystem-1.4.4/debian/changelog ruby-sys-filesystem-1.4.4/debian/changelog
--- ruby-sys-filesystem-1.4.4/debian/changelog	2023-11-22 05:56:59.000000000 +0100
+++ ruby-sys-filesystem-1.4.4/debian/changelog	2025-09-14 21:54:24.000000000 +0200
@@ -1,3 +1,11 @@
+ruby-sys-filesystem (1.4.4-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * Backport upstream PR#82 to fix linux64 detection fails on s390x and alpha
+    (Closes: #1114552).
+
+ -- Aurelien Jarno <aurel32 at debian.org>  Sun, 14 Sep 2025 21:54:24 +0200
+
 ruby-sys-filesystem (1.4.4-1) unstable; urgency=medium
 
   * Team upload.
diff -Nru ruby-sys-filesystem-1.4.4/debian/patches/linux64-detection-pr82.patch ruby-sys-filesystem-1.4.4/debian/patches/linux64-detection-pr82.patch
--- ruby-sys-filesystem-1.4.4/debian/patches/linux64-detection-pr82.patch	1970-01-01 01:00:00.000000000 +0100
+++ ruby-sys-filesystem-1.4.4/debian/patches/linux64-detection-pr82.patch	2025-09-14 21:54:24.000000000 +0200
@@ -0,0 +1,265 @@
+Description: Fix linux64 detection fails on s390x and alpha
+Origin: upstream, https://github.com/djberg96/sys-filesystem/commit/5a3416808e767d0a094c8dd0dc8641f7ff4b7829
+Bug: https://github.com/djberg96/sys-filesystem/issues/81
+Bug-Debian: https://bugs.debian.org/1114552
+Reviewed-by: Aurelien Jarno <aurel32 at debian.org>
+Last-Update: 2025-09-14
+
+diff --git a/lib/sys/unix/sys/filesystem/functions.rb b/lib/sys/unix/sys/filesystem/functions.rb
+index 685b388..e8738b3 100644
+--- a/lib/sys/unix/sys/filesystem/functions.rb
++++ b/lib/sys/unix/sys/filesystem/functions.rb
+@@ -16,7 +16,7 @@ def self.linux64?
+             ENV_JAVA['sun.arch.data.model'].to_i == 64
+         else
+           RbConfig::CONFIG['host_os'] =~ /linux/i &&
+-            (RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/)
++            (RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/ || [nil].pack('P').size == 8)
+         end
+       end
+ 
+diff --git a/lib/sys/unix/sys/filesystem/structs.rb b/lib/sys/unix/sys/filesystem/structs.rb
+index a055190..46019e6 100644
+--- a/lib/sys/unix/sys/filesystem/structs.rb
++++ b/lib/sys/unix/sys/filesystem/structs.rb
+@@ -28,7 +28,7 @@ def self.linux64?
+             ENV_JAVA['sun.arch.data.model'].to_i == 64
+           else
+             RbConfig::CONFIG['host_os'] =~ /linux/i &&
+-              (RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/)
++              (RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/ || [nil].pack('P').size == 8)
+           end
+         end
+ 
+@@ -155,7 +155,7 @@ def self.linux64?
+             ENV_JAVA['sun.arch.data.model'].to_i == 64
+           else
+             RbConfig::CONFIG['host_os'] =~ /linux/i &&
+-              (RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/)
++              (RbConfig::CONFIG['arch'] =~ /64/ || RbConfig::CONFIG['DEFS'] =~ /64/ || [nil].pack('P').size == 8)
+           end
+         end
+ 
+diff --git a/spec/sys_filesystem_unix_spec.rb b/spec/sys_filesystem_unix_spec.rb
+index d9a5ec7..9419b1a 100644
+--- a/spec/sys_filesystem_unix_spec.rb
++++ b/spec/sys_filesystem_unix_spec.rb
+@@ -524,4 +524,218 @@
+       expect{ described_class.stat('/whatever') }.to raise_error(Sys::Filesystem::Error, msg)
+     end
+   end
++
++  describe 'linux64? method' do
++    let(:functions_class) { Sys::Filesystem::Functions }
++
++    # Helper method to test linux64? with mocked config
++    def test_linux64_with_config(host_os, pointer_size, ruby_platform = nil, java_arch = nil)
++      # Mock RbConfig::CONFIG
++      allow(RbConfig::CONFIG).to receive(:[]).and_call_original
++      allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return(host_os)
++
++      # When running under JRuby, we need to handle it differently
++      if RUBY_PLATFORM == 'java'
++        # Under JRuby, always mock ENV_JAVA since that's the path the code will take
++        if java_arch
++          # This is a JRuby-specific test
++          allow(ENV_JAVA).to receive(:[]).with('sun.arch.data.model').and_return(java_arch.to_s)
++        else
++          # This is meant to test regular Ruby logic, but under JRuby we need to mock ENV_JAVA
++          # to make it take the "regular Ruby" path by returning nil/empty
++          expected_arch = pointer_size == 8 ? '64' : '32'
++          allow(ENV_JAVA).to receive(:[]).with('sun.arch.data.model').and_return(expected_arch)
++        end
++      else
++        # Running under regular Ruby
++        # Determine arch and DEFS based on host_os for the new multi-check approach
++        if pointer_size == 8
++          # For 64-bit systems, make arch contain "64"
++          arch_value = host_os.include?('64') ? host_os : host_os + '64'
++          defs_value = '-DSOMETHING=1'
++        else
++          # For 32-bit systems, ensure neither arch nor DEFS contain "64"
++          arch_value = host_os.gsub(/64/, '32')
++          defs_value = '-DSOMETHING=1'
++        end
++
++        allow(RbConfig::CONFIG).to receive(:[]).with('arch').and_return(arch_value)
++        allow(RbConfig::CONFIG).to receive(:[]).with('DEFS').and_return(defs_value)
++
++        if ruby_platform == 'java'
++          # Mock RUBY_PLATFORM for JRuby tests
++          stub_const('RUBY_PLATFORM', 'java')
++
++          # Mock ENV_JAVA for JRuby
++          env_java_mock = double('ENV_JAVA')
++          allow(env_java_mock).to receive(:[]).with('sun.arch.data.model').and_return(java_arch.to_s)
++          stub_const('ENV_JAVA', env_java_mock)
++        else
++          # Mock the pack method for regular Ruby (last resort check)
++          packed_data = 'x' * pointer_size
++          allow_any_instance_of(Array).to receive(:pack).with('P').and_return(packed_data)
++        end
++      end
++
++      functions_class.send(:linux64?)
++    end
++
++    context 'with different Linux distributions on 64-bit architectures' do
++      let(:linux_distros) do
++        {
++          'x86_64-linux-gnu' => 'Ubuntu/Debian x86_64',
++          'x86_64-pc-linux-gnu' => 'Generic x86_64 Linux',
++          'aarch64-linux-gnu' => 'ARM64 (Raspberry Pi 4, AWS Graviton)',
++          's390x-linux-gnu' => 'IBM Z mainframe',
++          'powerpc64le-linux-gnu' => 'POWER8/9 little-endian',
++          'powerpc64-linux-gnu' => 'POWER8/9 big-endian',
++          'mips64el-linux-gnuabi64' => 'MIPS64 little-endian',
++          'alpha-linux-gnu' => 'DEC Alpha',
++          'sparc64-linux-gnu' => 'SPARC64',
++          'riscv64-linux-gnu' => 'RISC-V 64-bit'
++        }
++      end
++
++      it 'returns true for 64-bit Linux systems' do
++        linux_distros.each do |host_os, description|
++          result = test_linux64_with_config(host_os, 8)
++          expect(result).to be_truthy, "Expected linux64? to return true for #{host_os} (#{description})"
++        end
++      end
++    end
++
++    context 'with different Linux distributions on 32-bit architectures' do
++      let(:linux_32bit_distros) do
++        {
++          'i386-linux-gnu' => '32-bit x86',
++          'i486-linux-gnu' => '32-bit x86',
++          'i586-linux-gnu' => '32-bit x86',
++          'i686-linux-gnu' => '32-bit x86',
++          'arm-linux-gnueabihf' => 'ARM 32-bit hard-float',
++          'armv7l-linux-gnueabihf' => 'ARMv7 32-bit',
++          'mips-linux-gnu' => 'MIPS 32-bit',
++          'mipsel-linux-gnu' => 'MIPS 32-bit little-endian',
++          'powerpc-linux-gnu' => 'PowerPC 32-bit',
++          's390-linux-gnu' => 'IBM S/390 32-bit'
++        }
++      end
++
++      it 'returns false for 32-bit Linux systems' do
++        linux_32bit_distros.each do |host_os, description|
++          result = test_linux64_with_config(host_os, 4)
++          expect(result).to be_falsey, "Expected linux64? to return false for #{host_os} (#{description})"
++        end
++      end
++    end
++
++    context 'with non-Linux operating systems' do
++      let(:non_linux_os) do
++        {
++          'darwin21.6.0' => 'macOS',
++          'freebsd13.1' => 'FreeBSD',
++          'openbsd7.2' => 'OpenBSD',
++          'netbsd9.3' => 'NetBSD',
++          'dragonfly6.4' => 'DragonFlyBSD',
++          'solaris2.11' => 'Solaris',
++          'aix7.2.0.0' => 'AIX',
++          'mingw32' => 'Windows MSYS2',
++          'cygwin' => 'Cygwin'
++        }
++      end
++
++      it 'returns false for non-Linux systems regardless of architecture' do
++        non_linux_os.each do |host_os, description|
++          # Test both 32-bit and 64-bit scenarios
++          [4, 8].each do |pointer_size|
++            result = test_linux64_with_config(host_os, pointer_size)
++            expect(result).to be_falsey,
++              "Expected linux64? to return false for #{host_os} (#{description}) with #{pointer_size * 8}-bit pointers"
++          end
++        end
++      end
++    end
++
++    context 'with JRuby on different platforms' do
++      it 'returns true for 64-bit Linux on JRuby' do
++        result = test_linux64_with_config('x86_64-linux-gnu', nil, 'java', 64)
++        expect(result).to be_truthy
++      end
++
++      it 'returns false for 32-bit Linux on JRuby' do
++        result = test_linux64_with_config('i386-linux-gnu', nil, 'java', 32)
++        expect(result).to be_falsey
++      end
++
++      it 'returns false for non-Linux systems on JRuby' do
++        result = test_linux64_with_config('darwin21.6.0', nil, 'java', 64)
++        expect(result).to be_falsey
++      end
++    end
++
++    context 'edge cases' do
++      it 'handles case-insensitive Linux detection' do
++        ['LINUX-gnu', 'Linux-gnu', 'linux-GNU'].each do |host_os|
++          result = test_linux64_with_config(host_os, 8)
++          expect(result).to be_truthy, "Expected linux64? to handle case-insensitive matching for #{host_os}"
++        end
++      end
++
++      it 'handles partial Linux matches in host_os string' do
++        ['some-linux-variant', 'embedded-linux-system', 'custom-linux-build'].each do |host_os|
++          result = test_linux64_with_config(host_os, 8)
++          expect(result).to be_truthy, "Expected linux64? to match partial Linux strings for #{host_os}"
++        end
++      end
++    end
++
++    context 'multi-check priority order', unless: RUBY_PLATFORM == 'java' do
++      it 'uses arch check first when arch contains 64' do
++        allow(RbConfig::CONFIG).to receive(:[]).and_call_original
++        allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return('x86_64-linux-gnu')
++        allow(RbConfig::CONFIG).to receive(:[]).with('arch').and_return('x86_64-linux')
++        allow(RbConfig::CONFIG).to receive(:[]).with('DEFS').and_return('')
++
++        # Should not need to call pack method since arch check succeeds
++        expect_any_instance_of(Array).not_to receive(:pack)
++
++        expect(functions_class.send(:linux64?)).to be_truthy
++      end
++
++      it 'uses DEFS check when arch does not contain 64 but DEFS does' do
++        allow(RbConfig::CONFIG).to receive(:[]).and_call_original
++        allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return('special-linux-gnu')
++        allow(RbConfig::CONFIG).to receive(:[]).with('arch').and_return('special-linux')
++        allow(RbConfig::CONFIG).to receive(:[]).with('DEFS').and_return('-D__LP64__=1')
++
++        # Should not need to call pack method since DEFS check succeeds
++        expect_any_instance_of(Array).not_to receive(:pack)
++
++        expect(functions_class.send(:linux64?)).to be_truthy
++      end
++
++      it 'falls back to pack method when neither arch nor DEFS contain 64' do
++        allow(RbConfig::CONFIG).to receive(:[]).and_call_original
++        allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return('custom-linux-gnu')
++        allow(RbConfig::CONFIG).to receive(:[]).with('arch').and_return('custom-linux')
++        allow(RbConfig::CONFIG).to receive(:[]).with('DEFS').and_return('-DSOMETHING=1')
++
++        # Should call pack method as last resort
++        allow_any_instance_of(Array).to receive(:pack).with('P').and_return('12345678')
++
++        expect(functions_class.send(:linux64?)).to be_truthy
++      end
++
++      it 'returns false when all checks fail on 32-bit' do
++        allow(RbConfig::CONFIG).to receive(:[]).and_call_original
++        allow(RbConfig::CONFIG).to receive(:[]).with('host_os').and_return('custom-linux-gnu')
++        allow(RbConfig::CONFIG).to receive(:[]).with('arch').and_return('custom-linux')
++        allow(RbConfig::CONFIG).to receive(:[]).with('DEFS').and_return('-DSOMETHING=1')
++
++        # Pack method returns 4 bytes (32-bit)
++        allow_any_instance_of(Array).to receive(:pack).with('P').and_return('1234')
++
++        expect(functions_class.send(:linux64?)).to be_falsey
++      end
++    end
++  end
+ end
diff -Nru ruby-sys-filesystem-1.4.4/debian/patches/series ruby-sys-filesystem-1.4.4/debian/patches/series
--- ruby-sys-filesystem-1.4.4/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
+++ ruby-sys-filesystem-1.4.4/debian/patches/series	2025-09-14 21:54:24.000000000 +0200
@@ -0,0 +1 @@
+linux64-detection-pr82.patch


More information about the Pkg-ruby-extras-maintainers mailing list