Fix crashes caused by unchecked memory allocation in Ruby library
diff --git a/lib/rb/spec/struct_spec.rb b/lib/rb/spec/struct_spec.rb
index 9349686..36c738e 100644
--- a/lib/rb/spec/struct_spec.rb
+++ b/lib/rb/spec/struct_spec.rb
@@ -142,6 +142,34 @@
       expect(struct.shorts).to eq(Set.new([3, 2]))
     end
 
+    it "rejects negative container sizes while reading" do
+      struct = SpecNamespace::Foo.new
+      prot = Thrift::BaseProtocol.new(double("transport"))
+
+      expect(prot).to receive(:read_list_begin).and_return([Thrift::Types::I32, -1])
+
+      expect {
+        struct.send(:read_field, prot, SpecNamespace::Foo::FIELDS[4])
+      }.to raise_error(Thrift::ProtocolException, "Negative size") { |error|
+        expect(error.type).to eq(Thrift::ProtocolException::NEGATIVE_SIZE)
+      }
+    end
+
+    it "does not preallocate arrays from declared list sizes" do
+      struct = SpecNamespace::Foo.new
+      prot = Thrift::BaseProtocol.new(double("transport"))
+      declared_size = 1 << 30
+      sentinel = RuntimeError.new("stop after first element")
+
+      expect(prot).to receive(:read_list_begin).and_return([Thrift::Types::I32, declared_size])
+      expect(prot).to receive(:read_i32).and_raise(sentinel)
+      expect(Array).not_to receive(:new).with(declared_size)
+
+      expect {
+        struct.send(:read_field, prot, SpecNamespace::Foo::FIELDS[4])
+      }.to raise_error(sentinel)
+    end
+
     it "should serialize false boolean fields correctly" do
       b = SpecNamespace::BoolStruct.new(:yesno => false)
       prot = Thrift::BinaryProtocol.new(Thrift::MemoryBufferTransport.new)