Fix integer overflow in computeSerializedSizeInWords

This commit is contained in:
Martin Dindoffer 2022-05-04 18:40:12 +02:00 committed by Vaci
parent e77372b1cd
commit 89d1c5722e
2 changed files with 23 additions and 4 deletions

View file

@ -178,15 +178,18 @@ public final class Serialize {
} }
public static long computeSerializedSizeInWords(MessageBuilder message) { public static long computeSerializedSizeInWords(MessageBuilder message) {
final ByteBuffer[] segments = message.getSegmentsForOutput(); return computeSerializedSizeInWords(message.getSegmentsForOutput());
}
// From the capnproto documentation: //VisibleForTesting
static long computeSerializedSizeInWords(ByteBuffer[] segments) {
// From the capnproto documentation (https://capnproto.org/encoding.html#serialization-over-a-stream):
// "When transmitting over a stream, the following should be sent..." // "When transmitting over a stream, the following should be sent..."
long bytes = 0; long bytes = 0;
// "(4 bytes) The number of segments, minus one..." // "(4 bytes) The number of segments, minus one..."
bytes += 4; bytes += 4;
// "(N * 4 bytes) The size of each segment, in words." // "(N * 4 bytes) The size of each segment, in words."
bytes += segments.length * 4; bytes += segments.length * 4L;
// "(0 or 4 bytes) Padding up to the next word boundary." // "(0 or 4 bytes) Padding up to the next word boundary."
if (bytes % 8 != 0) { if (bytes % 8 != 0) {
bytes += 4; bytes += 4;
@ -194,7 +197,7 @@ public final class Serialize {
// The content of each segment, in order. // The content of each segment, in order.
for (int i = 0; i < segments.length; ++i) { for (int i = 0; i < segments.length; ++i) {
final ByteBuffer s = segments[i]; ByteBuffer s = segments[i];
bytes += s.limit(); bytes += s.limit();
} }

View file

@ -30,8 +30,15 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
public class SerializeTest { public class SerializeTest {
/** /**
@ -194,4 +201,13 @@ public class SerializeTest {
java.nio.channels.Channels.newChannel(new java.io.ByteArrayInputStream(input)); java.nio.channels.Channels.newChannel(new java.io.ByteArrayInputStream(input));
MessageReader message = Serialize.read(channel); MessageReader message = Serialize.read(channel);
} }
@Test
@Ignore("Ignored by default because the huge array used in the test results in a long execution")
public void computeSerializedSizeInWordsShouldNotOverflowOnLargeSegmentCounts() {
ByteBuffer dummySegmentBuffer = ByteBuffer.allocate(0);
ByteBuffer[] segments = new ByteBuffer[Integer.MAX_VALUE / 2];
Arrays.fill(segments, dummySegmentBuffer);
assertThat(Serialize.computeSerializedSizeInWords(segments), is((segments.length * 4L + 4) / Constants.BYTES_PER_WORD));
}
} }