Fix NPE during encoding and add regression test for issue 9507.

pull/9637/head
Jason Lunn 3 years ago
parent 5dab09408c
commit 58e320a732
  1. 18
      ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
  2. 28
      ruby/tests/basic.rb

@ -62,6 +62,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class RubyMessage extends RubyObject { public class RubyMessage extends RubyObject {
private final String DEFAULT_VALUE = "google.protobuf.FieldDescriptorProto.default_value";
private final String TYPE = "type";
public RubyMessage(Ruby runtime, RubyClass klazz, Descriptor descriptor) { public RubyMessage(Ruby runtime, RubyClass klazz, Descriptor descriptor) {
super(runtime, klazz); super(runtime, klazz);
@ -677,6 +680,8 @@ public class RubyMessage extends RubyObject {
throw context.runtime.newRuntimeError("Recursion limit exceeded during encoding."); throw context.runtime.newRuntimeError("Recursion limit exceeded during encoding.");
} }
RubySymbol typeBytesSymbol = RubySymbol.newSymbol(context.runtime, "TYPE_BYTES");
// Handle the typical case where the fields.keySet contain the fieldDescriptors // Handle the typical case where the fields.keySet contain the fieldDescriptors
for (FieldDescriptor fieldDescriptor : fields.keySet()) { for (FieldDescriptor fieldDescriptor : fields.keySet()) {
IRubyObject value = fields.get(fieldDescriptor); IRubyObject value = fields.get(fieldDescriptor);
@ -707,13 +712,12 @@ public class RubyMessage extends RubyObject {
* stringDefaultValue}. * stringDefaultValue}.
*/ */
boolean isDefaultStringForBytes = false; boolean isDefaultStringForBytes = false;
FieldDescriptor enumFieldDescriptorForType = if (DEFAULT_VALUE.equals(fieldDescriptor.getFullName())) {
this.builder.getDescriptorForType().findFieldByName("type"); FieldDescriptor enumFieldDescriptorForType =
String type = enumFieldDescriptorForType == null ? this.builder.getDescriptorForType().findFieldByName(TYPE);
null : fields.get(enumFieldDescriptorForType).toString(); if (typeBytesSymbol.equals(fields.get(enumFieldDescriptorForType))) {
if (type != null && type.equals("TYPE_BYTES") && isDefaultStringForBytes = true;
fieldDescriptor.getFullName().equals("google.protobuf.FieldDescriptorProto.default_value")) { }
isDefaultStringForBytes = true;
} }
builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth, recursionLimit, isDefaultStringForBytes)); builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth, recursionLimit, isDefaultStringForBytes));
} }

@ -79,6 +79,34 @@ module BasicTest
assert_equal 8, msg.id assert_equal 8, msg.id
end end
def test_issue_9507
pool = Google::Protobuf::DescriptorPool.new
pool.build do
add_message "NpeMessage" do
optional :type, :enum, 1, "TestEnum"
optional :other, :string, 2
end
add_enum "TestEnum" do
value :Something, 0
end
end
msgclass = pool.lookup("NpeMessage").msgclass
m = msgclass.new(
other: "foo" # must be set, but can be blank
)
begin
encoded = msgclass.encode(m)
rescue java.lang.NullPointerException => e
flunk "NPE rescued"
end
decoded = msgclass.decode(encoded)
decoded.inspect
decoded.to_proto
end
def test_has_field def test_has_field
m = TestSingularFields.new m = TestSingularFields.new
assert !m.has_singular_msg? assert !m.has_singular_msg?

Loading…
Cancel
Save