msgpack 1.6.1 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e3e9d5536bdf4c127f51b0c7837af3a3e076003f903aae018ba1332d1eecaa8e
4
- data.tar.gz: c1f76401693a317b69bf37f8418e91f5a67dd77e74bd71668d321e0069b9ce7f
3
+ metadata.gz: c2caf680ff4cafade89a14da270f52528ba2a862cea237ad028ba27fa6a93e9b
4
+ data.tar.gz: 01d8cc906d925acbd32a88c22f6ace7f5534a0b447be1736ea58cfdf9abb85b6
5
5
  SHA512:
6
- metadata.gz: 18d189bec1b83c1e9252acaa82c3830728575a8222db0fe33fe3c1aa940734d4ee2c8a1991f2c38cef14ceccdde005ae4111df4884a8b43e4f0737e254ea719d
7
- data.tar.gz: 52a5080b4ec7e62309e60ce4a29d8daaf1e39c2b03c87e310236afe053d31c8f878f304eb029b10d89393af0c7646873b0745f51cb6fa88e1f5e421aaa64e7c5
6
+ metadata.gz: 48fcd12bfb13741d88a17e1a261cd742c903ba53cb1959a88b7083c2344817d90cfa898e775c136d785fbfcdd76be14b6dc5fc8ba3638a13ecabbb2d1387dbee
7
+ data.tar.gz: 310f3ea573cf41b15c47bc0033121496bd8ab7a723ef3667a96a38bc286feb79536ac5aeb8d27c3c71568149f93c8f36cc9ca8e050595e27ff87762cbccfe2dd
data/ChangeLog CHANGED
@@ -1,3 +1,17 @@
1
+ 2023-05-19 1.7.1:
2
+
3
+ * Fix JRuby 9.4 compatibility.
4
+ * Fix compilation on older compilers (gcc 4.x).
5
+ * Fix an infinite recursion issue when registering a Symbol type with a `nil` packer.
6
+
7
+ 2023-03-29 1.7.0:
8
+
9
+ * Fix a possible double-free issue when GC triggers inside `_msgpack_rmem_alloc2`.
10
+ * `Unpacker#feed` now always directly read in provided strings instead of copying content in its buffer.
11
+ * `Unpacker#feed` is now an alias of `Unpacker#feed_reference`.
12
+ * Implement `Factory::Pool#unpacker` and `Factory::Pool#packer` to allow for more precise serialization.
13
+ * Require Ruby 2.5+.
14
+
1
15
  2023-03-03 1.6.1:
2
16
 
3
17
  * Undefine `#clone` and `#dup` on `MessagePack::Buffer`, `MessagePack::Packer` and `MessagePack::Unpacker`.
