Skip to content

Commit

Permalink
Fix NPE during encoding and add regression test for issue 9507.
Browse files Browse the repository at this point in the history
(cherry picked from commit 58e320a)
  • Loading branch information
JasonLunn committed Mar 31, 2022
1 parent faa42e9 commit 7fa212b
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 7 deletions.
18 changes: 11 additions & 7 deletions ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
Expand Up @@ -62,6 +62,9 @@
import java.util.Map;

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) {
super(runtime, klazz);

Expand Down Expand Up @@ -677,6 +680,8 @@ protected DynamicMessage build(ThreadContext context, int depth, int recursionLi
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
for (FieldDescriptor fieldDescriptor : fields.keySet()) {
IRubyObject value = fields.get(fieldDescriptor);
Expand Down Expand Up @@ -707,13 +712,12 @@ protected DynamicMessage build(ThreadContext context, int depth, int recursionLi
* stringDefaultValue}.
*/
boolean isDefaultStringForBytes = false;
FieldDescriptor enumFieldDescriptorForType =
this.builder.getDescriptorForType().findFieldByName("type");
String type = enumFieldDescriptorForType == null ?
null : fields.get(enumFieldDescriptorForType).toString();
if (type != null && type.equals("TYPE_BYTES") &&
fieldDescriptor.getFullName().equals("google.protobuf.FieldDescriptorProto.default_value")) {
isDefaultStringForBytes = true;
if (DEFAULT_VALUE.equals(fieldDescriptor.getFullName())) {
FieldDescriptor enumFieldDescriptorForType =
this.builder.getDescriptorForType().findFieldByName(TYPE);
if (typeBytesSymbol.equals(fields.get(enumFieldDescriptorForType))) {
isDefaultStringForBytes = true;
}
}
builder.setField(fieldDescriptor, convert(context, fieldDescriptor, value, depth, recursionLimit, isDefaultStringForBytes));
}
Expand Down
28 changes: 28 additions & 0 deletions ruby/tests/basic.rb
Expand Up @@ -79,6 +79,34 @@ def test_issue_9440
assert_equal 8, msg.id
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
m = TestSingularFields.new
assert !m.has_singular_msg?
Expand Down

0 comments on commit 7fa212b

Please sign in to comment.