msgpack 1.6.1 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.