Skip to content

Fix buf error on interrupt.#121

Merged
ioquatix merged 3 commits intoruby:masterfrom
samuel-williams-shopify:fix-buf-error-on-interrupt
Feb 27, 2026
Merged

Fix buf error on interrupt.#121
ioquatix merged 3 commits intoruby:masterfrom
samuel-williams-shopify:fix-buf-error-on-interrupt

Conversation

@samuel-williams-shopify
Copy link
Contributor

I think this fixes #57.

@samuel-williams-shopify
Copy link
Contributor Author

@ianks can you please take a look? You investigated this some years ago.

@samuel-williams-shopify
Copy link
Contributor Author

If you add this line:

        if (err != Z_OK) fprintf(stderr, "[ZLIB] zstream_run_try: Z_BUF_ERROR with avail_out > 0, err=%d interrupt=%d\n", err, args->interrupt);

(instead of err = Z_OK) and run one of the reproductions, you can see the issue manifesting:

~/D/r/zlib (fix-buf-error-on-interrupt) [1]> ./test.rb
[SIGINT]
........................................................................................................[SIGINT]
[ZLIB] zstream_run_try: Z_BUF_ERROR with avail_out > 0, err=-5 interrupt=0
./test.rb:17:in 'Zlib::Deflate#deflate': buffer error (Zlib::BufError)
  from ./test.rb:17:in 'block (2 levels) in <main>'
  from ./test.rb:15:in 'Integer#times'
  from ./test.rb:15:in 'block in <main>'
  from ./test.rb:13:in 'Kernel#fork'
  from ./test.rb:13:in '<main>'
✗ Bug reproduced: #<Process::Status: pid 11347 exit 1>

~/D/r/zlib (fix-buf-error-on-interrupt) [1]> ./test2.rb
[ZLIB] zstream_run_try: Z_BUF_ERROR with avail_out > 0, err=-5 interrupt=0
#<Thread:0x0000000104f6c8e0 ./test2.rb:11 run> terminated with exception (report_on_exception is true):
./test2.rb:13:in 'Zlib::GzipReader#initialize': buffer error (Zlib::BufError)
  from ./test2.rb:13:in 'block (2 levels) in <main>'
  from ./test2.rb:12:in 'Kernel#loop'
  from ./test2.rb:12:in 'block in <main>'
./test2.rb:18:in 'Thread#wakeup': killed thread (ThreadError)
  from ./test2.rb:18:in 'block in <main>'
  from ./test2.rb:17:in 'Kernel#loop'
  from ./test2.rb:17:in '<main>'

test.rb

#!/usr/bin/env ruby
# frozen_string_literal: true

# Simple test to reproduce signal interrupt bug
# Run: ruby test.rb

require 'zlib'
require 'securerandom'

z = Zlib::Deflate.new
trap('INT') { $stderr.puts "[SIGINT]" }

pid = fork do
  # Run deflate calls:
  1000.times do |i|
    data = SecureRandom.random_bytes(100)
    z.deflate(data, Zlib::SYNC_FLUSH)
    $stdout.write(".")
  end
end

# Send signals
5.times { |i| Process.kill('INT', pid); sleep 0.001 }

status = Process.wait2(pid)[1]
if status.success?
  puts "✓ Test passed"
  exit 0
else
  puts "✗ Bug reproduced: #{status.inspect}"
  exit 1
end

# ./test.rb:19:in 'Zlib::Deflate#deflate': buffer error (Zlib::BufError)
#   from ./test.rb:19:in 'block (2 levels) in <main>'
#   from ./test.rb:17:in 'Integer#times'
#   from ./test.rb:17:in 'block in <main>'
#   from ./test.rb:12:in 'Kernel#fork'
#   from ./test.rb:12:in '<main>'
# ✗ Bug reproduced!

test2.rb

#!/usr/bin/env ruby
# frozen_string_literal: true

require "securerandom"
require "stringio"
require "zlib"

content = SecureRandom.base64(5000)
gzipped = Zlib.gzip(content)

thr = Thread.new do
  loop do
    Zlib::GzipReader.new(StringIO.new(gzipped)).read
  end
end

loop do
  thr.wakeup
end

@samuel-williams-shopify samuel-williams-shopify force-pushed the fix-buf-error-on-interrupt branch 5 times, most recently from 1c2d991 to b59f0ee Compare February 26, 2026 06:55
@ioquatix
Copy link
Member

Okay, so I came to the same conclusion as everyone else, basically we are retrying on interrupt when we shouldn't. So I tightened up the condition. Not sure if there are other cases, but for sure we should not retry unless there is available input and available output space.

Copy link

@ianks ianks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ioquatix ioquatix merged commit c975060 into ruby:master Feb 27, 2026
70 checks passed
@samuel-williams-shopify samuel-williams-shopify deleted the fix-buf-error-on-interrupt branch February 27, 2026 02:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Thread#wakeup leads to Zlib::BufError

3 participants