Skip to content

Commit 83a2600

Browse files
authored
Merge pull request #376 from Shopify/lazy-allocate-stack
Lazily allocate and eagerly free unpacker stack
2 parents 0737d2e + 8506279 commit 83a2600

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

ext/msgpack/unpacker.c

+35-13
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,29 @@ void msgpack_unpacker_static_destroy(void)
7979

8080
#define HEAD_BYTE_REQUIRED 0xc1
8181

82-
static inline void _msgpack_unpacker_stack_init(msgpack_unpacker_stack_t *stack) {
83-
stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
84-
stack->data = msgpack_rmem_alloc(&s_stack_rmem);
82+
static inline bool _msgpack_unpacker_stack_init(msgpack_unpacker_stack_t *stack) {
83+
if (!stack->data) {
84+
stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
85+
stack->data = msgpack_rmem_alloc(&s_stack_rmem);
86+
stack->depth = 0;
87+
return true;
88+
}
89+
return false;
8590
}
8691

92+
static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
93+
if (stack->data) {
94+
if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
95+
rb_bug("Failed to free an rmem pointer, memory leak?");
96+
}
97+
stack->data = NULL;
98+
stack->depth = 0;
99+
}
100+
}
101+
102+
#define STACK_INIT(uk) bool stack_allocated = _msgpack_unpacker_stack_init(&uk->stack);
103+
#define STACK_FREE(uk) if (stack_allocated) { _msgpack_unpacker_free_stack(&uk->stack); }
104+
87105
void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
88106
{
89107
msgpack_buffer_init(UNPACKER_BUFFER_(uk));
@@ -92,16 +110,6 @@ void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
92110

93111
uk->last_object = Qnil;
94112
uk->reading_raw = Qnil;
95-
96-
_msgpack_unpacker_stack_init(&uk->stack);
97-
}
98-
99-
static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
100-
if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
101-
rb_bug("Failed to free an rmem pointer, memory leak?");
102-
}
103-
stack->data = NULL;
104-
stack->depth = 0;
105113
}
106114

107115
void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
@@ -750,9 +758,15 @@ int msgpack_unpacker_read_map_header(msgpack_unpacker_t* uk, uint32_t* result_si
750758

751759
int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
752760
{
761+
STACK_INIT(uk);
762+
753763
while(true) {
754764
int r = read_primitive(uk);
755765
if(r < 0) {
766+
if (r != PRIMITIVE_EOF) {
767+
// We keep the stack on EOF as the parsing may be resumed.
768+
STACK_FREE(uk);
769+
}
756770
return r;
757771
}
758772
if(r == PRIMITIVE_CONTAINER_START) {
@@ -761,6 +775,7 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
761775
/* PRIMITIVE_OBJECT_COMPLETE */
762776

763777
if(msgpack_unpacker_stack_is_empty(uk)) {
778+
STACK_FREE(uk);
764779
return PRIMITIVE_OBJECT_COMPLETE;
765780
}
766781

@@ -785,13 +800,15 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
785800
top->type = STACK_TYPE_MAP_KEY;
786801
break;
787802
case STACK_TYPE_RECURSIVE:
803+
STACK_FREE(uk);
788804
return PRIMITIVE_OBJECT_COMPLETE;
789805
}
790806
size_t count = --top->count;
791807

792808
if(count == 0) {
793809
object_complete(uk, top->object);
794810
if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
811+
STACK_FREE(uk);
795812
return PRIMITIVE_OBJECT_COMPLETE;
796813
}
797814
goto container_completed;
@@ -802,9 +819,12 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
802819

803820
int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
804821
{
822+
STACK_INIT(uk);
823+
805824
while(true) {
806825
int r = read_primitive(uk);
807826
if(r < 0) {
827+
STACK_FREE(uk);
808828
return r;
809829
}
810830
if(r == PRIMITIVE_CONTAINER_START) {
@@ -813,6 +833,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
813833
/* PRIMITIVE_OBJECT_COMPLETE */
814834

815835
if(msgpack_unpacker_stack_is_empty(uk)) {
836+
STACK_FREE(uk);
816837
return PRIMITIVE_OBJECT_COMPLETE;
817838
}
818839

@@ -828,6 +849,7 @@ int msgpack_unpacker_skip(msgpack_unpacker_t* uk, size_t target_stack_depth)
828849
if(count == 0) {
829850
object_complete(uk, Qnil);
830851
if(msgpack_unpacker_stack_pop(uk) <= target_stack_depth) {
852+
STACK_FREE(uk);
831853
return PRIMITIVE_OBJECT_COMPLETE;
832854
}
833855
goto container_completed;

0 commit comments

Comments
 (0)