msgpack 1.7.3 → 1.8.0

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: fe6adcd787be2f8c3e9459d46c3baa4ad81c5b08bdcaeb9bfec9a80c9a4540c6
4
- data.tar.gz: 76d6be5a37a2b6e225ad995e6b0f670d0489839a98b678c9332837bd082e7d7e
3
+ metadata.gz: efdb772bf54b74587a6c99e9513f9c16c78bbef3e5e3c17064a4be79fd5adb7a
4
+ data.tar.gz: d2f74cb1115947f5337cd730b6283fac61ceeed3a9457597cc90155b3dc93d7e
5
5
  SHA512:
6
- metadata.gz: 36b0e748e7b54baad2ecef8c1c071a82cf3e6bd26540fd433a3c71f1e77afe341188594a26bfed817f84af10ef4f613ded14fc0a8448a77dc4978683cf7c35d1
7
- data.tar.gz: 45ce3770a12b3580945ba3dd42d40ab8ba24a167f675f71d57bb42af6cf4ab204d7cc7960925ea78556988f523886fd92b431789a174e0529143ab0908d52418
6
+ metadata.gz: 92da2466eac162f0d6d319496d7af3dbbef0d76b77c3aefb4787213e3b957464603859101ae28ac9620be82feb29278b2ed601adf2fd9d9811b364c258061d4b
7
+ data.tar.gz: a469586178eb44bbd50abf4cb34684f6a3fd4038063a80d9b3bf7f5cb9e6a2b34c1fed853be669f0bfb356d618efff3a2eaa51b86dd34d5427787a05453b8e11
data/ChangeLog CHANGED
@@ -1,3 +1,16 @@
1
+ 2025-02-06 1.8.0
2
+
3
+ * Numerous small optimizations.
4
+ * Added `key_cache` option to `Unpacker`.
5
+
6
+ 2024-11-11 1.7.5
7
+
8
+ * Rerelease 1.7.4 with fixed java package.
9
+
10
+ 2024-11-11 1.7.4
11
+
12
+ * Fixed a potental memory leak when recursive unpacker raise.
13
+
1
14
  2024-10-03 1.7.3
2
15
 
3
16
  * Limit initial containers pre-allocation to `SHRT_MAX` (32k) entries.
data/ext/msgpack/buffer.c CHANGED
@@ -300,7 +300,7 @@ static inline void _msgpack_buffer_add_new_chunk(msgpack_buffer_t* b)
300
300
  static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE string)
