msgpack 1.8.4 → 1.8.6

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: 4a5aa259ac95b61218c0f1cf10a23195bf3c847c7b1423172f50ece723363905
4
- data.tar.gz: 9b3369d91349618e125cef788f3051fd706bcbbf01a78ed2afcb82ecd6d0ecf5
3
+ metadata.gz: cc5fdca2a5a867c26e72649de9838ca9a7ee44e2e84d295215207edaa98d3629
4
+ data.tar.gz: 703a7d56d9d634b53020db638e578339296e6a9cbc3da0ee6d3c8efa7d5d58bb
5
5
  SHA512:
6
- metadata.gz: 9feed41442045775173abfcae2d384b27904c44b81cd3674dfa18bfbf10558c9f77ea2f2ed51b694101a33e37761fa94553108fedb866d4834bbce697f96579a
7
- data.tar.gz: ae0d30ca66f5f4e1e22fcfee2615bd91db00ddfe101e043a0753e32bc7252c42d9bbfc3b763d3a519f20fdbb28ad0be2f5071472ad8b7c6c4053ac7702875432
6
+ metadata.gz: d06ef9b19f1d8e3d18eb2bc05ed5cd26102bdd0cb60d1d8ac622d122da1d734cc2c17180f4b9c0fd75d093f0829ebd38ecab4f3a685d0cb3653a20cf5bbd78c4
7
+ data.tar.gz: d5f57a80f7a109703629c1965d87638675b478ca0f34ac8421836fbadde433cd108185094326cff0a4b9c7d59f53d07904a4569e9549ca6a500f0309ae58048a
data/ChangeLog CHANGED
@@ -1,3 +1,16 @@
1
+ 2026-10-27 1.8.6
2
+
3
+ * Fix use-after-free when a recursive extension proc rescues, skips or resets.
4
+ * Speed up decoding of oversized integers.
5
+ * Avoid excessive memory allocation from crafted container headers.
6
+
7
+ 2026-09-11 1.8.5
8
+
9
+ * Prevent stack depth underflow when skipping from recursive unpacker.
10
+ * Fix `Unpacker#skip_nil` to properly consume the buffer.
11
+ * Fix some small difference in Factory registration of the Java implementation.
12
+ * Fix some Factory/ext_type optimization edge cases.
13
+
1
14
  2026-07-28 1.8.4
2
15
 
3
16
  * Fix `MessagePack::Buffer` to stop using already released memory page.
@@ -59,6 +59,7 @@ public class Factory extends RubyObject {
59
59
  Factory clone = (Factory)super.dup();
60
60
  clone.extensionRegistry = extensionRegistry();
61
61
  clone.hasSymbolExtType = hasSymbolExtType;
62
+ clone.hasBigIntExtType = hasBigIntExtType;
62
63
  return clone;
63
64
  }
64
65
 
@@ -110,8 +111,8 @@ public class Factory extends RubyObject {
110
111
 
111
112
  extensionRegistry.put(extModule, (int) typeId, recursive, packerProc, unpackerProc);
112
113
 
113
- if (extModule == runtime.getSymbol() && !packerProc.isNil()) {
114
- hasSymbolExtType = true;
114
+ if (extModule == runtime.getSymbol()) {
115
+ hasSymbolExtType = packerProc != null && !packerProc.isNil();
115
116
  }
116
117
 
117
118
  if (options != null) {
@@ -122,6 +123,8 @@ public class Factory extends RubyObject {
122
123
  } else {
123
124
  throw runtime.newArgumentError("oversized_integer_extension: true is only for Integer class");
124
125
  }
126
+ } else if (extModule == runtime.getModule("Integer")) {
127
+ hasBigIntExtType = false;
125
128
  }
126
129
  }
127
130
 
data/ext/msgpack/buffer.h CHANGED
@@ -237,14 +237,27 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string);
237
237
 
238
238
  static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE string)
