Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Descriptors$FieldDescriptor.<init>(Descriptors.java:1107) isPacked() NPE #24

Closed
protobufel opened this issue Sep 16, 2014 · 2 comments · Fixed by #39
Closed

Descriptors$FieldDescriptor.<init>(Descriptors.java:1107) isPacked() NPE #24

protobufel opened this issue Sep 16, 2014 · 2 comments · Fixed by #39
Milestone

Comments

@protobufel
Copy link

Here is the excerpt from Descriptors$FieldDescriptor constructor:

    private FieldDescriptor(final FieldDescriptorProto proto,
                            final FileDescriptor file,
                            final Descriptor parent,
                            final int index,
                            final boolean isExtension)
                     throws DescriptorValidationException {
      this.index = index;
      this.proto = proto;
      fullName = computeFullName(file, parent, proto.getName());
      this.file = file;

      if (proto.hasType()) {
        type = Type.valueOf(proto.getType());
      }

      if (getNumber() <= 0) {
        throw new DescriptorValidationException(this,
          "Field numbers must be positive integers.");
      }

      // Only repeated primitive fields may be packed.
      if (proto.getOptions().getPacked() && !isPackable()) {

... 

    public boolean isPackable() {
      return isRepeated() && getLiteType().isPackable();
    }

    public WireFormat.FieldType getLiteType() {
      return table[type.ordinal()];
    }

However, if there is an enum or a message proto field with unresolved type (which is okay during cross-linking), then isPackable() will NPE because type ==null in getLiteType() !

This is a serious bug, preventing build of ANY protos with enum or message fields with only the TypeName set. The protoc does its own cross-linking so its Type fields are always set, anything else will fail miserably!

The resolution is simple add type != null in this condition, and if wanted check again after cross-linking:

if ((type != null) && proto.getOptions().getPacked() && !isPackable()) {

Thanks in advance, and hope it will be released soon!

Regards,
David

@protobufel
Copy link
Author

And here is the test for this case:

  @Test(expected = NullPointerException.class)
  public void testPackedEnumFieldInProto() throws Exception {
    final FileDescriptorProto.Builder protoBuilder = FileDescriptorProto.newBuilder()
        .setName("test1.proto");
    protoBuilder.addEnumTypeBuilder()
        .setName("Enum1").addValueBuilder().setName("V1").setNumber(1);
    protoBuilder.addMessageTypeBuilder()
        .setName("Message1").addFieldBuilder().setName("field1").setTypeName("Enum1").setNumber(999)
        .setLabel(Label.LABEL_REPEATED).getOptionsBuilder().setPacked(true);

    // The buildFrom() will fail, but it shouldn't!
    final FileDescriptor fileDescriptor = FileDescriptor.buildFrom(protoBuilder.build(), new FileDescriptor[0]);
  }

or just remove (expected = NullPointerException.class) and see it fail!

@protobufel
Copy link
Author

BTW, you're not seeing a lot of problems because the protoc does a lot of cross-linking/name resolutions in protos for you already, so it gives you nice RESOLVED ones, and a lot of the Java "build" stuff, therefore, goes untested and problems are undetected!

@xfxyjwf xfxyjwf added this to the Release 2.6.1 milestone Sep 18, 2014
copybara-service bot pushed a commit that referenced this issue Dec 14, 2023
Before, every charAt would emit (on android):
```
    0x00002104    adrp x17, #+0x1000 (addr 0x3000)
    0x00002108    ldr w17, [x17, #20]
    0x0000210c    ldr x0, [x0, #128]
    0x00002110    ldr x0, [x0, #328]
    0x00002114    ldr lr, [x0, #24]
    0x00002118    blr lr <-- Call into String.charAt(int)
```
Now, it emits the inlined implementation of charAt (branch is for possibly compressed strings):
```
    0x000020b4    ldur w16, [x4, #-8]
    0x000020b8    tbnz w16, #0, #+0xc (addr 0x20c4)
    0x000020bc    ldrb w4, [x4, x0]
    0x000020c0    b #+0x8 (addr 0x20c8)
    0x000020c4    ldrh w4, [x4, x0, lsl #1]
```

PiperOrigin-RevId: 590821750
copybara-service bot pushed a commit that referenced this issue Dec 15, 2023
Before, every charAt would emit (on android):
```
    0x00002104    adrp x17, #+0x1000 (addr 0x3000)
    0x00002108    ldr w17, [x17, #20]
    0x0000210c    ldr x0, [x0, #128]
    0x00002110    ldr x0, [x0, #328]
    0x00002114    ldr lr, [x0, #24]
    0x00002118    blr lr <-- Call into String.charAt(int)
```
Now, it emits the inlined implementation of charAt (branch is for possibly compressed strings):
```
    0x000020b4    ldur w16, [x4, #-8]
    0x000020b8    tbnz w16, #0, #+0xc (addr 0x20c4)
    0x000020bc    ldrb w4, [x4, x0]
    0x000020c0    b #+0x8 (addr 0x20c8)
    0x000020c4    ldrh w4, [x4, x0, lsl #1]
```

PiperOrigin-RevId: 590821750
copybara-service bot pushed a commit that referenced this issue Dec 15, 2023
Before, every charAt would emit (on android):
```
    0x00002104    adrp x17, #+0x1000 (addr 0x3000)
    0x00002108    ldr w17, [x17, #20]
    0x0000210c    ldr x0, [x0, #128]
    0x00002110    ldr x0, [x0, #328]
    0x00002114    ldr lr, [x0, #24]
    0x00002118    blr lr <-- Call into String.charAt(int)
```
Now, it emits the inlined implementation of charAt (branch is for possibly compressed strings):
```
    0x000020b4    ldur w16, [x4, #-8]
    0x000020b8    tbnz w16, #0, #+0xc (addr 0x20c4)
    0x000020bc    ldrb w4, [x4, x0]
    0x000020c0    b #+0x8 (addr 0x20c8)
    0x000020c4    ldrh w4, [x4, x0, lsl #1]
```

PiperOrigin-RevId: 591147406
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants