diff options
-rw-r--r-- | ext/zlib/zlib.c | 32 | ||||
-rw-r--r-- | test/zlib/test_zlib.rb | 56 | ||||
-rw-r--r-- | version.h | 8 |
3 files changed, 91 insertions, 5 deletions
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 3b8e097da9..bfd55ffe34 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -530,6 +530,7 @@ struct zstream { unsigned long flags; VALUE buf; VALUE input; + VALUE mutex; z_stream stream; const struct zstream_funcs { int (*reset)(z_streamp); @@ -602,6 +603,7 @@ zstream_init(struct zstream *z, const struct zstream_funcs *func) z->flags = 0; z->buf = Qnil; z->input = Qnil; + z->mutex = rb_mutex_new(); z->stream.zalloc = zlib_mem_alloc; z->stream.zfree = zlib_mem_free; z->stream.opaque = Z_NULL; @@ -631,7 +633,9 @@ zstream_expand_buffer(struct zstream *z) rb_obj_reveal(z->buf, rb_cString); + rb_mutex_unlock(z->mutex); rb_protect(rb_yield, z->buf, &state); + rb_mutex_lock(z->mutex); z->buf = Qnil; zstream_expand_buffer_into(z, ZSTREAM_AVAIL_OUT_STEP_MAX); @@ -1025,7 +1029,7 @@ zstream_unblock_func(void *ptr) } static void -zstream_run(struct zstream *z, Bytef *src, long len, int flush) +zstream_run0(struct zstream *z, Bytef *src, long len, int flush) { struct zstream_run_args args; int err; @@ -1109,6 +1113,31 @@ loop: rb_jump_tag(args.jump_state); } +struct zstream_run_synchronized_args { + struct zstream *z; + Bytef *src; + long len; + int flush; +}; + +static VALUE +zstream_run_synchronized(VALUE value_arg) +{ + struct zstream_run_synchronized_args *run_args = (struct zstream_run_synchronized_args *)value_arg; + zstream_run0(run_args->z, run_args->src, run_args->len, run_args->flush); + return Qnil; +} + +static void +zstream_run(struct zstream *z, Bytef *src, long len, int flush) +{ + struct zstream_run_synchronized_args run_args; + run_args.z = z; + run_args.src = src; + run_args.len = len; + run_args.flush = flush; + rb_mutex_synchronize(z->mutex, zstream_run_synchronized, (VALUE)&run_args); +} static VALUE zstream_sync(struct zstream *z, Bytef *src, long len) { @@ -1154,6 +1183,7 @@ zstream_mark(void *p) struct zstream *z = p; rb_gc_mark(z->buf); rb_gc_mark(z->input); + rb_gc_mark(z->mutex); } static void diff --git a/test/zlib/test_zlib.rb b/test/zlib/test_zlib.rb index 7d703d15e4..e4baa44ecb 100644 --- a/test/zlib/test_zlib.rb +++ b/test/zlib/test_zlib.rb @@ -3,6 +3,7 @@ require 'test/unit' require 'stringio' require 'tempfile' +require 'securerandom' begin require 'zlib' @@ -443,6 +444,61 @@ if defined? Zlib assert_raise(Zlib::StreamError) { z.set_dictionary("foo") } z.close end + + def test_multithread_deflate + zd = Zlib::Deflate.new + s = "x" * 10000 + (0...10).map do |x| + Thread.new do + 1000.times { zd.deflate(s) } + end + end.each do |th| + th.join + end + ensure + zd&.finish + zd&.close + end + + def test_multithread_inflate + zi = Zlib::Inflate.new + s = Zlib.deflate("x" * 10000) + (0...10).map do |x| + Thread.new do + 1000.times { zi.inflate(s) } + end + end.each do |th| + th.join + end + ensure + zi&.finish + zi&.close + end + + def test_recursive_deflate + zd = Zlib::Deflate.new + s = SecureRandom.random_bytes(1024**2) + assert_raise(Zlib::BufError) do + zd.deflate(s) do + zd.deflate(s) + end + end + ensure + zd&.finish + zd&.close + end + + def test_recursive_inflate + zi = Zlib::Inflate.new + s = Zlib.deflate(SecureRandom.random_bytes(1024**2)) + assert_raise(Zlib::DataError) do + zi.inflate(s) do + zi.inflate(s) + end + end + ensure + zi&.close + end end class TestZlibGzipFile < Test::Unit::TestCase @@ -2,11 +2,11 @@ # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR #define RUBY_VERSION_TEENY 6 #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 209 +#define RUBY_PATCHLEVEL 210 -#define RUBY_RELEASE_YEAR 2021 -#define RUBY_RELEASE_MONTH 12 -#define RUBY_RELEASE_DAY 31 +#define RUBY_RELEASE_YEAR 2022 +#define RUBY_RELEASE_MONTH 3 +#define RUBY_RELEASE_DAY 5 #include "ruby/version.h" |