protobuf-lite: ProtoLiteUtils fix infinite loop

InputStream by contract can return zero if requested length equal to zero.

```
If len is zero, then no bytes are read and 0 is returned;
otherwise, there is an attempt to read at least one byte.
If no byte is available because the stream is at end of file,
the value -1 is returned; otherwise, at least one byte is read
and stored into b.
```

Close #3323
This commit is contained in:
Vladimir Gordiychuk 2017-08-16 02:04:24 +03:00 committed by Eric Anderson
parent 577bbefd1a
commit ca7685ef50
2 changed files with 45 additions and 5 deletions

View File

@ -128,12 +128,19 @@ public class ProtoLiteUtils {
buf = new byte[size];
bufs.set(new WeakReference<byte[]>(buf));
}
int chunkSize;
int position = 0;
while ((chunkSize = stream.read(buf, position, size - position)) != -1) {
position += chunkSize;
int remaining = size;
while (remaining > 0) {
int position = size - remaining;
int count = stream.read(buf, position, remaining);
if (count == -1) {
break;
}
if (size != position) {
remaining -= count;
}
if (remaining != 0) {
int position = size - remaining;
throw new RuntimeException("size inaccurate: " + size + " != " + position);
}
cis = CodedInputStream.newInstance(buf, 0, size);

View File

@ -29,6 +29,7 @@ import com.google.protobuf.Enum;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Type;
import io.grpc.Drainable;
import io.grpc.KnownLength;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor.Marshaller;
import io.grpc.MethodDescriptor.PrototypeMarshaller;
@ -215,4 +216,36 @@ public class ProtoLiteUtilsTest {
ProtoLiteUtils.setExtensionRegistry(null);
}
@Test
public void parseFromKnowLengthInputStream() throws Exception {
Marshaller<Type> marshaller = ProtoLiteUtils.marshaller(Type.getDefaultInstance());
Type expect = Type.newBuilder().setName("expected name").build();
Type result = marshaller.parse(new CustomKnownLengthInputStream(expect.toByteArray()));
assertEquals(expect, result);
}
private static class CustomKnownLengthInputStream extends InputStream implements KnownLength {
private int position = 0;
private byte[] source;
private CustomKnownLengthInputStream(byte[] source) {
this.source = source;
}
@Override
public int available() throws IOException {
return source.length - position;
}
@Override
public int read() throws IOException {
if (position == source.length) {
return -1;
}
return source[position++];
}
}
}