239
239
  {
240
- size_t length;
241
- char *ptr;
242
- RSTRING_GETMEM(string, ptr, length);
240
+ size_t length = RSTRING_LEN(string);
243
241
 
244
242
  if(length > b->write_reference_threshold) {
245
243
  _msgpack_buffer_append_long_string(b, string);
246
- } else {
247
- msgpack_buffer_append(b, ptr, length);
244
+ } else if(length > 0) {
245
+ /* Making room can run io.write or trigger GC, either of which may free
246
+ * or shrink the string, so reserve the space first and only then read
247
+ * its pointer. */
248
+ msgpack_buffer_ensure_writable(b, length);
249
+ char *ptr;
250
+ size_t current;
251
+ RSTRING_GETMEM(string, ptr, current);
252
+ if(current > length) {
253
+ current = length;
254
+ }
255
+ memcpy(b->tail.last, ptr, current);
256
+ if(current < length) {
257
+ memset(b->tail.last + current, 0, length - current);
258
+ }
259
+ b->tail.last += length;
260
+ RB_GC_GUARD(string);
248
261
  }
249
262
 
250
263
  return length;
@@ -121,7 +121,10 @@ static VALUE Factory_dup(VALUE self)
121
121
  msgpack_factory_t *fc = Factory_get(self);
122
122
  msgpack_factory_t *cloned_fc = Factory_get(clone);
123
123
 
124
+ cloned_fc->has_bigint_ext_type = fc->has_bigint_ext_type;
124
125
  cloned_fc->has_symbol_ext_type = fc->has_symbol_ext_type;
126
+ cloned_fc->optimized_symbol_ext_type = fc->optimized_symbol_ext_type;
127
+ cloned_fc->symbol_ext_type = fc->symbol_ext_type;
125
128
  cloned_fc->pkrg = fc->pkrg;
126
129
  msgpack_unpacker_ext_registry_borrow(fc->ukrg, &cloned_fc->ukrg);
127
130
  msgpack_packer_ext_registry_dup(clone, &fc->pkrg, &cloned_fc->pkrg);
@@ -230,12 +233,13 @@ static VALUE Factory_register_type_internal(VALUE self, VALUE rb_ext_type, VALUE
230
233
  }
231
234
 
232
235
  if(ext_module == rb_cSymbol) {
233
- if(NIL_P(options) || RTEST(rb_hash_aref(options, ID2SYM(rb_intern("packer"))))) {
234
- fc->has_symbol_ext_type = true;
235
- }
236
- if(RTEST(options) && RTEST(rb_hash_aref(options, ID2SYM(rb_intern("optimized_symbols_parsing"))))) {
237
- fc->optimized_symbol_ext_type = true;
238
- }
236
+ fc->symbol_ext_type = ext_type;
237
+ fc->has_symbol_ext_type = NIL_P(options) || RTEST(packer_proc);
238
+ fc->optimized_symbol_ext_type = RTEST(options) && RTEST(rb_hash_aref(options, ID2SYM(rb_intern("optimized_symbols_parsing"))));
239
+ }
240
+
241
+ if(ext_module == rb_cInteger) {
242
+ fc->has_bigint_ext_type = false;
239
243
  }
240
244
 
241
245
  if(RTEST(options)) {
@@ -246,7 +250,6 @@ static VALUE Factory_register_type_internal(VALUE self, VALUE rb_ext_type, VALUE
246
250
  rb_raise(rb_eArgError, "oversized_integer_extension: true is only for Integer class");
247
251
  }
248
252
  }
249
-
250
253
  if(RTEST(rb_hash_aref(options, ID2SYM(rb_intern("recursive"))))) {
251
254
  flags |= MSGPACK_EXT_RECURSIVE;
252
255
  }
@@ -235,7 +235,7 @@ static VALUE Packer_write_extension(VALUE self, VALUE obj)
235
235
 
236
236
  VALUE rb_ext_type = RSTRUCT_GET(obj, 0);
237
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)));
238
+ rb_raise(rb_eRangeError, "integer %"PRIsVALUE" too big to convert to `signed char'", rb_ext_type);
239
239
  }