data/README.md CHANGED
@@ -211,6 +211,33 @@ factory.register_type(
211
211
  factory.load(factory.dump(Point.new(12, 34))) # => #<struct Point x=12, y=34>
212
212
  ```
213
213
 
214
+ ## Pooling
215
+
216
+ Creating `Packer` and `Unpacker` objects is expensive. For best performance it is preferable to re-use these objects.
217
+
218
+ `MessagePack::Factory#pool` makes that easier:
219
+
220
+ ```ruby
221
+ factory = MessagePack::Factory.new
222
+ factory.register_type(
223
+ 0x01,
224
+ Point,
225
+ packer: ->(point, packer) {
226
+ packer.write(point.x)
227
+ packer.write(point.y)
228
+ },
229
+ unpacker: ->(unpacker) {
230
+ x = unpacker.read
231
+ y = unpacker.read
232
+ Point.new(x, y)
233
+ },
234
+ recursive: true,
235
+ )
236
+ pool = factory.pool(5) # The pool size should match the number of threads expected to use the factory concurrently.
237
+
238
+ pool.load(pool.dump(Point.new(12, 34))) # => #<struct Point x=12, y=34>
239
+ ```
240
+
214
241
  ## Buffer API
215
242
 
216
243
  MessagePack for Ruby provides a buffer API so that you can read or write data by hand, not via Packer or Unpacker API.
@@ -22,10 +22,10 @@ import org.jcodings.Encoding;
22
22
  @JRubyClass(name="MessagePack::Buffer")
23
23
  public class Buffer extends RubyObject {
24
24
  private static final long serialVersionUID = 8441244627425629412L;
25
- private IRubyObject io;
26
- private ByteBuffer buffer;
25
+ private transient IRubyObject io;
26
+ private transient ByteBuffer buffer;
27
27
  private boolean writeMode;
28
- private Encoding binaryEncoding;
28
+ private transient Encoding binaryEncoding;
29
29
 
30
30
  private static final int CACHE_LINE_SIZE = 64;
31
31
  private static final int ARRAY_HEADER_SIZE = 24;
@@ -141,11 +141,11 @@ public class ExtensionRegistry {
141
141
  }
142
142
 
143
143
  public boolean hasPacker() {
144
- return packerProc != null;
144
+ return packerProc != null && !packerProc.isNil();
145
145
  }
146
146
 
147
147
  public boolean hasUnpacker() {
148
- return unpackerProc != null;
148
+ return unpackerProc != null && !unpackerProc.isNil();
149
149
  }
150
150
 
151
151
  public IRubyObject getPackerProc() {
@@ -26,7 +26,7 @@ import static org.msgpack.jruby.Types.*;
26
26
  @JRubyClass(name="MessagePack::ExtensionValue")
27
27
  public class ExtensionValue extends RubyObject {
28
28
  private static final long serialVersionUID = 8451274621449322492L;
29
- private final Encoding binaryEncoding;
29
+ private transient final Encoding binaryEncoding;
30
30
 
31
31
  private RubyFixnum type;
32
32
  private RubyString payload;
@@ -26,8 +26,8 @@ import static org.jruby.runtime.Visibility.PRIVATE;
26
26
  @JRubyClass(name="MessagePack::Factory")
27
27
  public class Factory extends RubyObject {
28
28
  private static final long serialVersionUID = 8441284623445322492L;
29
- private final Ruby runtime;
30
- private ExtensionRegistry extensionRegistry;
29
+ private transient final Ruby runtime;
30
+ private transient ExtensionRegistry extensionRegistry;
31
31
  private boolean hasSymbolExtType;
32
32
  private boolean hasBigIntExtType;
33
33
 
@@ -82,6 +82,8 @@ public class Factory extends RubyObject {
82
82
 
83
83
  @JRubyMethod(name = "register_type", required = 2, optional = 1)
84
84
  public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args) {
85
+ testFrozen("MessagePack::Factory");
86
+
85
87
  Ruby runtime = ctx.runtime;
86
88
  IRubyObject type = args[0];
87
89
  IRubyObject mod = args[1];
@@ -91,10 +93,6 @@ public class Factory extends RubyObject {
91
93
 
92
94
  RubyHash options = null;
93
95
 
94
- if (isFrozen()) {
95
- throw runtime.newRuntimeError("can't modify frozen Factory");
96
- }
97
-
98
96
  if (args.length == 2) {
99
97
  packerArg = runtime.newSymbol("to_msgpack_ext");
100
98
  unpackerArg = runtime.newSymbol("from_msgpack_ext");
@@ -102,7 +100,13 @@ public class Factory extends RubyObject {
102
100
  if (args[args.length - 1] instanceof RubyHash) {
103
101
  options = (RubyHash) args[args.length - 1];
104
102
  packerArg = options.fastARef(runtime.newSymbol("packer"));
103
+ if (packerArg != null && packerArg.isNil()) {
104
+ packerArg = null;
105
+ }
105
106
  unpackerArg = options.fastARef(runtime.newSymbol("unpacker"));
107
+ if (unpackerArg != null && unpackerArg.isNil()) {
108
+ unpackerArg = null;
109
+ }
106
110
  IRubyObject optimizedSymbolsParsingArg = options.fastARef(runtime.newSymbol("optimized_symbols_parsing"));
107
111
  if (optimizedSymbolsParsingArg != null && optimizedSymbolsParsingArg.isTrue()) {
108
112
  throw runtime.newArgumentError("JRuby implementation does not support the optimized_symbols_parsing option");
@@ -149,7 +153,7 @@ public class Factory extends RubyObject {
149
153
 
150
154
  extensionRegistry.put(extModule, (int) typeId, recursive, packerProc, packerArg, unpackerProc, unpackerArg);
151
155
 
152
- if (extModule == runtime.getSymbol()) {
156
+ if (extModule == runtime.getSymbol() && !packerProc.isNil()) {
153
157
  hasSymbolExtType = true;
154
158
  }
155
159
 
@@ -28,12 +28,12 @@ import static org.jruby.runtime.Visibility.PRIVATE;
28
28
  @JRubyClass(name="MessagePack::Packer")
29
29
  public class Packer extends RubyObject {
30
30
  private static final long serialVersionUID = 8451274621499362492L;
31
- public ExtensionRegistry registry;
31
+ public transient ExtensionRegistry registry;
32
32
  private Buffer buffer;
33
- private Encoder encoder;
33
+ private transient Encoder encoder;
34
34
  private boolean hasSymbolExtType;
35
35
  private boolean hasBigintExtType;
36
- private Encoding binaryEncoding;
36
+ private transient Encoding binaryEncoding;
37
37
 
38
38
  public Packer(Ruby runtime, RubyClass type, ExtensionRegistry registry, boolean hasSymbolExtType, boolean hasBigintExtType) {
39
39
  super(runtime, type);
@@ -95,6 +95,8 @@ public class Packer extends RubyObject {
95
95
 
96
96
  @JRubyMethod(name = "register_type", required = 2, optional = 1)
97
97
  public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args, final Block block) {
98
+ testFrozen("MessagePack::Packer");
99
+
98
100
  Ruby runtime = ctx.runtime;
99
101
  IRubyObject type = args[0];
100
102
  IRubyObject mod = args[1];
@@ -126,7 +128,7 @@ public class Packer extends RubyObject {
126
128
 
127
129
  registry.put(extModule, (int) typeId, false, proc, arg, null, null);
128
130
 
129
- if (extModule == runtime.getSymbol()) {
131
+ if (extModule == runtime.getSymbol() && !proc.isNil()) {
130
132
  encoder.hasSymbolExtType = true;
131
133
  }
132
134
 
@@ -21,18 +21,17 @@ import org.jruby.runtime.ThreadContext;
21
21
  import org.jruby.anno.JRubyClass;
22
22
  import org.jruby.anno.JRubyMethod;
23
23
  import org.jruby.util.ByteList;
24
- import org.jruby.ext.stringio.StringIO;
25
24
 
26
25
  import static org.jruby.runtime.Visibility.PRIVATE;
27
26
 
28
27
  @JRubyClass(name="MessagePack::Unpacker")
29
28
  public class Unpacker extends RubyObject {
30
29
  private static final long serialVersionUID = 8451264671199362492L;
31
- private final ExtensionRegistry registry;
30
+ private transient final ExtensionRegistry registry;
32
31
 
33
- private IRubyObject stream;
34
- private IRubyObject data;
35
- private Decoder decoder;
32
+ private transient IRubyObject stream;
33
+ private transient IRubyObject data;
34
+ private transient Decoder decoder;
36
35
  private final RubyClass underflowErrorClass;
37
36
  private boolean symbolizeKeys;
38
37
  private boolean freeze;
@@ -129,6 +128,8 @@ public class Unpacker extends RubyObject {
129
128
 
130
129
  @JRubyMethod(name = "register_type", required = 1, optional = 2)
131
130
  public IRubyObject registerType(ThreadContext ctx, IRubyObject[] args, final Block block) {
131
+ testFrozen("MessagePack::Unpacker");
132
+
132
133
  Ruby runtime = ctx.runtime;
133
134
  IRubyObject type = args[0];
134
135
 
@@ -331,9 +332,7 @@ public class Unpacker extends RubyObject {
331
332
  @JRubyMethod(name = "stream=", required = 1)
332
333
  public IRubyObject setStream(ThreadContext ctx, IRubyObject stream) {
333
334
  RubyString str;
334
- if (stream instanceof StringIO) {
335
- str = stream.callMethod(ctx, "string").asString();
336
- } else if (stream instanceof RubyIO) {
335
+ if (stream instanceof RubyIO) {
337
336
  str = stream.callMethod(ctx, "read").asString();
338
337
  } else if (stream.respondsTo("read")) {
339
338
  str = stream.callMethod(ctx, "read").asString();
data/ext/msgpack/buffer.c CHANGED
@@ -19,10 +19,6 @@
19
19
  #include "buffer.h"
20
20
  #include "rmem.h"
21
21
 
22
- #ifndef HAVE_RB_STR_REPLACE
23
- static ID s_replace;
24
- #endif
25
-
26
22
  int msgpack_rb_encindex_utf8;
27
23
  int msgpack_rb_encindex_usascii;
28
24
  int msgpack_rb_encindex_ascii8bit;
@@ -40,10 +36,6 @@ void msgpack_buffer_static_init(void)
40
36
  msgpack_rb_encindex_ascii8bit = rb_ascii8bit_encindex();
41
37
 
42
38
  msgpack_rmem_init(&s_rmem);
43
-
44
- #ifndef HAVE_RB_STR_REPLACE
45
- s_replace = rb_intern("replace");
46
- #endif
47
39
  }
48
40
 
49
41
  void msgpack_buffer_static_destroy(void)
@@ -66,7 +58,11 @@ void msgpack_buffer_init(msgpack_buffer_t* b)
66
58
  static void _msgpack_buffer_chunk_destroy(msgpack_buffer_chunk_t* c)
67
59
  {
68
60
  if(c->mem != NULL) {
69
- if(!msgpack_rmem_free(&s_rmem, c->mem)) {
61
+ if(c->rmem) {
62
+ if(!msgpack_rmem_free(&s_rmem, c->mem)) {
63
+ rb_bug("Failed to free an rmem pointer, memory leak?");
64
+ }
65
+ } else {
70
66
  xfree(c->mem);
71
67
  }
72
68
  /* no needs to update rmem_owner because chunks will not be
@@ -330,14 +326,12 @@ static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE s
330
326
 
331
327
  void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
332
328
  {
333
- size_t length = RSTRING_LEN(string);
334
-
335
329
  if(b->io != Qnil) {
336
330
  msgpack_buffer_flush(b);
337
331
  if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
338
332
  rb_funcall(b->io, b->io_write_all_method, 1, string);
339
333
  } else {
340
- msgpack_buffer_append(b, RSTRING_PTR(string), length);
334
+ msgpack_buffer_append(b, RSTRING_PTR(string), RSTRING_LEN(string));
341
335
  }
342
336
  } else {
343
337
  _msgpack_buffer_append_reference(b, string);
@@ -349,6 +343,8 @@ static inline void* _msgpack_buffer_chunk_malloc(
349
343
  size_t required_size, size_t* allocated_size)
350
344
  {
351
345
  if(required_size <= MSGPACK_RMEM_PAGE_SIZE) {
346
+ c->rmem = true;
347
+
352
348
  if((size_t)(b->rmem_end - b->rmem_last) < required_size) {
353
349
  /* alloc new rmem page */
354
350
  *allocated_size = MSGPACK_RMEM_PAGE_SIZE;
@@ -379,6 +375,7 @@ static inline void* _msgpack_buffer_chunk_malloc(
379
375
  *allocated_size = required_size;
380
376
  void* mem = xmalloc(required_size);
381
377
  c->mem = mem;
378
+ c->rmem = false;
382
379
  return mem;
383
380
  }
384
381
 
data/ext/msgpack/buffer.h CHANGED
@@ -78,6 +78,7 @@ struct msgpack_buffer_chunk_t {
78
78
  void* mem;
79
79
  msgpack_buffer_chunk_t* next;
80
80
  VALUE mapped_string; /* RBString or NO_MAPPED_STRING */
81
+ bool rmem;
81
82
  };
82
83
 
83
84
  union msgpack_buffer_cast_block_t {
@@ -267,14 +268,7 @@ static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE str
267
268
  static inline size_t msgpack_buffer_append_string_reference(msgpack_buffer_t* b, VALUE string)
268
269
  {
269
270
  size_t length = RSTRING_LEN(string);
270
-
271
- if(length > MSGPACK_BUFFER_STRING_WRITE_REFERENCE_MINIMUM) {
272
- _msgpack_buffer_append_long_string(b, string);
273
-
274
- } else {
275
- msgpack_buffer_append(b, RSTRING_PTR(string), length);
276
- }
277
-
271
+ _msgpack_buffer_append_long_string(b, string);
278
272
  return length;
279
273
  }
280
274
 
@@ -479,7 +473,6 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
479
473
  result = rb_str_new(b->read_buffer, length);
480
474
  }
481
475
 
482
- #if STR_UMINUS_DEDUPE
483
476
  if (will_be_frozen) {
484
477
  #if STR_UMINUS_DEDUPE_FROZEN
485
478
  // Starting from MRI 2.8 it is preferable to freeze the string
@@ -491,7 +484,6 @@ static inline VALUE msgpack_buffer_read_top_as_string(msgpack_buffer_t* b, size_
491
484
  // frozen.
492
485
  result = rb_funcall(result, s_uminus, 0);
493
486
  }
494
- #endif // STR_UMINUS_DEDUPE
495
487
  _msgpack_buffer_consumed(b, length);
496
488
  return result;
497
489
 
@@ -5,15 +5,20 @@ have_header("st.h")
5
5
  have_func("rb_enc_interned_str", "ruby.h") # Ruby 3.0+
6
6
  have_func("rb_hash_new_capa", "ruby.h") # Ruby 3.2+
7
7
 
8
- $CFLAGS << " -fvisibility=hidden "
8
+ append_cflags([
9
+ "-fvisibility=hidden",
10
+ "-I..",
11
+ "-Wall",
12
+ "-O3",
13
+ "-std=gnu99"
14
+ ])
15
+ append_cflags(RbConfig::CONFIG["debugflags"]) if RbConfig::CONFIG["debugflags"]
9
16
 
10
- unless RUBY_PLATFORM.include? 'mswin'
11
- $CFLAGS << %[ -I.. -Wall -O3 #{RbConfig::CONFIG["debugflags"]} -std=gnu99]
12
- end
17
+ append_cflags("-DRUBY_DEBUG=1") if ENV["MSGPACK_DEBUG"]
13
18
 
14
19
  if RUBY_VERSION.start_with?('3.0.') && RUBY_VERSION <= '3.0.5'
15
20
  # https://bugs.ruby-lang.org/issues/18772
16
- $CFLAGS << ' -DRB_ENC_INTERNED_STR_NULL_CHECK=1 '
21
+ append_cflags("-DRB_ENC_INTERNED_STR_NULL_CHECK=1")
17
22
  end
18
23
 
19
24
  # checking if Hash#[]= (rb_hash_aset) dedupes string keys (Ruby 2.6+)
@@ -23,35 +28,21 @@ r = rand.to_s
23
28
  h[%W(#{r}).join('')] = :foo
24
29
  x[%W(#{r}).join('')] = :foo
25
30
  if x.keys[0].equal?(h.keys[0])
26
- $CFLAGS << ' -DHASH_ASET_DEDUPE=1 '
31
+ append_cflags("-DHASH_ASET_DEDUPE=1")
27
32
  else
28
- $CFLAGS << ' -DHASH_ASET_DEDUPE=0 '
29
- end
30
-
31
-
32
- # checking if String#-@ (str_uminus) dedupes... ' (Ruby 2.5+)
33
- begin
34
- a = -(%w(t e s t).join)
35
- b = -(%w(t e s t).join)
36
- if a.equal?(b)
37
- $CFLAGS << ' -DSTR_UMINUS_DEDUPE=1 '
38
- else
39
- $CFLAGS += ' -DSTR_UMINUS_DEDUPE=0 '
40
- end
41
- rescue NoMethodError
42
- $CFLAGS << ' -DSTR_UMINUS_DEDUPE=0 '
33
+ append_cflags("-DHASH_ASET_DEDUPE=0")
43
34
  end
44
35
 
45
36
  # checking if String#-@ (str_uminus) directly interns frozen strings... ' (Ruby 3.0+)
46
37
  begin
47
38
  s = rand.to_s.freeze
48
39
  if (-s).equal?(s) && (-s.dup).equal?(s)
49
- $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=1 '
40
+ append_cflags("-DSTR_UMINUS_DEDUPE_FROZEN=1")
50
41
  else
51
- $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
42
+ append_cflags("-DSTR_UMINUS_DEDUPE_FROZEN=0")
52
43
  end
53
44
  rescue NoMethodError
54
- $CFLAGS << ' -DSTR_UMINUS_DEDUPE_FROZEN=0 '
45
+ append_cflags("-DSTR_UMINUS_DEDUPE_FROZEN=0")
55
46
  end
56
47
 
57
48
  if warnflags = CONFIG['warnflags']
@@ -212,7 +212,7 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
212
212
  VALUE packer_proc, unpacker_proc;
213
213
 
214
214
  if (OBJ_FROZEN(self)) {
215
- rb_raise(rb_eRuntimeError, "can't modify frozen Factory");
215
+ rb_raise(rb_eFrozenError, "can't modify frozen MessagePack::Factory");
216
216
  }
217
217
 
218
218
  switch (argc) {
@@ -222,11 +222,12 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
222
222
  unpacker_arg = ID2SYM(rb_intern("from_msgpack_ext"));
223
223
  break;
224
224
  case 3:
225
- /* register_type(0x7f, Time, packer: proc-like, unapcker: proc-like) */
225
+ /* register_type(0x7f, Time, packer: proc-like, unpacker: proc-like) */
226
226
  options = argv[2];
227
227
  if(rb_type(options) != T_HASH) {
228
228
  rb_raise(rb_eArgError, "expected Hash but found %s.", rb_obj_classname(options));
229
229
  }
230
+
230
231
  packer_arg = rb_hash_aref(options, ID2SYM(rb_intern("packer")));
231
232
  unpacker_arg = rb_hash_aref(options, ID2SYM(rb_intern("unpacker")));
232
233
  break;
@@ -266,7 +267,9 @@ static VALUE Factory_register_type(int argc, VALUE* argv, VALUE self)
266
267
  }
267
268
 
268
269
  if(ext_module == rb_cSymbol) {
269
- fc->has_symbol_ext_type = true;
270
+ if(NIL_P(options) || RTEST(rb_hash_aref(options, ID2SYM(rb_intern("packer"))))) {
271
+ fc->has_symbol_ext_type = true;
272
+ }
270
273
  if(RTEST(options) && RTEST(rb_hash_aref(options, ID2SYM(rb_intern("optimized_symbols_parsing"))))) {
271
274
  fc->optimized_symbol_ext_type = true;
272
275
  }
@@ -233,7 +233,12 @@ static VALUE Packer_write_extension(VALUE self, VALUE obj)
233
233
  msgpack_packer_t *pk = MessagePack_Packer_get(self);
234
234
  Check_Type(obj, T_STRUCT);
235
235
 
236
- int ext_type = FIX2INT(RSTRUCT_GET(obj, 0));
236
+ VALUE rb_ext_type = RSTRUCT_GET(obj, 0);
237
+ if(!RB_TYPE_P(rb_ext_type, T_FIXNUM)) {
238
+ rb_raise(rb_eRangeError, "integer %s too big to convert to `signed char'", RSTRING_PTR(rb_String(rb_ext_type)));
239
+ }
240
+
241
+ int ext_type = FIX2INT(rb_ext_type);
237
242
  if(ext_type < -128 || ext_type > 127) {
238
243
  rb_raise(rb_eRangeError, "integer %d too big to convert to `signed char'", ext_type);
239
244
  }
@@ -349,6 +354,10 @@ static VALUE Packer_registered_types_internal(VALUE self)
349
354
 
350
355
  static VALUE Packer_register_type(int argc, VALUE* argv, VALUE self)
351
356
  {
357
+ if (OBJ_FROZEN(self)) {
358
+ rb_raise(rb_eFrozenError, "can't modify frozen MessagePack::Packer");
359
+ }
360
+
352
361
  msgpack_packer_t *pk = MessagePack_Packer_get(self);
353
362
 
354
363
  int ext_type;
data/ext/msgpack/rmem.c CHANGED
@@ -65,11 +65,10 @@ void* _msgpack_rmem_alloc2(msgpack_rmem_t* pm)
65
65
  /* allocate new chunk */
66
66
  c = pm->array_last++;
67
67
 
68
- /* move to head */
69
- msgpack_rmem_chunk_t tmp = pm->head;
70
- pm->head = *c;
71
- *c = tmp;
68
+ /* move head to array */
69
+ *c = pm->head;
72
70
 
71
+ pm->head.pages = NULL; /* make sure we don't point to another chunk's pages in case xmalloc triggers GC */
73
72
  pm->head.mask = 0xffffffff & (~1); /* "& (~1)" means first chunk is already allocated */
74
73
  pm->head.pages = xmalloc(MSGPACK_RMEM_PAGE_SIZE * 32);
75
74
 
@@ -19,20 +19,14 @@
19
19
  #include "unpacker.h"
20
20
  #include "rmem.h"
21
21
  #include "extension_value_class.h"
22
-
23
- #if !defined(DISABLE_UNPACKER_STACK_RMEM) && \
24
- MSGPACK_UNPACKER_STACK_CAPACITY * MSGPACK_UNPACKER_STACK_SIZE <= MSGPACK_RMEM_PAGE_SIZE
25
- #define UNPACKER_STACK_RMEM
26
- #endif
22
+ #include <assert.h>
27
23
 
28
24
  static int RAW_TYPE_STRING = 256;
29
25
  static int RAW_TYPE_BINARY = 257;
30
26
 
31
27
  static ID s_call;
32
28
 
33
- #ifdef UNPACKER_STACK_RMEM
34
29
  static msgpack_rmem_t s_stack_rmem;
35
- #endif
36
30
 
37
31
  #if !defined(HAVE_RB_HASH_NEW_CAPA)
38
32
  static inline VALUE rb_hash_new_capa(long capa)
@@ -43,18 +37,16 @@ static inline VALUE rb_hash_new_capa(long capa)
43
37
 
44
38
  void msgpack_unpacker_static_init(void)
45
39
  {
46
- #ifdef UNPACKER_STACK_RMEM
40
+ assert(sizeof(msgpack_unpacker_stack_entry_t) * MSGPACK_UNPACKER_STACK_CAPACITY <= MSGPACK_RMEM_PAGE_SIZE);
41
+
47
42
  msgpack_rmem_init(&s_stack_rmem);
48
- #endif
49
43
 
50
44
  s_call = rb_intern("call");
51
45
  }
52
46
 
53
47
  void msgpack_unpacker_static_destroy(void)
54
48
  {
55
- #ifdef UNPACKER_STACK_RMEM
56
49
  msgpack_rmem_destroy(&s_stack_rmem);
57
- #endif
58
50
  }
59
51
 
60
52
  #define HEAD_BYTE_REQUIRED 0xc1
@@ -62,13 +54,8 @@ void msgpack_unpacker_static_destroy(void)
62
54
  static inline msgpack_unpacker_stack_t* _msgpack_unpacker_new_stack(void) {
63
55
  msgpack_unpacker_stack_t *stack = ZALLOC(msgpack_unpacker_stack_t);
64
56
  stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
65
- #ifdef UNPACKER_STACK_RMEM
66
57
  stack->data = msgpack_rmem_alloc(&s_stack_rmem);
67
58
  /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
68
- #else
69
- /*uk->stack = calloc(MSGPACK_UNPACKER_STACK_CAPACITY, sizeof(msgpack_unpacker_stack_entry_t));*/
70
- stack->data = xmalloc(MSGPACK_UNPACKER_STACK_CAPACITY * sizeof(msgpack_unpacker_stack_entry_t));
71
- #endif
72
59
  return stack;
73
60
  }
74
61
 
@@ -85,11 +72,9 @@ void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
85
72
  }
86
73
 
87
74
  static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
88
- #ifdef UNPACKER_STACK_RMEM
89
- msgpack_rmem_free(&s_stack_rmem, stack->data);
90
- #else
91
- xfree(stack->data);
92
- #endif
75
+ if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
76
+ rb_bug("Failed to free an rmem pointer, memory leak?");
77
+ }
93
78
  xfree(stack);
94
79
  }
95
80
 
@@ -21,9 +21,7 @@
21
21
  #include "buffer.h"
22
22
  #include "unpacker_ext_registry.h"
23
23
 
24
- #ifndef MSGPACK_UNPACKER_STACK_CAPACITY
25
24
  #define MSGPACK_UNPACKER_STACK_CAPACITY 128
26
- #endif
27
25
 
28
26
  struct msgpack_unpacker_t;
29
27
  typedef struct msgpack_unpacker_t msgpack_unpacker_t;
@@ -49,8 +47,6 @@ struct msgpack_unpacker_stack_t {
49
47
  msgpack_unpacker_stack_t *parent;
50
48
  };
51
49
 
52
- #define MSGPACK_UNPACKER_STACK_SIZE (8+4+8+8) /* assumes size_t <= 64bit, enum <= 32bit, VALUE <= 64bit */
53
-
54
50
  struct msgpack_unpacker_t {
55
51
  msgpack_buffer_t buffer;
56
52
  msgpack_unpacker_stack_t *stack;
@@ -249,18 +249,6 @@ static VALUE Unpacker_read_map_header(VALUE self)
249
249
  return ULONG2NUM(size); // long at least 32 bits
250
250
  }
251
251
 
252
-
253
- static VALUE Unpacker_feed(VALUE self, VALUE data)
254
- {
255
- msgpack_unpacker_t *uk = MessagePack_Unpacker_get(self);
256
-
257
- StringValue(data);
258
-
259
- msgpack_buffer_append_string(UNPACKER_BUFFER_(uk), data);
260
-
261
- return self;
262
- }
263
-
264
252
  static VALUE Unpacker_feed_reference(VALUE self, VALUE data)
265
253
  {
266
254
  msgpack_unpacker_t *uk = MessagePack_Unpacker_get(self);
@@ -360,6 +348,10 @@ static VALUE Unpacker_registered_types_internal(VALUE self)
360
348
 
361
349
  static VALUE Unpacker_register_type(int argc, VALUE* argv, VALUE self)
362
350
  {
351
+ if (OBJ_FROZEN(self)) {
352
+ rb_raise(rb_eFrozenError, "can't modify frozen MessagePack::Unpacker");
353
+ }
354
+
363
355
  msgpack_unpacker_t *uk = MessagePack_Unpacker_get(self);
364
356
 
365
357
  int ext_type;
@@ -457,8 +449,8 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
457
449
  rb_define_method(cMessagePack_Unpacker, "skip_nil", Unpacker_skip_nil, 0);
458
450
  rb_define_method(cMessagePack_Unpacker, "read_array_header", Unpacker_read_array_header, 0);
459
451
  rb_define_method(cMessagePack_Unpacker, "read_map_header", Unpacker_read_map_header, 0);
460
- rb_define_method(cMessagePack_Unpacker, "feed", Unpacker_feed, 1);
461
- rb_define_method(cMessagePack_Unpacker, "feed_reference", Unpacker_feed_reference, 1);
452
+ rb_define_method(cMessagePack_Unpacker, "feed", Unpacker_feed_reference, 1);
453
+ rb_define_alias(cMessagePack_Unpacker, "feed_reference", "feed");
462
454
  rb_define_method(cMessagePack_Unpacker, "each", Unpacker_each, 0);
463
455
  rb_define_method(cMessagePack_Unpacker, "feed_each", Unpacker_feed_each, 1);
464
456
  rb_define_method(cMessagePack_Unpacker, "reset", Unpacker_reset, 0);
@@ -88,33 +88,34 @@ module MessagePack
88
88
 
89
89
  class Pool
90
90
  if RUBY_ENGINE == "ruby"
91
- class AbstractPool
91
+ class MemberPool
92
92
  def initialize(size, &block)
93
93
  @size = size
94
94
  @new_member = block
95
95
  @members = []
96
96
  end
97
97
 
98
- def checkout
99
- @members.pop || @new_member.call
100
- end
101
-
102
- def checkin(member)
103
- # If the pool is already full, we simply drop the extra member.
104
- # This is because contrary to a connection pool, creating an extra instance
105
- # is extremely unlikely to cause some kind of resource exhaustion.
106
- #
107
- # We could cycle the members (keep the newer one) but first It's more work and second
108
- # the older member might have been created pre-fork, so it might be at least partially
109
- # in shared memory.
110
- if member && @members.size < @size
111
- member.reset
112
- @members << member
98
+ def with
99
+ member = @members.pop || @new_member.call
100
+ begin
101
+ yield member
102
+ ensure
103
+ # If the pool is already full, we simply drop the extra member.
104
+ # This is because contrary to a connection pool, creating an extra instance
105
+ # is extremely unlikely to cause some kind of resource exhaustion.
106
+ #
107
+ # We could cycle the members (keep the newer one) but first It's more work and second
108
+ # the older member might have been created pre-fork, so it might be at least partially
109
+ # in shared memory.
110
+ if member && @members.size < @size
111
+ member.reset
112
+ @members << member
113
+ end
113
114
  end
114
115
  end
115
116
  end
116
117
  else
117
- class AbstractPool
118
+ class MemberPool
118
119
  def initialize(size, &block)
119
120
  @size = size
120
121
  @new_member = block
@@ -122,63 +123,50 @@ module MessagePack
122
123
  @mutex = Mutex.new
123
124
  end
124
125
 
125
- def checkout
126
- @mutex.synchronize { @members.pop } || @new_member.call
127
- end
128
-
129
- def checkin(member)
130
- @mutex.synchronize do
131
- if member && @members.size < @size
132
- member.reset
133
- @members << member
126
+ def with
127
+ member = @mutex.synchronize { @members.pop } || @new_member.call
128
+ begin
129
+ yield member
130
+ ensure
131
+ member.reset
132
+ @mutex.synchronize do
133
+ if member && @members.size < @size
134
+ @members << member
135
+ end
134
136
  end
135
137
  end
136
138
  end
137
139
  end
138
140
  end
139
141
 
140
- class PackerPool < AbstractPool
141
- private
142
-
143
- def reset(packer)
144
- packer.clear
145
- end
146
- end
147
-
148
- class UnpackerPool < AbstractPool
149
- private
150
-
151
- def reset(unpacker)
152
- unpacker.reset
153
- end
154
- end
155
-
156
142
  def initialize(factory, size, options = nil)
157
143
  options = nil if !options || options.empty?
158
144
  @factory = factory
159
- @packers = PackerPool.new(size) { factory.packer(options) }
160
- @unpackers = UnpackerPool.new(size) { factory.unpacker(options) }
145
+ @packers = MemberPool.new(size) { factory.packer(options).freeze }
146
+ @unpackers = MemberPool.new(size) { factory.unpacker(options).freeze }
161
147
  end
162
148
 
163
149
  def load(data)
164
- unpacker = @unpackers.checkout
165
- begin
166
- unpacker.feed_reference(data)
150
+ @unpackers.with do |unpacker|
151
+ unpacker.feed(data)
167
152
  unpacker.full_unpack
168
- ensure
169
- @unpackers.checkin(unpacker)
170
153
  end
171
154
  end
172
155
 
173
156
  def dump(object)
174
- packer = @packers.checkout
175
- begin
157
+ @packers.with do |packer|
176
158
  packer.write(object)
177
159
  packer.full_pack
178
- ensure
179
- @packers.checkin(packer)
180
160
  end
181
161
  end
162
+
163
+ def unpacker(&block)
164
+ @unpackers.with(&block)
165
+ end
166
+
167
+ def packer(&block)
168
+ @packers.with(&block)
169
+ end
182
170
  end
183
171
  end
184
172
  end
@@ -1,5 +1,5 @@
1
1
  module MessagePack
2
- VERSION = "1.6.1"
2
+ VERSION = "1.7.1"
3
3
  # Note for maintainers:
4
4
  # Don't miss building/releasing the JRuby version (rake buld:java)
5
5
  # See "How to build -java rubygems" in README for more details.
data/msgpack.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
  s.extensions = ["ext/msgpack/extconf.rb"]
22
22
  end
23
23
 
24
- s.required_ruby_version = ">= 2.4"
24
+ s.required_ruby_version = ">= 2.5"
25
25
 
26
26
  s.add_development_dependency 'bundler'
27
27
  s.add_development_dependency 'rake'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msgpack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-03-03 00:00:00.000000000 Z
13
+ date: 2023-05-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -201,14 +201,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
201
201
  requirements:
202
202
  - - ">="
203
203
  - !ruby/object:Gem::Version
204
- version: '2.4'
204
+ version: '2.5'
205
205
  required_rubygems_version: !ruby/object:Gem::Requirement
206
206
  requirements:
207
207
  - - ">="
208
208
  - !ruby/object:Gem::Version
209
209
  version: '0'
210
210
  requirements: []
211
- rubygems_version: 3.4.6
211
+ rubygems_version: 3.1.2
212
212
  signing_key:
213
213
  specification_version: 4
214
214
  summary: MessagePack, a binary-based efficient data interchange format.