Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zlib::Reader: Reading to EOF deadlocks application #6575

Closed
z64 opened this issue Aug 20, 2018 · 4 comments · Fixed by #6610
Closed

Zlib::Reader: Reading to EOF deadlocks application #6575

z64 opened this issue Aug 20, 2018 · 4 comments · Fixed by #6610
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:stdlib

Comments

@z64
Copy link
Contributor

z64 commented Aug 20, 2018

Zlib::Reader can deadlock the application if you read to EOF:

require "zlib"

spawn do
  i = 0
  loop do
    puts "[#{i}] looping"
    i += 1
    sleep 1
  end
end

# Wait 3 sec to start
sleep 3

File.open("data.bin", "r") do |file|
  Zlib::Reader.new(file).gets_to_end
end
$ time cr run.cr
[0] looping                       
[1] looping                                      
[2] looping                                
^C                                                  
real    0m9.508s                      
user    0m3.162s                      
sys     0m3.205s

I've created https://github.com/z64/zlib-freeze which contains a sample data blob and the above code that demonstrates the deadlock, as well as an excerpt from lldb in README.md.

Background

I found this while implementing business logic of a websocket protocol that sends chunks of zlib-compressed data over multiple frames, where you buffer each frame received until a "end of flush" binary suffix is read; so you must use a single instance of Zlib::Reader throughout your connections lifetime over multiple frames. Trying to inflate a single blob (shown in the above repo) deadlocked the app.

I suspect the correct behavior here should be to raise an exception; as a workaround I'm infalting into a slice (reader.read(slice)) which will not exhibit this deadlock behavior.

@kostya
Copy link
Contributor

kostya commented Aug 20, 2018

when i use my static crystal analyze tool, i find one bug in zlib flate code, not sure it related here or not, or how to test it (just want to note it somewhere).
https://github.com/crystal-lang/crystal/blob/master/src/flate/reader.cr#L97

          ret = LibZ.inflateSetDictionary(pointerof(@stream), dict, dict.size)
          next if ret == LibZ::Error::OK

ret it Int, and compared with enum, this is always false.

@z64
Copy link
Contributor Author

z64 commented Aug 20, 2018

Interesting! Unfortunately I don't think that applies here, at least I'm pretty sure - I monkey patched read to correct that comparison, as well as a debug p! ret == LibZ::Error::OK.value before that line, and nothing was printed, and the example application from my OP still deadlocks.

@rdp
Copy link
Contributor

rdp commented Aug 26, 2018

wonder if related to #4650 ...

@z64
Copy link
Contributor Author

z64 commented Aug 26, 2018

Good call, maybe! 🙂

Reviewing the last few comments it seems like it may be, though the lldb inspections seem to be a bit different. Though what @RX14 said last in that thread sounds plausible. Either way, my zlib-freeze repo 100% reproduces (at least) this issue.. we just need someone who knows how to debug this further. I don't know where to go from here, but happy to dig further if someone points me in the right direction.

@asterite asterite added kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:stdlib labels Aug 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:stdlib
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants