diff options
author | Vladimir Gordiychuk <folyga@gmail.com> | 2017-08-16 02:04:24 +0300 |
---|---|---|
committer | Eric Anderson <ejona@google.com> | 2017-08-15 16:04:24 -0700 |
commit | ca7685ef50a0970662a55e3ad84b7cba73c2f2d0 (patch) | |
tree | aeeeea587d52f30fc2b020ba622350330765b5b8 /protobuf-lite | |
parent | 577bbefd1a968e524497626c5487496f93c5254e (diff) | |
download | grpc-grpc-java-ca7685ef50a0970662a55e3ad84b7cba73c2f2d0.tar.gz |
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
Diffstat (limited to 'protobuf-lite')
-rw-r--r-- | protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java | 17 | ||||
-rw-r--r-- | protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java | 33 |
2 files changed, 45 insertions, 5 deletions
diff --git a/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java b/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java index 891420134..2a88a3f89 100644 --- a/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java +++ b/protobuf-lite/src/main/java/io/grpc/protobuf/lite/ProtoLiteUtils.java @@ -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; + } + remaining -= count; } - if (size != position) { + + if (remaining != 0) { + int position = size - remaining; throw new RuntimeException("size inaccurate: " + size + " != " + position); } cis = CodedInputStream.newInstance(buf, 0, size); diff --git a/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java b/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java index d47e089a0..c4a4d3217 100644 --- a/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java +++ b/protobuf-lite/src/test/java/io/grpc/protobuf/lite/ProtoLiteUtilsTest.java @@ -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++]; + } + } } |