301
301
  {
302
302
  VALUE mapped_string;
303
- if(ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit && RTEST(rb_obj_frozen_p(string))) {
303
+ if(ENCODING_GET_INLINED(string) == msgpack_rb_encindex_ascii8bit && RB_OBJ_FROZEN_RAW(string)) {
304
304
  mapped_string = string;
305
305
  } else {
306
306
  mapped_string = rb_str_dup(string);
@@ -309,8 +309,9 @@ static inline void _msgpack_buffer_append_reference(msgpack_buffer_t* b, VALUE s
309
309
 
310
310
  _msgpack_buffer_add_new_chunk(b);
311
311
 
312
- char* data = RSTRING_PTR(mapped_string);
313
- size_t length = RSTRING_LEN(mapped_string);
312
+ char* data;
313
+ size_t length;
314
+ RSTRING_GETMEM(mapped_string, data, length);
314
315
 
315
316
  b->tail.first = (char*) data;
316
317
  b->tail.last = (char*) data + length;
@@ -330,7 +331,7 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string)
330
331
  {
331
332
  if(b->io != Qnil) {
332
333
  msgpack_buffer_flush(b);
333
- if (ENCODING_GET(string) == msgpack_rb_encindex_ascii8bit) {
334
+ if (ENCODING_GET_INLINED(string) == msgpack_rb_encindex_ascii8bit) {
334
335
  rb_funcall(b->io, b->io_write_all_method, 1, string);
335
336
  } else {
336
337
  msgpack_buffer_append(b, RSTRING_PTR(string), RSTRING_LEN(string));
data/ext/msgpack/buffer.h CHANGED
@@ -81,20 +81,6 @@ struct msgpack_buffer_chunk_t {
81
81
  bool rmem;
82
82
  };
83
83
 
84
- union msgpack_buffer_cast_block_t {
85
- char buffer[8];
86
- uint8_t u8;
87
- uint16_t u16;
88
- uint32_t u32;
89
- uint64_t u64;
90
- int8_t i8;
91
- int16_t i16;
92
- int32_t i32;
93
- int64_t i64;
94
- float f;
95
- double d;
96
- };
97
-
98
84
  struct msgpack_buffer_t {
99
85
  char* read_buffer;
100
86
  char* tail_buffer_end;
@@ -107,8 +93,6 @@ struct msgpack_buffer_t {
107
93
  char* rmem_end;
108
94
  void** rmem_owner;
109
95
 
110
- union msgpack_buffer_cast_block_t cast_block;
111
-
112
96
  VALUE io;
113
97
  VALUE io_buffer;
114
98
  ID io_write_all_method;
@@ -253,13 +237,14 @@ void _msgpack_buffer_append_long_string(msgpack_buffer_t* b, VALUE string);
253
237
 
254
238
  static inline size_t msgpack_buffer_append_string(msgpack_buffer_t* b, VALUE string)
255
239
  {
256
- size_t length = RSTRING_LEN(string);
240
+ size_t length;
241
+ char *ptr;
242
+ RSTRING_GETMEM(string, ptr, length);
257
243
 
258
244
  if(length > b->write_reference_threshold) {
259
245
  _msgpack_buffer_append_long_string(b, string);
260
-
261
246
  } else {
262
- msgpack_buffer_append(b, RSTRING_PTR(string), length);
247
+ msgpack_buffer_append(b, ptr, length);
263
248
  }
264
249
 
265
250
  return length;
@@ -383,14 +368,6 @@ static inline size_t msgpack_buffer_skip_nonblock(msgpack_buffer_t* b, size_t le
383
368
  return length;
384
369
  }
385
370
 
386
- static inline union msgpack_buffer_cast_block_t* msgpack_buffer_read_cast_block(msgpack_buffer_t* b, size_t n)
387
- {
388
- if(!msgpack_buffer_read_all(b, b->cast_block.buffer, n)) {
389
- return NULL;
390
- }
391
- return &b->cast_block;
392
- }
393
-
394
371
  size_t msgpack_buffer_read_to_string_nonblock(msgpack_buffer_t* b, VALUE string, size_t length);
395
372
 
396
373
  static inline size_t msgpack_buffer_read_to_string(msgpack_buffer_t* b, VALUE string, size_t length)
@@ -497,4 +474,131 @@ static inline VALUE msgpack_buffer_read_top_as_symbol(msgpack_buffer_t* b, size_
497
474
  return rb_str_intern(msgpack_buffer_read_top_as_string(b, length, true, utf8));
498
475
  }
499
476
 
477
+ // Hash keys are likely to be repeated, and are frozen.
478
+ // As such we can re-use them if we keep a cache of the ones we've seen so far,
479
+ // and save much more expensive lookups into the global fstring table.
480
+ // This cache implementation is deliberately simple, as we're optimizing for compactness,
481
+ // to be able to fit easily embeded inside msgpack_unpacker_t.
482
+ // As such, binary search into a sorted array gives a good tradeoff between compactness and
483
+ // performance.
484
+ #define MSGPACK_KEY_CACHE_CAPACITY 63
485
+
486
+ typedef struct msgpack_key_cache_t msgpack_key_cache_t;
487
+ struct msgpack_key_cache_t {
488
+ int length;
489
+ VALUE entries[MSGPACK_KEY_CACHE_CAPACITY];
490
+ };
491
+
492
+ static inline VALUE build_interned_string(const char *str, const long length)
493
+ {
494
+ # ifdef HAVE_RB_ENC_INTERNED_STR
495
+ return rb_enc_interned_str(str, length, rb_utf8_encoding());
496
+ # else
497
+ VALUE rstring = rb_utf8_str_new(str, length);
498
+ return rb_funcall(rb_str_freeze(rstring), s_uminus, 0);
499
+ # endif
500
+ }
501
+
502
+ static inline VALUE build_symbol(const char *str, const long length)
503
+ {
504
+ return rb_str_intern(build_interned_string(str, length));
505
+ }
506
+
507
+ static void rvalue_cache_insert_at(msgpack_key_cache_t *cache, int index, VALUE rstring)
508
+ {
509
+ MEMMOVE(&cache->entries[index + 1], &cache->entries[index], VALUE, cache->length - index);
510
+ cache->length++;
511
+ cache->entries[index] = rstring;
512
+ }
513
+
514
+ static inline int rstring_cache_cmp(const char *str, const long length, VALUE rstring)
515
+ {
516
+ long rstring_length = RSTRING_LEN(rstring);
517
+ if (length == rstring_length) {
518
+ return memcmp(str, RSTRING_PTR(rstring), length);
519
+ } else {
520
+ return (int)(length - rstring_length);
521
+ }
522
+ }
523
+
524
+ static VALUE rstring_cache_fetch(msgpack_key_cache_t *cache, const char *str, const long length)
525
+ {
526
+ int low = 0;
527
+ int high = cache->length - 1;
528
+ int mid = 0;
529
+ int last_cmp = 0;
530
+
531
+ while (low <= high) {
532
+ mid = (high + low) >> 1;
533
+ VALUE entry = cache->entries[mid];
534
+ last_cmp = rstring_cache_cmp(str, length, entry);
535
+
536
+ if (last_cmp == 0) {
537
+ return entry;
538
+ } else if (last_cmp > 0) {
539
+ low = mid + 1;
540
+ } else {
541
+ high = mid - 1;
542
+ }
543
+ }
544
+
545
+ VALUE rstring = build_interned_string(str, length);
546
+
547
+ if (cache->length < MSGPACK_KEY_CACHE_CAPACITY) {
548
+ if (last_cmp > 0) {
549
+ mid += 1;
550
+ }
551
+
552
+ rvalue_cache_insert_at(cache, mid, rstring);
553
+ }
554
+ return rstring;
555
+ }
556
+
557
+ static VALUE rsymbol_cache_fetch(msgpack_key_cache_t *cache, const char *str, const long length)
558
+ {
559
+ int low = 0;
560
+ int high = cache->length - 1;
561
+ int mid = 0;
562
+ int last_cmp = 0;
563
+
564
+ while (low <= high) {
565
+ mid = (high + low) >> 1;
566
+ VALUE entry = cache->entries[mid];
567
+ last_cmp = rstring_cache_cmp(str, length, rb_sym2str(entry));
568
+
569
+ if (last_cmp == 0) {
570
+ return entry;
571
+ } else if (last_cmp > 0) {
572
+ low = mid + 1;
573
+ } else {
574
+ high = mid - 1;
575
+ }
576
+ }
577
+
578
+ VALUE rsymbol = build_symbol(str, length);
579
+
580
+ if (cache->length < MSGPACK_KEY_CACHE_CAPACITY) {
581
+ if (last_cmp > 0) {
582
+ mid += 1;
583
+ }
584
+
585
+ rvalue_cache_insert_at(cache, mid, rsymbol);
586
+ }
587
+ return rsymbol;
588
+ }
589
+
590
+ static inline VALUE msgpack_buffer_read_top_as_interned_symbol(msgpack_buffer_t* b, msgpack_key_cache_t *cache, size_t length)
591
+ {
592
+ VALUE result = rsymbol_cache_fetch(cache, b->read_buffer, length);
593
+ _msgpack_buffer_consumed(b, length);
594
+ return result;
595
+ }
596
+
597
+ static inline VALUE msgpack_buffer_read_top_as_interned_string(msgpack_buffer_t* b, msgpack_key_cache_t *cache, size_t length)
598
+ {
599
+ VALUE result = rstring_cache_fetch(cache, b->read_buffer, length);
600
+ _msgpack_buffer_consumed(b, length);
601
+ return result;
602
+ }
603
+
500
604
  #endif
@@ -3,17 +3,19 @@ require 'mkmf'
3
3
  have_func("rb_enc_interned_str", "ruby.h") # Ruby 3.0+
4
4
  have_func("rb_hash_new_capa", "ruby.h") # Ruby 3.2+
5
5
  have_func("rb_proc_call_with_block", "ruby.h") # CRuby (TruffleRuby doesn't have it)
6
+ have_func("rb_gc_mark_locations", "ruby.h") # Missing on TruffleRuby
6
7
 
7
8
  append_cflags([
8
9
  "-fvisibility=hidden",
9
10
  "-I..",
10
11
  "-Wall",
11
- "-O3",
12
12
  "-std=gnu99"
13
13
  ])
14
- append_cflags(RbConfig::CONFIG["debugflags"]) if RbConfig::CONFIG["debugflags"]
15
14
 
16
- append_cflags("-DRUBY_DEBUG=1") if ENV["MSGPACK_DEBUG"]
15
+ if ENV["MSGPACK_DEBUG"]
16
+ append_cflags(RbConfig::CONFIG["debugflags"]) if RbConfig::CONFIG["debugflags"]
17
+ append_cflags("-DRUBY_DEBUG=1")
18
+ end
17
19
 
18
20
  if RUBY_VERSION.start_with?('3.0.') && RUBY_VERSION <= '3.0.5'
19
21
  # https://bugs.ruby-lang.org/issues/18772
data/ext/msgpack/packer.h CHANGED
@@ -25,21 +25,26 @@
25
25
  #define MSGPACK_PACKER_IO_FLUSH_THRESHOLD_TO_WRITE_STRING_BODY (1024)
26
26
  #endif
27
27
 
28
+ #ifndef UNREACHABLE_RETURN
29
+ // Ruby 2.5
30
+ #define UNREACHABLE_RETURN() return
31
+ #endif
32
+
28
33
  struct msgpack_packer_t;
29
34
  typedef struct msgpack_packer_t msgpack_packer_t;
30
35
 
31
36
  struct msgpack_packer_t {
32
37
  msgpack_buffer_t buffer;
33
38
 
34
- bool compatibility_mode;
35
- bool has_bigint_ext_type;
36
- bool has_symbol_ext_type;
37
-
38
39
  ID to_msgpack_method;
39
40
  VALUE to_msgpack_arg;
40
41
 
41
42
  VALUE buffer_ref;
42
43
 
44
+ bool compatibility_mode;
45
+ bool has_bigint_ext_type;
46
+ bool has_symbol_ext_type;
47
+
43
48
  /* options */
44
49
  bool comaptibility_mode;
45
50
  msgpack_packer_ext_registry_t ext_registry;
@@ -404,27 +409,33 @@ static inline bool msgpack_packer_is_utf8_compat_string(VALUE v, int encindex)
404
409
  {
405
410
  return encindex == msgpack_rb_encindex_utf8
406
411
  || encindex == msgpack_rb_encindex_usascii
407
- || (rb_enc_asciicompat(rb_enc_from_index(encindex)) && ENC_CODERANGE_ASCIIONLY(v));
412
+ || ENC_CODERANGE_ASCIIONLY(v);
408
413
  }
409
414
 
410
415
  static inline void msgpack_packer_write_string_value(msgpack_packer_t* pk, VALUE v)
411
416
  {
412
- /* actual return type of RSTRING_LEN is long */
413
- unsigned long len = RSTRING_LEN(v);
414
- if(len > 0xffffffffUL) {
415
- // TODO rb_eArgError?
416
- rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %lu", len, 0xffffffffUL);
417
+ long len = RSTRING_LEN(v);
418
+
419
+ if(RB_UNLIKELY(len > 0xffffffffL)) {
420
+ rb_raise(rb_eArgError, "size of string is too long to pack: %lu bytes should be <= %ld", len, 0xffffffffL);
421
+ UNREACHABLE_RETURN();
422
+ }
423
+
424
+ if (RB_UNLIKELY(pk->compatibility_mode)) {
425
+ msgpack_packer_write_raw_header(pk, (unsigned int)len);
426
+ msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
427
+ return;
417
428
  }
418
429
 
419
- int encindex = ENCODING_GET(v);
420
- if(msgpack_packer_is_binary(v, encindex) && !pk->compatibility_mode) {
430
+ int encindex = ENCODING_GET_INLINED(v);
431
+ if(msgpack_packer_is_binary(v, encindex)) {
421
432
  /* write ASCII-8BIT string using Binary type */
422
433
  msgpack_packer_write_bin_header(pk, (unsigned int)len);
423
434
  msgpack_buffer_append_string(PACKER_BUFFER_(pk), v);
424
435
  } else {
425
436
  /* write UTF-8, US-ASCII, or 7bit-safe ascii-compatible string using String type directly */
426
437
  /* in compatibility mode, packer packs String values as is */
427
- if(!pk->compatibility_mode && !msgpack_packer_is_utf8_compat_string(v, encindex)) {
438
+ if(RB_UNLIKELY(!msgpack_packer_is_utf8_compat_string(v, encindex))) {
428
439
  /* transcode other strings to UTF-8 and write using String type */
429
440
  VALUE enc = rb_enc_from_encoding(rb_utf8_encoding()); /* rb_enc_from_encoding_index is not extern */
430
441
  v = rb_str_encode(v, enc, 0, Qnil);
@@ -453,11 +464,7 @@ static inline void msgpack_packer_write_symbol_value(msgpack_packer_t* pk, VALUE
453
464
 
454
465
  static inline void msgpack_packer_write_fixnum_value(msgpack_packer_t* pk, VALUE v)
455
466
  {
456
- #ifdef JRUBY
457
- msgpack_packer_write_long(pk, FIXNUM_P(v) ? FIX2LONG(v) : rb_num2ll(v));
458
- #else
459
467
  msgpack_packer_write_long(pk, FIX2LONG(v));
460
- #endif
461
468
  }
462
469
 
463
470
  static inline void msgpack_packer_write_bignum_value(msgpack_packer_t* pk, VALUE v)
@@ -26,6 +26,40 @@
26
26
  #define rb_proc_call_with_block(recv, argc, argv, block) rb_funcallv(recv, rb_intern("call"), argc, argv)
27
27
  #endif
28
28
 
29
+ #ifndef HAVE_RB_GC_MARK_LOCATIONS
30
+ // For TruffleRuby
31
+ void rb_gc_mark_locations(const VALUE *start, const VALUE *end)
32
+ {
33
+ VALUE *value = start;
34
+
35
+ while (value < end) {
36
+ rb_gc_mark(*value);
37
+ value++;
38
+ }
39
+ }
40
+ #endif
41
+
42
+ struct protected_proc_call_args {
43
+ VALUE proc;
44
+ int argc;
45
+ VALUE *argv;
46
+ };
47
+
48
+ static VALUE protected_proc_call_safe(VALUE _args) {
49
+ struct protected_proc_call_args *args = (struct protected_proc_call_args *)_args;
50
+
51
+ return rb_proc_call_with_block(args->proc, args->argc, args->argv, Qnil);
52
+ }
53
+
54
+ static VALUE protected_proc_call(VALUE proc, int argc, VALUE *argv, int *raised) {
55
+ struct protected_proc_call_args args = {
56
+ .proc = proc,
57
+ .argc = argc,
58
+ .argv = argv,
59
+ };
60
+ return rb_protect(protected_proc_call_safe, (VALUE)&args, raised);
61
+ }
62
+
29
63
  static int RAW_TYPE_STRING = 256;
30
64
  static int RAW_TYPE_BINARY = 257;
31
65
  static int16_t INITIAL_BUFFER_CAPACITY_MAX = SHRT_MAX;
@@ -58,14 +92,29 @@ void msgpack_unpacker_static_destroy(void)
58
92
 
59
93
  #define HEAD_BYTE_REQUIRED 0xc1
60
94
 
61
- static inline msgpack_unpacker_stack_t* _msgpack_unpacker_new_stack(void) {
62
- msgpack_unpacker_stack_t *stack = ZALLOC(msgpack_unpacker_stack_t);
63
- stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
64
- stack->data = msgpack_rmem_alloc(&s_stack_rmem);
65
- /*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
66
- return stack;
95
+ static inline bool _msgpack_unpacker_stack_init(msgpack_unpacker_stack_t *stack) {
96
+ if (!stack->data) {
97
+ stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
98
+ stack->data = msgpack_rmem_alloc(&s_stack_rmem);
99
+ stack->depth = 0;
100
+ return true;
101
+ }
102
+ return false;
103
+ }
104
+
105
+ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
106
+ if (stack->data) {
107
+ if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
108
+ rb_bug("Failed to free an rmem pointer, memory leak?");
109
+ }
110
+ stack->data = NULL;
111
+ stack->depth = 0;
112
+ }
67
113
  }
68
114
 
115
+ #define STACK_INIT(uk) bool stack_allocated = _msgpack_unpacker_stack_init(&uk->stack);
116
+ #define STACK_FREE(uk) if (stack_allocated) { _msgpack_unpacker_free_stack(&uk->stack); }
117
+
69
118
  void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
70
119
  {
71
120
  msgpack_buffer_init(UNPACKER_BUFFER_(uk));
@@ -74,41 +123,38 @@ void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
74
123
 
75
124
  uk->last_object = Qnil;
76
125
  uk->reading_raw = Qnil;
77
-
78
- uk->stack = _msgpack_unpacker_new_stack();
79
- }
80
-
81
- static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
82
- if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
83
- rb_bug("Failed to free an rmem pointer, memory leak?");
84
- }
85
- xfree(stack);
86
126
  }
87
127
 
88
128
  void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
89
129
  {
90
- _msgpack_unpacker_free_stack(uk->stack);
130
+ _msgpack_unpacker_free_stack(&uk->stack);
91
131
  msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
92
132
  }
93
133
 
94
134
  void msgpack_unpacker_mark_stack(msgpack_unpacker_stack_t* stack)
95
135
  {
96
- while (stack) {
136
+ if (stack->data) {
97
137
  msgpack_unpacker_stack_entry_t* s = stack->data;
98
138
  msgpack_unpacker_stack_entry_t* send = stack->data + stack->depth;
99
139
  for(; s < send; s++) {
100
140
  rb_gc_mark(s->object);
101
141
  rb_gc_mark(s->key);
102
142
  }
103
- stack = stack->parent;
104
143
  }
105
144
  }
106
145
 
146
+ void msgpack_unpacker_mark_key_cache(msgpack_key_cache_t *cache)
147
+ {
148
+ const VALUE *entries = &cache->entries[0];
149
+ rb_gc_mark_locations(entries, entries + cache->length);
150
+ }
151
+
107
152
  void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
108
153
  {
109
154
  rb_gc_mark(uk->last_object);
110
155
  rb_gc_mark(uk->reading_raw);
111
- msgpack_unpacker_mark_stack(uk->stack);
156
+ msgpack_unpacker_mark_stack(&uk->stack);
157
+ msgpack_unpacker_mark_key_cache(&uk->key_cache);
112
158
  /* See MessagePack_Buffer_wrap */
113
159
  /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
114
160
  rb_gc_mark(uk->buffer_ref);
@@ -121,8 +167,8 @@ void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
121
167
 
122
168
  uk->head_byte = HEAD_BYTE_REQUIRED;
123
169
 
124
- /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack->depth);*/
125
- uk->stack->depth = 0;
170
+ /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack.depth);*/
171
+ uk->stack.depth = 0;
126
172
  uk->last_object = Qnil;
127
173
  uk->reading_raw = Qnil;
128
174
  uk->reading_raw_remaining = 0;
@@ -186,7 +232,12 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
186
232
  if(proc != Qnil) {
187
233
  VALUE obj;
188
234
  VALUE arg = (str == Qnil ? rb_str_buf_new(0) : str);
189
- obj = rb_proc_call_with_block(proc, 1, &arg, Qnil);
235
+ int raised;
236
+ obj = protected_proc_call(proc, 1, &arg, &raised);
237
+ if (raised) {
238
+ uk->last_object = rb_errinfo();
239
+ return PRIMITIVE_RECURSIVE_RAISED;
240
+ }
190
241
  return object_complete(uk, obj);
191
242
  }
192
243
 
@@ -201,35 +252,35 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
201
252
  /* stack funcs */
202
253
  static inline msgpack_unpacker_stack_entry_t* _msgpack_unpacker_stack_entry_top(msgpack_unpacker_t* uk)
203
254
  {
204
- return &uk->stack->data[uk->stack->depth-1];
255
+ return &uk->stack.data[uk->stack.depth-1];
205
256
  }
206
257
 
207
258
  static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
208
259
  {
209
260
  reset_head_byte(uk);
210
261
 
211
- if(uk->stack->capacity - uk->stack->depth <= 0) {
262
+ if(uk->stack.capacity - uk->stack.depth <= 0) {
212
263
  return PRIMITIVE_STACK_TOO_DEEP;
213
264
  }
214
265
 
215
- msgpack_unpacker_stack_entry_t* next = &uk->stack->data[uk->stack->depth];
266
+ msgpack_unpacker_stack_entry_t* next = &uk->stack.data[uk->stack.depth];
216
267
  next->count = count;
217
268
  next->type = type;
218
269
  next->object = object;
219
270
  next->key = Qnil;
220
271
 
221
- uk->stack->depth++;
272
+ uk->stack.depth++;
222
273
  return PRIMITIVE_CONTAINER_START;
223
274
  }
224
275
 
225
- static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
276
+ static inline size_t msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
226
277
  {
227
- return --uk->stack->depth;
278
+ return --uk->stack.depth;
228
279
  }
229
280
 
230
281
  static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
231
282
  {
232
- return uk->stack->depth == 0;
283
+ return uk->stack.depth == 0;
233
284
  }
234
285
 
235
286
  #ifdef USE_CASE_RANGE
@@ -248,16 +299,29 @@ static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
248
299
 
249
300
  #endif
250
301
 
302
+ union msgpack_buffer_cast_block_t {
303
+ char buffer[8];
304
+ uint8_t u8;
305
+ uint16_t u16;
306
+ uint32_t u32;
307
+ uint64_t u64;
308
+ int8_t i8;
309
+ int16_t i16;
310
+ int32_t i32;
311
+ int64_t i64;
312
+ float f;
313
+ double d;
314
+ };
251
315
 
252
316
  #define READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, n) \
253
- union msgpack_buffer_cast_block_t* cb = msgpack_buffer_read_cast_block(UNPACKER_BUFFER_(uk), n); \
254
- if(cb == NULL) { \
317
+ union msgpack_buffer_cast_block_t cb; \
318
+ if (!msgpack_buffer_read_all(UNPACKER_BUFFER_(uk), (char *)&cb.buffer, n)) { \
255
319
  return PRIMITIVE_EOF; \
256
320
  }
257
321
 
258
322
  static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
259
323
  {
260
- if(uk->stack->depth > 0) {
324
+ if(uk->stack.depth > 0) {
261
325
  msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
262
326
  if(top->type == STACK_TYPE_MAP_KEY) {
263
327
  return true;
@@ -312,14 +376,15 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
312
376
  reset_head_byte(uk);
313
377
  uk->reading_raw_remaining = 0;
314
378
 
315
- msgpack_unpacker_stack_t* child_stack = _msgpack_unpacker_new_stack();
316
- child_stack->parent = uk->stack;
317
- uk->stack = child_stack;
379
+ _msgpack_unpacker_stack_push(uk, STACK_TYPE_RECURSIVE, 1, Qnil);
380
+ int raised;
381
+ obj = protected_proc_call(proc, 1, &uk->self, &raised);
382
+ msgpack_unpacker_stack_pop(uk);
318
383
 
319
- obj = rb_proc_call_with_block(proc, 1, &uk->self, Qnil);
320
-
321
- uk->stack = child_stack->parent;
322
- _msgpack_unpacker_free_stack(child_stack);
384
+ if (raised) {
385
+ uk->last_object = rb_errinfo();
386
+ return PRIMITIVE_RECURSIVE_RAISED;
387
+ }
323
388
 
324
389
  return object_complete(uk, obj);
325
390
  }
@@ -329,15 +394,32 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
329
394
  size_t length = uk->reading_raw_remaining;
330
395
  if(length <= msgpack_buffer_top_readable_size(UNPACKER_BUFFER_(uk))) {
331
396
  int ret;
332
- if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type) || (uk->symbolize_keys && is_reading_map_key(uk))) {
397
+ if ((uk->optimized_symbol_ext_type && uk->symbol_ext_type == raw_type)) {
333
398
  VALUE symbol = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length, raw_type != RAW_TYPE_BINARY);
334
399
  ret = object_complete_symbol(uk, symbol);
400
+ } else if (is_reading_map_key(uk) && raw_type == RAW_TYPE_STRING) {
401
+ /* don't use zerocopy for hash keys but get a frozen string directly
402
+ * because rb_hash_aset freezes keys and it causes copying */
403
+ VALUE key;
404
+ if (uk->symbolize_keys) {
405
+ if (uk->use_key_cache) {
406
+ key = msgpack_buffer_read_top_as_interned_symbol(UNPACKER_BUFFER_(uk), &uk->key_cache, length);
407
+ } else {
408
+ key = msgpack_buffer_read_top_as_symbol(UNPACKER_BUFFER_(uk), length, true);
409
+ }
410
+ ret = object_complete_symbol(uk, key);
411
+ } else {
412
+ if (uk->use_key_cache) {
413
+ key = msgpack_buffer_read_top_as_interned_string(UNPACKER_BUFFER_(uk), &uk->key_cache, length);
414
+ } else {
415
+ key = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, true, true);
416
+ }
417
+
418
+ ret = object_complete(uk, key);
419
+ }
335
420
  } else {
336
421
  bool will_freeze = uk->freeze;
337
422
  if(raw_type == RAW_TYPE_STRING || raw_type == RAW_TYPE_BINARY) {
338
- /* don't use zerocopy for hash keys but get a frozen string directly
339
- * because rb_hash_aset freezes keys and it causes copying */
340
- will_freeze = will_freeze || is_reading_map_key(uk);
341
423
  VALUE string = msgpack_buffer_read_top_as_string(UNPACKER_BUFFER_(uk), length, will_freeze, raw_type == RAW_TYPE_STRING);
342
424
  ret = object_complete(uk, string);
343
425
  } else {
@@ -407,8 +489,8 @@ static int read_primitive(msgpack_unpacker_t* uk)
407
489
  case 0xc7: // ext 8
408
490
  {
409
491
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
410
- uint8_t length = cb->u8;
411
- int ext_type = (signed char) cb->buffer[1];
492
+ uint8_t length = cb.u8;
493
+ int ext_type = (signed char) cb.buffer[1];
412
494
  if(length == 0) {
413
495
  return object_complete_ext(uk, ext_type, Qnil);
414
496
  }
@@ -419,8 +501,8 @@ static int read_primitive(msgpack_unpacker_t* uk)
419
501
  case 0xc8: // ext 16
420
502
  {
421
503
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 3);
422
- uint16_t length = _msgpack_be16(cb->u16);
423
- int ext_type = (signed char) cb->buffer[2];
504
+ uint16_t length = _msgpack_be16(cb.u16);
505
+ int ext_type = (signed char) cb.buffer[2];
424
506
  if(length == 0) {
425
507
  return object_complete_ext(uk, ext_type, Qnil);
426
508
  }
@@ -431,8 +513,8 @@ static int read_primitive(msgpack_unpacker_t* uk)
431
513
  case 0xc9: // ext 32
432
514
  {
433
515
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 5);
434
- uint32_t length = _msgpack_be32(cb->u32);
435
- int ext_type = (signed char) cb->buffer[4];
516
+ uint32_t length = _msgpack_be32(cb.u32);
517
+ int ext_type = (signed char) cb.buffer[4];
436
518
  if(length == 0) {
437
519
  return object_complete_ext(uk, ext_type, Qnil);
438
520
  }
@@ -443,77 +525,77 @@ static int read_primitive(msgpack_unpacker_t* uk)
443
525
  case 0xca: // float
444
526
  {
445
527
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
446
- cb->u32 = _msgpack_be_float(cb->u32);
447
- return object_complete(uk, rb_float_new(cb->f));
528
+ cb.u32 = _msgpack_be_float(cb.u32);
529
+ return object_complete(uk, rb_float_new(cb.f));
448
530
  }
449
531
 
450
532
  case 0xcb: // double
451
533
  {
452
534
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8);
453
- cb->u64 = _msgpack_be_double(cb->u64);
454
- return object_complete(uk, rb_float_new(cb->d));
535
+ cb.u64 = _msgpack_be_double(cb.u64);
536
+ return object_complete(uk, rb_float_new(cb.d));
455
537
  }
456
538
 
457
539
  case 0xcc: // unsigned int 8
458
540
  {
459
541
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
460
- uint8_t u8 = cb->u8;
542
+ uint8_t u8 = cb.u8;
461
543
  return object_complete(uk, INT2NUM((int)u8));
462
544
  }
463
545
 
464
546
  case 0xcd: // unsigned int 16
465
547
  {
466
548
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
467
- uint16_t u16 = _msgpack_be16(cb->u16);
549
+ uint16_t u16 = _msgpack_be16(cb.u16);
468
550
  return object_complete(uk, INT2NUM((int)u16));
469
551
  }
470
552
 
471
553
  case 0xce: // unsigned int 32
472
554
  {
473
555
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
474
- uint32_t u32 = _msgpack_be32(cb->u32);
556
+ uint32_t u32 = _msgpack_be32(cb.u32);
475
557
  return object_complete(uk, ULONG2NUM(u32)); // long at least 32 bits
476
558
  }
477
559
 
478
560
  case 0xcf: // unsigned int 64
479
561
  {
480
562
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8);
481
- uint64_t u64 = _msgpack_be64(cb->u64);
563
+ uint64_t u64 = _msgpack_be64(cb.u64);
482
564
  return object_complete(uk, rb_ull2inum(u64));
483
565
  }
484
566
 
485
567
  case 0xd0: // signed int 8
486
568
  {
487
569
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
488
- int8_t i8 = cb->i8;
570
+ int8_t i8 = cb.i8;
489
571
  return object_complete(uk, INT2NUM((int)i8));
490
572
  }
491
573
 
492
574
  case 0xd1: // signed int 16
493
575
  {
494
576
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
495
- int16_t i16 = _msgpack_be16(cb->i16);
577
+ int16_t i16 = _msgpack_be16(cb.i16);
496
578
  return object_complete(uk, INT2NUM((int)i16));
497
579
  }
498
580
 
499
581
  case 0xd2: // signed int 32
500
582
  {
501
583
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
502
- int32_t i32 = _msgpack_be32(cb->i32);
584
+ int32_t i32 = _msgpack_be32(cb.i32);
503
585
  return object_complete(uk, LONG2NUM(i32)); // long at least 32 bits
504
586
  }
505
587
 
506
588
  case 0xd3: // signed int 64
507
589
  {
508
590
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 8);
509
- int64_t i64 = _msgpack_be64(cb->i64);
591
+ int64_t i64 = _msgpack_be64(cb.i64);
510
592
  return object_complete(uk, rb_ll2inum(i64));
511
593
  }
512
594
 
513
595
  case 0xd4: // fixext 1
514
596
  {
515
597
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
516
- int ext_type = cb->i8;
598
+ int ext_type = cb.i8;
517
599
  uk->reading_raw_remaining = 1;
518
600
  return read_raw_body_begin(uk, ext_type);
519
601
  }
@@ -521,7 +603,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
521
603
  case 0xd5: // fixext 2
522
604
  {
523
605
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
524
- int ext_type = cb->i8;
606
+ int ext_type = cb.i8;
525
607
  uk->reading_raw_remaining = 2;
526
608
  return read_raw_body_begin(uk, ext_type);
527
609
  }
@@ -529,7 +611,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
529
611
  case 0xd6: // fixext 4
530
612
  {
531
613
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
532
- int ext_type = cb->i8;
614
+ int ext_type = cb.i8;
533
615
  uk->reading_raw_remaining = 4;
534
616
  return read_raw_body_begin(uk, ext_type);
535
617
  }
@@ -537,7 +619,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
537
619
  case 0xd7: // fixext 8
538
620
  {
539
621
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
540
- int ext_type = cb->i8;
622
+ int ext_type = cb.i8;
541
623
  uk->reading_raw_remaining = 8;
542
624
  return read_raw_body_begin(uk, ext_type);
543
625
  }
@@ -545,7 +627,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
545
627
  case 0xd8: // fixext 16
546
628
  {
547
629
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
548
- int ext_type = cb->i8;
630
+ int ext_type = cb.i8;
549
631
  uk->reading_raw_remaining = 16;
550
632
  return read_raw_body_begin(uk, ext_type);
551
633
  }
@@ -554,7 +636,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
554
636
  case 0xd9: // raw 8 / str 8
555
637
  {
556
638
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
557
- uint8_t count = cb->u8;
639
+ uint8_t count = cb.u8;
558
640
  /* read_raw_body_begin sets uk->reading_raw */
559
641
  uk->reading_raw_remaining = count;
560
642
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -563,7 +645,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
563
645
  case 0xda: // raw 16 / str 16
564
646
  {
565
647
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
566
- uint16_t count = _msgpack_be16(cb->u16);
648
+ uint16_t count = _msgpack_be16(cb.u16);
567
649
  /* read_raw_body_begin sets uk->reading_raw */
568
650
  uk->reading_raw_remaining = count;
569
651
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -572,7 +654,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
572
654
  case 0xdb: // raw 32 / str 32
573
655
  {
574
656
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
575
- uint32_t count = _msgpack_be32(cb->u32);
657
+ uint32_t count = _msgpack_be32(cb.u32);
576
658
  /* read_raw_body_begin sets uk->reading_raw */
577
659
  uk->reading_raw_remaining = count;
578
660
  return read_raw_body_begin(uk, RAW_TYPE_STRING);
@@ -581,7 +663,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
581
663
  case 0xc4: // bin 8
582
664
  {
583
665
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 1);
584
- uint8_t count = cb->u8;
666
+ uint8_t count = cb.u8;
585
667
  /* read_raw_body_begin sets uk->reading_raw */
586
668
  uk->reading_raw_remaining = count;
587
669
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -590,7 +672,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
590
672
  case 0xc5: // bin 16
591
673
  {
592
674
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
593
- uint16_t count = _msgpack_be16(cb->u16);
675
+ uint16_t count = _msgpack_be16(cb.u16);
594
676
  /* read_raw_body_begin sets uk->reading_raw */
595
677
  uk->reading_raw_remaining = count;
596
678
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -599,7 +681,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
599
681
  case 0xc6: // bin 32
600
682
  {
601
683
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
602
- uint32_t count = _msgpack_be32(cb->u32);
684
+ uint32_t count = _msgpack_be32(cb.u32);
603
685
  /* read_raw_body_begin sets uk->reading_raw */
604
686
  uk->reading_raw_remaining = count;
605
687
  return read_raw_body_begin(uk, RAW_TYPE_BINARY);
@@ -608,7 +690,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
608
690
  case 0xdc: // array 16
609
691
  {
610
692
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
611
- uint16_t count = _msgpack_be16(cb->u16);
693
+ uint16_t count = _msgpack_be16(cb.u16);
612
694
  if(count == 0) {
613
695
  return object_complete(uk, rb_ary_new());
614
696
  }
@@ -618,7 +700,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
618
700
  case 0xdd: // array 32
619
701
  {
620
702
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
621
- uint32_t count = _msgpack_be32(cb->u32);
703
+ uint32_t count = _msgpack_be32(cb.u32);
622
704
  if(count == 0) {
623
705
  return object_complete(uk, rb_ary_new());
624
706
  }
@@ -628,7 +710,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
628
710
  case 0xde: // map 16
629
711
  {
630
712
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
631
- uint16_t count = _msgpack_be16(cb->u16);
713
+ uint16_t count = _msgpack_be16(cb.u16);
632
714
  if(count == 0) {
633
715
  return object_complete(uk, rb_hash_new());
634
716
  }
@@ -638,7 +720,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
638
720
  case 0xdf: // map 32
639
721
  {
640
722
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
641
- uint32_t count = _msgpack_be32(cb->u32);
723
+ uint32_t count = _msgpack_be32(cb.u32);
642
724
  if(count == 0) {
643
725
  return object_complete(uk, rb_hash_new());
644
726
  }
@@ -668,12 +750,12 @@ int msgpack_unpacker_read_array_header(msgpack_unpacker_t* uk, uint32_t* result_
668
750
  } else if(b == 0xdc) {
669
751
  /* array 16 */
670
752
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
671
- *result_size = _msgpack_be16(cb->u16);
753
+ *result_size = _msgpack_be16(cb.u16);
672
754
 
673
755
  } else if(b == 0xdd) {
674
756
  /* array 32 */
675
757
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
676
- *result_size = _msgpack_be32(cb->u32);
758
+ *result_size = _msgpack_be32(cb.u32);
677
759
 
678
760
  } else {
679
761
  return PRIMITIVE_UNEXPECTED_TYPE;
@@ -696,12 +778,12 @@ int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint32_t* result_si
696
778
  } else if(b == 0xde) {
697
779
  /* map 16 */
698
780
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 2);
699
- *result_size = _msgpack_be16(cb->u16);
781
+ *result_size = _msgpack_be16(cb.u16);
700
782
 
701
783
  } else if(b == 0xdf) {
702
784
  /* map 32 */
703
785
  READ_CAST_BLOCK_OR_RETURN_EOF(cb, uk, 4);
704
- *result_size = _msgpack_be32(cb->u32);
786
+ *result_size = _msgpack_be32(cb.u32);
705
787
 
706
788
  } else {
707
789
  return PRIMITIVE_UNEXPECTED_TYPE;
@@ -713,9 +795,15 @@ int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint32_t* result_si
713
795
 
714
796
  int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
715
797
  {
798
+ STACK_INIT(uk);
799
+
716
800
  while(true) {
717
801
  int r = read_primitive(uk);
718
802
  if(r < 0) {
803
+ if (r != PRIMITIVE_EOF) {
804
+ // We keep the stack on EOF as the parsing may be resumed.
805
+ STACK_FREE(uk);
806
+ }
719
807
  return r;
720
808
  }
721
809
  if(r == PRIMITIVE_CONTAINER_START) {
@@ -724,6 +812,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
724
812
  /* PRIMITIVE_OBJECT_COMPLETE */
725
813
 
726
814
  if(msgpack_unpacker_stack_is_empty(uk)) {
815
+ STACK_FREE(uk);
727
816
  return PRIMITIVE_OBJECT_COMPLETE;
728
817
  }
729
818
 
@@ -747,12 +836,16 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
747
836
  }
748
837
  top->type = STACK_TYPE_MAP_KEY;
749
838
  break;
839
+ case STACK_TYPE_RECURSIVE:
840
+ STACK_FREE(uk);
841
+ return PRIMITIVE_OBJECT_COMPLETE;
750
842
  }
751
843
  size_t count = --top->count;
752
844
 
753
845
  if(count == 0) {
754
846
  object_complete(uk, top->object);
755
847
  if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
848
+ STACK_FREE(uk);
756
849
  return PRIMITIVE_OBJECT_COMPLETE;
757
850
  }
758
851
  goto container_completed;
@@ -763,9 +856,12 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
763
856
 
764
857
  int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
765
858
  {
859
+ STACK_INIT(uk);
860
+
766
861
  while(true) {
767
862
  int r = read_primitive(uk);
768
863
  if(r < 0) {
864
+ STACK_FREE(uk);
769
865
  return r;
770
866
  }
771
867
  if(r == PRIMITIVE_CONTAINER_START) {
@@ -774,6 +870,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
774
870
  /* PRIMITIVE_OBJECT_COMPLETE */
775
871
 
776
872
  if(msgpack_unpacker_stack_is_empty(uk)) {
873
+ STACK_FREE(uk);
777
874
  return PRIMITIVE_OBJECT_COMPLETE;
778
875
  }
779
876
 
@@ -789,6 +886,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
789
886
  if(count == 0) {
790
887
  object_complete(uk, Qnil);
791
888
  if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
889
+ STACK_FREE(uk);
792
890
  return PRIMITIVE_OBJECT_COMPLETE;
793
891
  }
794
892
  goto container_completed;
@@ -31,6 +31,7 @@ enum stack_type_t {
31
31
  STACK_TYPE_ARRAY,
32
32
  STACK_TYPE_MAP_KEY,
33
33
  STACK_TYPE_MAP_VALUE,
34
+ STACK_TYPE_RECURSIVE,
34
35
  };
35
36
 
36
37
  typedef struct {
@@ -44,31 +45,34 @@ struct msgpack_unpacker_stack_t {
44
45
  size_t depth;
45
46
  size_t capacity;
46
47
  msgpack_unpacker_stack_entry_t *data;
47
- msgpack_unpacker_stack_t *parent;
48
48
  };
49
49
 
50
50
  struct msgpack_unpacker_t {
51
51
  msgpack_buffer_t buffer;
52
- msgpack_unpacker_stack_t *stack;
53
- unsigned int head_byte;
52
+ msgpack_unpacker_stack_t stack;
53
+ msgpack_key_cache_t key_cache;
54
54
 
55
55
  VALUE self;
56
56
  VALUE last_object;
57
57
 
58
58
  VALUE reading_raw;
59
59
  size_t reading_raw_remaining;
60
- int reading_raw_type;
61
60
 
62
61
  VALUE buffer_ref;
63
62
 
64
63
  msgpack_unpacker_ext_registry_t *ext_registry;
65
64
 
65
+ int reading_raw_type;
66
+ unsigned int head_byte;
67
+
66
68
  /* options */
67
- bool symbolize_keys;
68
- bool freeze;
69
- bool allow_unknown_ext;
70
- bool optimized_symbol_ext_type;
71
69
  int symbol_ext_type;
70
+
71
+ bool use_key_cache: 1;
72
+ bool symbolize_keys: 1;
73
+ bool freeze: 1;
74
+ bool allow_unknown_ext: 1;
75
+ bool optimized_symbol_ext_type: 1;
72
76
  };
73
77
 
74
78
  #define UNPACKER_BUFFER_(uk) (&(uk)->buffer)
@@ -100,6 +104,11 @@ static inline void msgpack_unpacker_set_symbolized_keys(msgpack_unpacker_t* uk,
100
104
  uk->symbolize_keys = enable;
101
105
  }
102
106
 
107
+ static inline void msgpack_unpacker_set_key_cache(msgpack_unpacker_t* uk, bool enable)
108
+ {
109
+ uk->use_key_cache = enable;
110
+ }
111
+
103
112
  static inline void msgpack_unpacker_set_freeze(msgpack_unpacker_t* uk, bool enable)
104
113
  {
105
114
  uk->freeze = enable;
@@ -119,6 +128,7 @@ static inline void msgpack_unpacker_set_allow_unknown_ext(msgpack_unpacker_t* uk
119
128
  #define PRIMITIVE_STACK_TOO_DEEP -3
120
129
  #define PRIMITIVE_UNEXPECTED_TYPE -4
121
130
  #define PRIMITIVE_UNEXPECTED_EXT_TYPE -5
131
+ #define PRIMITIVE_RECURSIVE_RAISED -6
122
132
 
123
133
  int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth);
124
134
 
@@ -34,6 +34,7 @@ static VALUE eUnknownExtTypeError;
34
34
  static VALUE mTypeError; // obsoleted. only for backward compatibility. See #86.
35
35
 
36
36
  static VALUE sym_symbolize_keys;
37
+ static VALUE sym_key_cache;
37
38
  static VALUE sym_freeze;
38
39
  static VALUE sym_allow_unknown_ext;
39
40
 
@@ -58,14 +59,17 @@ static void Unpacker_mark(void *ptr)
58
59
 
59
60
  static size_t Unpacker_memsize(const void *ptr)
60
61
  {
62
+ const msgpack_unpacker_t* uk = ptr;
63
+
61
64
  size_t total_size = sizeof(msgpack_unpacker_t);
62
65
 
63
- const msgpack_unpacker_t* uk = ptr;
64
66
  if (uk->ext_registry) {
65
67
  total_size += sizeof(msgpack_unpacker_ext_registry_t) / (uk->ext_registry->borrow_count + 1);
66
68
  }
67
69
 
68
- total_size += (uk->stack->depth + 1) * sizeof(msgpack_unpacker_stack_t);
70
+ if (uk->stack.data) {
71
+ total_size += (uk->stack.depth + 1) * sizeof(msgpack_unpacker_stack_t);
72
+ }
69
73
 
70
74
  return total_size + msgpack_buffer_memsize(&uk->buffer);
71
75
  }
@@ -125,6 +129,9 @@ VALUE MessagePack_Unpacker_initialize(int argc, VALUE* argv, VALUE self)
125
129
  if(options != Qnil) {
126
130
  VALUE v;
127
131
 
132
+ v = rb_hash_aref(options, sym_key_cache);
133
+ msgpack_unpacker_set_key_cache(uk, RTEST(v));
134
+
128
135
  v = rb_hash_aref(options, sym_symbolize_keys);
129
136
  msgpack_unpacker_set_symbolized_keys(uk, RTEST(v));
130
137
 
@@ -156,20 +163,28 @@ static VALUE Unpacker_allow_unknown_ext_p(VALUE self)
156
163
  return uk->allow_unknown_ext ? Qtrue : Qfalse;
157
164
  }
158
165
 
159
- NORETURN(static void raise_unpacker_error(int r))
166
+ NORETURN(static void raise_unpacker_error(msgpack_unpacker_t *uk, int r))
160
167
  {
168
+ uk->stack.depth = 0;
161
169
  switch(r) {
162
170
  case PRIMITIVE_EOF:
163
171
  rb_raise(rb_eEOFError, "end of buffer reached");
172
+ break;
164
173
  case PRIMITIVE_INVALID_BYTE:
165
174
  rb_raise(eMalformedFormatError, "invalid byte");
175
+ break;
166
176
  case PRIMITIVE_STACK_TOO_DEEP:
167
177
  rb_raise(eStackError, "stack level too deep");
178
+ break;
168
179
  case PRIMITIVE_UNEXPECTED_TYPE:
169
180
  rb_raise(eUnexpectedTypeError, "unexpected type");
181
+ break;
170
182
  case PRIMITIVE_UNEXPECTED_EXT_TYPE:
171
- // rb_bug("unexpected extension type");
172
183
  rb_raise(eUnknownExtTypeError, "unexpected extension type");
184
+ break;
185
+ case PRIMITIVE_RECURSIVE_RAISED:
186
+ rb_exc_raise(msgpack_unpacker_get_last_object(uk));
187
+ break;
173
188
  default:
174
189
  rb_raise(eUnpackError, "logically unknown error %d", r);
175
190
  }
@@ -190,7 +205,7 @@ static VALUE Unpacker_read(VALUE self)
190
205
 
191
206
  int r = msgpack_unpacker_read(uk, 0);
192
207
  if(r < 0) {
193
- raise_unpacker_error(r);
208
+ raise_unpacker_error(uk, r);
194
209
  }
195
210
 
196
211
  return msgpack_unpacker_get_last_object(uk);
@@ -202,7 +217,7 @@ static VALUE Unpacker_skip(VALUE self)
202
217
 
203
218
  int r = msgpack_unpacker_skip(uk, 0);
204
219
  if(r < 0) {
205
- raise_unpacker_error(r);
220
+ raise_unpacker_error(uk, r);
206
221
  }
207
222
 
208
223
  return Qnil;
@@ -214,7 +229,7 @@ static VALUE Unpacker_skip_nil(VALUE self)
214
229
 
215
230
  int r = msgpack_unpacker_skip_nil(uk);
216
231
  if(r < 0) {
217
- raise_unpacker_error(r);
232
+ raise_unpacker_error(uk, r);
218
233
  }
219
234
 
220
235
  if(r) {
@@ -230,7 +245,7 @@ static VALUE Unpacker_read_array_header(VALUE self)
230
245
  uint32_t size;
231
246
  int r = msgpack_unpacker_read_array_header(uk, &size);
232
247
  if(r < 0) {
233
- raise_unpacker_error(r);
248
+ raise_unpacker_error(uk, r);
234
249
  }
235
250
 
236
251
  return ULONG2NUM(size); // long at least 32 bits
@@ -243,7 +258,7 @@ static VALUE Unpacker_read_map_header(VALUE self)
243
258
  uint32_t size;
244
259
  int r = msgpack_unpacker_read_map_header(uk, &size);
245
260
  if(r < 0) {
246
- raise_unpacker_error((int)r);
261
+ raise_unpacker_error(uk, r);
247
262
  }
248
263
 
249
264
  return ULONG2NUM(size); // long at least 32 bits
@@ -270,15 +285,9 @@ static VALUE Unpacker_each_impl(VALUE self)
270
285
  if(r == PRIMITIVE_EOF) {
271
286
  return Qnil;
272
287
  }
273
- raise_unpacker_error(r);
288
+ raise_unpacker_error(uk, r);
274
289
  }
275
290
  VALUE v = msgpack_unpacker_get_last_object(uk);
276
- #ifdef JRUBY
277
- /* TODO JRuby's rb_yield behaves differently from Ruby 1.9.3 or Rubinius. */
278
- if(rb_type(v) == T_ARRAY) {
279
- v = rb_ary_new3(1, v);
280
- }
281
- #endif
282
291
  rb_yield(v);
283
292
  }
284
293
  }
@@ -369,7 +378,7 @@ static VALUE Unpacker_full_unpack(VALUE self)
369
378
 
370
379
  int r = msgpack_unpacker_read(uk, 0);
371
380
  if(r < 0) {
372
- raise_unpacker_error(r);
381
+ raise_unpacker_error(uk, r);
373
382
  }
374
383
 
375
384
  /* raise if extra bytes follow */
@@ -408,6 +417,7 @@ void MessagePack_Unpacker_module_init(VALUE mMessagePack)
408
417
  eUnknownExtTypeError = rb_define_class_under(mMessagePack, "UnknownExtTypeError", eUnpackError);
409
418
 
410
419
  sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
420
+ sym_key_cache = ID2SYM(rb_intern("key_cache"));
411
421
  sym_freeze = ID2SYM(rb_intern("freeze"));
412
422
  sym_allow_unknown_ext = ID2SYM(rb_intern("allow_unknown_ext"));
413
423
 
@@ -1,5 +1,5 @@
1
1
  module MessagePack
2
- VERSION = "1.7.3"
2
+ VERSION = "1.8.0"
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
@@ -31,4 +31,6 @@ Gem::Specification.new do |s|
31
31
  s.add_development_dependency 'yard'
32
32
  s.add_development_dependency 'json'
33
33
  s.add_development_dependency 'benchmark-ips', ['~> 2.10.0']
34
+
35
+ s.metadata["changelog_uri"] = "https://github.com/msgpack/msgpack-ruby/blob/master/ChangeLog"
34
36
  end
metadata CHANGED
@@ -1,16 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: msgpack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.3
4
+ version: 1.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sadayuki Furuhashi
8
8
  - Theo Hultberg
9
9
  - Satoshi Tagomori
10
- autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2024-10-04 00:00:00.000000000 Z
12
+ date: 2025-02-06 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: bundler
@@ -192,8 +191,8 @@ files:
192
191
  homepage: http://msgpack.org/
193
192
  licenses:
194
193
  - Apache 2.0
195
- metadata: {}
196
- post_install_message:
194
+ metadata:
195
+ changelog_uri: https://github.com/msgpack/msgpack-ruby/blob/master/ChangeLog
197
196
  rdoc_options: []
198
197
  require_paths:
199
198
  - lib
@@ -208,8 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
208
207
  - !ruby/object:Gem::Version
209
208
  version: '0'
210
209
  requirements: []
211
- rubygems_version: 3.5.11
212
- signing_key:
210
+ rubygems_version: 3.6.2
213
211
  specification_version: 4
214
212
  summary: MessagePack, a binary-based efficient data interchange format.
215
213
  test_files: []