Bug #7040

gem install で特定の gem がインストールできない

Added by Hiroshi SHIBATA almost 3 years ago. Updated over 2 years ago.

[ruby-dev:<unknown>]
Status:Closed
Priority:Normal
Assignee:Tomoyuki Chikanaga
ruby -v:ruby 2.0.0dev (2012-09-20 trunk 36993) [x86_64-darwin12.2.0] Backport:

Description

trunk で特定の gem(例えば libv8等)をインストールしようとすると必ず失敗してしまいます。

% gem i libv8
ERROR: While executing gem ... (Zlib::BufError)
buffer error

Twitter 上で nagachika さんから Zlib の GVL 対応?が原因ではないかとコメントを頂きましたが、上記のエラー表示以降は調査しきれていません。

zlib_inflate_buf_error.patch Magnifier (634 Bytes) Tomoyuki Chikanaga, 10/08/2012 12:29 AM

Associated revisions

Revision 37119
Added by Tomoyuki Chikanaga over 2 years ago

  • ext/zlib/zlib.c (zstream_run_func): don't call inflate() when z->stream.avail_in == 0. it return Z_BUF_ERROR. but deflate() could be called with z->stream->avail_in == 0 because it has hidden buffer in z->stream->state (opaque structure). fix for gem install error. [Bug #7040]

Revision 37119
Added by Tomoyuki Chikanaga over 2 years ago

  • ext/zlib/zlib.c (zstream_run_func): don't call inflate() when z->stream.avail_in == 0. it return Z_BUF_ERROR. but deflate() could be called with z->stream->avail_in == 0 because it has hidden buffer in z->stream->state (opaque structure). fix for gem install error. [Bug #7040]

History

#1 Updated by Tomoyuki Chikanaga almost 3 years ago

  • Assignee set to Eric Hodel

Hello,

I'd like to switch to ruby-core, but I don't know how to do it on redmine...

Anyway, I've found that zstream_run_func() leaks Z_BUF_ERROR because inflate() could return Z_BUF_ERROR even when z->stream.avail_out > 0.
My tiny patch below prevent the exception, but I'm not confident at all it's right way to fix this issue.

diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index 6135e82..bcf289f 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -987,6 +987,7 @@ zstream_run_func(void *ptr)

    if (z->stream.avail_out > 0) {
        z->flags |= ZSTREAM_FLAG_IN_STREAM;
  • err = Z_OK; break; }

I think Eric (a.k.a drbrain) should have any idea, so I'll assign this ticket to him.

thakns,

#2 Updated by Tomoyuki Chikanaga over 2 years ago

Hello,

I've investigated this little more deeper.

If inflate() (aka z->func->run()) return under condition which z->stream.avail_in == z->stream.avail_out == 0, current zstream_run_func() call inflate() once more even though there's no input available. In that case inflate() return Z_BUF_ERROR.

However, deflate() have hidden input buffer in z->stream.state (opaque structure) and should be called even when z->stream.avail_in == 0 (while z->stream.avail_out == 0).

I think zstream_run_func() should break from while loop when zstream->avail_in == 0 only if z->func->run == inflate.

I will commit an attached patch tomorrow if there's no objection.

ruby-dev なので日本語でも。

もう少し調べてみました。

zstream_run_func() で inflate() (z->func->run()) がたまたま入出力のバッファがぴったり空/一杯になった (z->stream.avail_in == z->stream.avail_out == 0) で返ってきた時に、今の実装だとバッファを拡張して再度 inflate() を呼んでしまいます。zlib は入力が既にない状態で inflate() を呼ぶと Z_BUF_ERROR を返すようです。

ただ deflate() の場合は不可視な z->stream->state の構造体の中に隠れたバッファを持っているようで、z->stream.avail_in == 0 でももう一度 deflate() を呼ぶ必要がある場合があるようです。

添付したパッチのように z->func->run が inflate の時に限り z->stream.avail_in == 0 の時にも zstream_run_func() の while ループから抜けて、余分に inflate() (z->func->run())を呼ばないようにしてはどうかと思います。 make test-all は手元の環境では通りました。
実際に gem がインストールできない問題で困っているということなので、特に反対がなければ明日にでもコミットしておこうと思います。

#3 Updated by Tomoyuki Chikanaga over 2 years ago

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

This issue was solved with changeset r37119.
Hiroshi, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • ext/zlib/zlib.c (zstream_run_func): don't call inflate() when z->stream.avail_in == 0. it return Z_BUF_ERROR. but deflate() could be called with z->stream->avail_in == 0 because it has hidden buffer in z->stream->state (opaque structure). fix for gem install error. [Bug #7040]

Also available in: Atom PDF