240
240
 
241
241
  int ext_type = FIX2INT(rb_ext_type);
@@ -74,9 +74,13 @@ static inline VALUE rb_hash_new_capa_inline(long capa)
74
74
  #define rb_hash_new_capa rb_hash_new_capa_inline
75
75
  #endif
76
76
 
77
- static inline int16_t initial_buffer_size(long size)
77
+ static inline int16_t initial_buffer_size(msgpack_unpacker_t* uk, long count, size_t bytes_per_element)
78
78
  {
79
- return (size > INITIAL_BUFFER_CAPACITY_MAX) ? INITIAL_BUFFER_CAPACITY_MAX : size;
79
+ size_t available = msgpack_buffer_all_readable_size(UNPACKER_BUFFER_(uk)) / bytes_per_element;
80
+ if((size_t)count > available) {
81
+ count = (long)available;
82
+ }
83
+ return (count > INITIAL_BUFFER_CAPACITY_MAX) ? INITIAL_BUFFER_CAPACITY_MAX : count;
80
84
  }
81
85
 
82
86
  void msgpack_unpacker_static_init(void)
@@ -110,6 +114,7 @@ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack)
110
114
  }
111
115
  stack->data = NULL;
112
116
  stack->depth = 0;
117
+ stack->floor = 0;
113
118
  }
114
119
  }
115
120
 
@@ -169,7 +174,7 @@ void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
169
174
  uk->head_byte = HEAD_BYTE_REQUIRED;
170
175
 
171
176
  /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack.depth);*/
172
- uk->stack.depth = 0;
177
+ msgpack_unpacker_stack_rewind(uk);
173
178
  uk->last_object = Qnil;
174
179
  uk->reading_raw = Qnil;
175
180
  uk->reading_raw_remaining = 0;
@@ -386,9 +391,16 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
386
391
  * instead of raising StackError like every other container type. */
387
392
  return PRIMITIVE_STACK_TOO_DEEP;
388
393
  }
394
+ size_t barrier_depth = uk->stack.depth;
395
+ size_t saved_floor = uk->stack.floor;
389
396
  int raised;
397
+
398
+ uk->stack.floor = barrier_depth;
390
399
  obj = protected_proc_call(proc, 1, &uk->self, &raised);
391
- msgpack_unpacker_stack_pop(uk);
400
+ uk->stack.floor = saved_floor;
401
+
402
+ /* Not --depth: the proc may return with entries left above the barrier. */
403
+ uk->stack.depth = barrier_depth - 1;
392
404
 
393
405
  if (raised) {
394
406
  uk->last_object = rb_errinfo();
@@ -473,14 +485,14 @@ static int read_primitive(msgpack_unpacker_t* uk)
473
485
  if(count == 0) {
474
486
  return object_complete(uk, rb_ary_new());
475
487
  }
476
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(initial_buffer_size(count)));
488
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(initial_buffer_size(uk, count, 1)));
477
489
 
478
490
  SWITCH_RANGE(b, 0x80, 0x8f) // FixMap
479
491
  int count = b & 0x0f;
480
492
  if(count == 0) {
481
493
  return object_complete(uk, rb_hash_new());
482
494
  }
483
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(initial_buffer_size(count)));
495
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(initial_buffer_size(uk, count, 2)));
484
496
 
485
497
  SWITCH_RANGE(b, 0xc0, 0xdf) // Variable
486
498
  switch(b) {
@@ -703,7 +715,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
703
715
  if(count == 0) {
704
716
  return object_complete(uk, rb_ary_new());
705
717
  }
706
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(initial_buffer_size(count)));
718
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(initial_buffer_size(uk, count, 1)));
707
719
  }
708
720
 
709
721
  case 0xdd: // array 32
@@ -713,7 +725,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
713
725
  if(count == 0) {
714
726
  return object_complete(uk, rb_ary_new());
715
727
  }
