From ca7685ef50a0970662a55e3ad84b7cba73c2f2d0 Mon Sep 17 00:00:00 2001 From: Vladimir Gordiychuk Date: Wed, 16 Aug 2017 02:04:24 +0300 Subject: [PATCH] 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 --- .../io/grpc/protobuf/lite/ProtoLiteUtils.java | 17 +++++++--- .../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 8914201341..2a88a3f891 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(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 d47e089a02..c4a4d32174 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 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++]; + } + } }