Fix crashes caused by unchecked memory allocation in Ruby library
diff --git a/lib/rb/ext/struct.c b/lib/rb/ext/struct.c
index b61b995..cdc11db 100644
--- a/lib/rb/ext/struct.c
+++ b/lib/rb/ext/struct.c
@@ -35,6 +35,19 @@
 #define IS_CONTAINER(ttype) ((ttype) == TTYPE_MAP || (ttype) == TTYPE_LIST || (ttype) == TTYPE_SET)
 #define STRUCT_FIELDS(obj) rb_const_get(CLASS_OF(obj), fields_const_id)
 
+static VALUE new_container_array(int size) {
+  if (size < 0) {
+    rb_exc_raise(
+      get_protocol_exception(
+        INT2FIX(PROTOERR_NEGATIVE_SIZE),
+        rb_str_new2("Negative container size")
+      )
+    );
+  }
+
+  return rb_ary_new2(size > 1024 ? 1024 : size);
+}
+
 //-------------------------------------------
 // Writing section
 //-------------------------------------------
@@ -483,6 +496,10 @@
     int value_ttype = FIX2INT(rb_ary_entry(map_header, 1));
     int num_entries = FIX2INT(rb_ary_entry(map_header, 2));
 
+    if (num_entries < 0) {
+      rb_exc_raise(get_protocol_exception(INT2FIX(PROTOERR_NEGATIVE_SIZE), rb_str_new2("Negative container size")));
+    }
+
     // Check the declared key and value types against the expected ones and skip the map contents
     // if the types don't match.
     VALUE key_info = rb_hash_aref(field_info, key_sym);
@@ -523,7 +540,7 @@
     if (!NIL_P(element_info)) {
       int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
       if (specified_element_type == element_ttype) {
-        result = rb_ary_new2(num_elements);
+        result = new_container_array(num_elements);
 
         for (i = 0; i < num_elements; ++i) {
           rb_ary_push(result, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));
@@ -550,7 +567,7 @@
     if (!NIL_P(element_info)) {
       int specified_element_type = FIX2INT(rb_hash_aref(element_info, type_sym));
       if (specified_element_type == element_ttype) {
-        items = rb_ary_new2(num_elements);
+        items = new_container_array(num_elements);
 
         for (i = 0; i < num_elements; ++i) {
           rb_ary_push(items, read_anything(protocol, element_ttype, rb_hash_aref(field_info, element_sym)));