716
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(initial_buffer_size(count)));
728
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_ARRAY, count, rb_ary_new2(initial_buffer_size(uk, count, 1)));
717
729
  }
718
730
 
719
731
  case 0xde: // map 16
@@ -723,7 +735,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
723
735
  if(count == 0) {
724
736
  return object_complete(uk, rb_hash_new());
725
737
  }
726
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(initial_buffer_size(count)));
738
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(initial_buffer_size(uk, count, 2)));
727
739
  }
728
740
 
729
741
  case 0xdf: // map 32
@@ -733,7 +745,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
733
745
  if(count == 0) {
734
746
  return object_complete(uk, rb_hash_new());
735
747
  }
736
- return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(initial_buffer_size(count)));
748
+ return _msgpack_unpacker_stack_push(uk, STACK_TYPE_MAP_KEY, count*2, rb_hash_new_capa(initial_buffer_size(uk, count, 2)));
737
749
  }
738
750
 
739
751
  default:
@@ -886,6 +898,10 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
886
898
  container_completed:
887
899
  {
888
900
  msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
901
+ if(top->type == STACK_TYPE_RECURSIVE) {
902
+ STACK_FREE(uk);
903
+ return PRIMITIVE_OBJECT_COMPLETE;
904
+ }
889
905
 
890
906
  /* this section optimized out */
891
907
  // TODO object_complete still creates objects which should be optimized out
@@ -911,8 +927,8 @@ int msgpack_unpacker_skip_nil(msgpack_unpacker_t* uk)
911
927
  return b;
912
928
  }
913
929
  if(b == 0xc0) {
930
+ reset_head_byte(uk);
914
931
  return 1;
915
932
  }
916
933
  return 0;
917
934
  }
918
-
@@ -43,6 +43,7 @@ typedef struct {
43
43
 
44
44
  struct msgpack_unpacker_stack_t {
45
45
  size_t depth;
46
+ size_t floor;
46
47
  size_t capacity;
47
48
  msgpack_unpacker_stack_entry_t *data;
48
49
  };
@@ -109,6 +110,11 @@ static inline void msgpack_unpacker_set_allow_unknown_ext(msgpack_unpacker_t* uk
109
110
  uk->allow_unknown_ext = enable;
110
111
  }
111
112
 
113
+ static inline void msgpack_unpacker_stack_rewind(msgpack_unpacker_t* uk)
114
+ {
115
+ uk->stack.depth = uk->stack.floor;
116
+ }
117
+
112
118
 
113
119
  /* error codes */
114
120
  #define PRIMITIVE_CONTAINER_START 1
@@ -165,7 +165,7 @@ static VALUE Unpacker_allow_unknown_ext_p(VALUE self)
165
165
 
166
166
  NORETURN(static void raise_unpacker_error(msgpack_unpacker_t *uk, int r))
167
167
  {
168
- uk->stack.depth = 0;
168
+ msgpack_unpacker_stack_rewind(uk);
169
169
  switch(r) {
170
170
  case PRIMITIVE_EOF:
171
171
  rb_raise(rb_eEOFError, "end of buffer reached");
@@ -5,7 +5,8 @@ module MessagePack
5
5
  # We split the bigint in 32bits chunks so that individual part fits into
6
6
  # a MRI immediate Integer.
7
7
  CHUNK_BITLENGTH = 32
8
- FORMAT = 'CL>*'
8
+ CHUNK_FORMAT = 'L>*'
9
+ FORMAT = "C#{CHUNK_FORMAT}"
9
10
 
10
11
  if Integer.instance_method(:[]).arity != 1 # Ruby 2.7 and newer
11
12
  # Starting from Ruby 2.7 we can address arbitrary bitranges inside an Integer with Integer#[]
@@ -56,12 +57,7 @@ module MessagePack
56
57
  parts = data.unpack(FORMAT)
57
58
 
58
59
  sign = parts.shift
59
- sum = parts.pop.to_i
60
-
61
- parts.reverse_each do |part|
62
- sum = sum << CHUNK_BITLENGTH
63
- sum += part
64
- end
60
+ sum = parts.reverse.pack(CHUNK_FORMAT).unpack1('H*').to_i(16)
65
61
 
66
62
  sign == 0 ? sum : -sum
67
63
  end
@@ -14,10 +14,12 @@ module MessagePack
14
14
  options[:packer] = packer.to_sym.to_proc
15
15
  when Method
16
16
  options[:packer] = packer.to_proc
17
- when packer.respond_to?(:call)
18
- options[:packer] = packer.method(:call).to_proc
19
17
  else
20
- raise ::TypeError, "expected :packer argument to be a callable object, got: #{packer.inspect}"
18
+ if packer.respond_to?(:call)
19
+ options[:packer] = packer.method(:call).to_proc
20
+ else
21
+ raise ::TypeError, "expected :packer argument to be a callable object, got: #{packer.inspect}"
22
+ end
21
23
  end
22
24
 
23
25
  case unpacker = options[:unpacker]
@@ -27,10 +29,12 @@ module MessagePack
27
29
  options[:unpacker] = klass.method(unpacker).to_proc
28
30
  when Method
29
31
  options[:unpacker] = unpacker.to_proc
30
- when packer.respond_to?(:call)
31
- options[:unpacker] = unpacker.method(:call).to_proc
32
32
  else
33
- raise ::TypeError, "expected :unpacker argument to be a callable object, got: #{unpacker.inspect}"
33
+ if unpacker.respond_to?(:call)
34
+ options[:unpacker] = unpacker.method(:call).to_proc
35
+ else
36
+ raise ::TypeError, "expected :unpacker argument to be a callable object, got: #{unpacker.inspect}"
37
+ end
34
38
  end
35
39
  end
36
40
 
@@ -51,7 +55,7 @@ module MessagePack
51
55
  type = ary[0]
52
56
  packer_proc = ary[1]
53
57
  unpacker_proc = nil
54
- if unpacker.has_key?(type)
58
+ if unpacker.has_key?(type) && unpacker[type][0] == klass
55
59
  unpacker_proc = unpacker.delete(type)[1]
56
60
  end
57
61
  list << {type: type, class: klass, packer: packer_proc, unpacker: unpacker_proc}
@@ -85,7 +89,7 @@ module MessagePack
85
89
 
86
90
  def type_registered?(klass_or_type, selector=:both)
87
91
  case klass_or_type
88
- when Class
92
+ when Module
89
93
  klass = klass_or_type
90
94
  registered_types(selector).any?{|entry| klass <= entry[:class] }
91
95
  when Integer
@@ -23,7 +23,7 @@ module MessagePack
23
23
 
24
24
  def type_registered?(klass_or_type)
25
25
  case klass_or_type
26
- when Class
26
+ when Module
27
27
  klass = klass_or_type
28
28
  registered_types.any?{|entry| klass <= entry[:class] }
29
29
  when Integer
@@ -27,7 +27,7 @@ module MessagePack
27
27
 
28
28
  def type_registered?(klass_or_type)
29
29
  case klass_or_type
30
- when Class
30
+ when Module
31
31
  klass = klass_or_type
32
32
  registered_types.any?{|entry| klass == entry[:class] }
33
33
  when Integer
@@ -1,5 +1,5 @@
1
1
  module MessagePack
2
- VERSION = "1.8.4"
2
+ VERSION = "1.8.6"
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.
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.8.4
4
+ version: 1.8.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
@@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
98
  - !ruby/object:Gem::Version
99
99
  version: '0'
100
100
  requirements: []
101
- rubygems_version: 4.0.16
101
+ rubygems_version: 4.0.20
102
102
  specification_version: 4
103
103
  summary: MessagePack, a binary-based efficient data interchange format.
104
104
  test_files: []