Java fixes for 21.x (#12036)

* Fix mutability bug in Java proto lite: sub-messages inside of oneofs were not
being set as immutable. This would allow code to get a builder for a
sub-message and modify the original (supposedly immutable) copy.

PiperOrigin-RevId: 511598810

* Add casts to make protobuf compatible with Java 1.8 runtime.
Fix for: https://github.com/protocolbuffers/protobuf/issues/11393

PiperOrigin-RevId: 511807920

* Update Makefile.am

---------

Co-authored-by: Protobuf Team Bot <protobuf-github-bot@google.com>
pull/12098/head
Jerry Berg 2 years ago committed by GitHub
parent cd7f3bd478
commit 8e6b5d5303
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Makefile.am
  2. 1
      java/core/BUILD.bazel
  3. 2
      java/core/src/main/java/com/google/protobuf/AllocatedBuffer.java
  4. 28
      java/core/src/main/java/com/google/protobuf/BinaryWriter.java
  5. 2
      java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java
  6. 28
      java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
  7. 8
      java/core/src/main/java/com/google/protobuf/Internal.java
  8. 4
      java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java
  9. 67
      java/core/src/main/java/com/google/protobuf/Java8Compatibility.java
  10. 6
      java/core/src/main/java/com/google/protobuf/MessageSchema.java
  11. 11
      java/core/src/main/java/com/google/protobuf/NioByteString.java
  12. 2
      java/core/src/main/java/com/google/protobuf/TextFormat.java
  13. 10
      java/core/src/main/java/com/google/protobuf/Utf8.java
  14. 1
      java/lite/pom.xml
  15. 18
      java/lite/src/test/java/com/google/protobuf/LiteTest.java
  16. 1
      src/google/protobuf/unittest_lite.proto

@ -343,6 +343,7 @@ java_EXTRA_DIST=
java/core/src/main/java/com/google/protobuf/Internal.java \
java/core/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java \
java/core/src/main/java/com/google/protobuf/IterableByteBufferInputStream.java \
java/core/src/main/java/com/google/protobuf/Java8Compatibility.java \
java/core/src/main/java/com/google/protobuf/JavaType.java \
java/core/src/main/java/com/google/protobuf/LazyField.java \
java/core/src/main/java/com/google/protobuf/LazyFieldLite.java \

@ -49,6 +49,7 @@ LITE_SRCS = [
"src/main/java/com/google/protobuf/Internal.java",
"src/main/java/com/google/protobuf/InvalidProtocolBufferException.java",
"src/main/java/com/google/protobuf/IterableByteBufferInputStream.java",
"src/main/java/com/google/protobuf/Java8Compatibility.java",
"src/main/java/com/google/protobuf/JavaType.java",
"src/main/java/com/google/protobuf/LazyField.java",
"src/main/java/com/google/protobuf/LazyFieldLite.java",

@ -189,7 +189,7 @@ abstract class AllocatedBuffer {
@Override
public AllocatedBuffer position(int position) {
buffer.position(position);
Java8Compatibility.position(buffer, position);
return this;
}

@ -2019,8 +2019,8 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
buffers.addFirst(allocatedBuffer);
buffer = nioBuffer;
buffer.limit(buffer.capacity());
buffer.position(0);
Java8Compatibility.limit(buffer, buffer.capacity());
Java8Compatibility.position(buffer, 0);
// Set byte order to little endian for fast writing of fixed 32/64.
buffer.order(ByteOrder.LITTLE_ENDIAN);
@ -2046,7 +2046,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
if (buffer != null) {
totalDoneBytes += bytesWrittenToCurrentBuffer();
// Update the indices on the netty buffer.
buffer.position(pos + 1);
Java8Compatibility.position(buffer, pos + 1);
buffer = null;
pos = 0;
limitMinusOne = 0;
@ -2475,7 +2475,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
}
pos -= length;
buffer.position(pos + 1);
Java8Compatibility.position(buffer, pos + 1);
buffer.put(value, offset, length);
}
@ -2494,7 +2494,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
}
pos -= length;
buffer.position(pos + 1);
Java8Compatibility.position(buffer, pos + 1);
buffer.put(value, offset, length);
}
@ -2506,7 +2506,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
}
pos -= length;
buffer.position(pos + 1);
Java8Compatibility.position(buffer, pos + 1);
buffer.put(value);
}
@ -2526,7 +2526,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
}
pos -= length;
buffer.position(pos + 1);
Java8Compatibility.position(buffer, pos + 1);
buffer.put(value);
}
@ -2576,8 +2576,8 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
buffers.addFirst(allocatedBuffer);
buffer = nioBuffer;
buffer.limit(buffer.capacity());
buffer.position(0);
Java8Compatibility.limit(buffer, buffer.capacity());
Java8Compatibility.position(buffer, 0);
bufferOffset = UnsafeUtil.addressOffset(buffer);
limitMinusOne = bufferOffset + (buffer.limit() - 1);
@ -2602,7 +2602,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
if (buffer != null) {
totalDoneBytes += bytesWrittenToCurrentBuffer();
// Update the indices on the netty buffer.
buffer.position(bufferPos() + 1);
Java8Compatibility.position(buffer, bufferPos() + 1);
buffer = null;
pos = 0;
limitMinusOne = 0;
@ -3016,7 +3016,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
}
pos -= length;
buffer.position(bufferPos() + 1);
Java8Compatibility.position(buffer, bufferPos() + 1);
buffer.put(value, offset, length);
}
@ -3035,7 +3035,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
}
pos -= length;
buffer.position(bufferPos() + 1);
Java8Compatibility.position(buffer, bufferPos() + 1);
buffer.put(value, offset, length);
}
@ -3047,7 +3047,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
}
pos -= length;
buffer.position(bufferPos() + 1);
Java8Compatibility.position(buffer, bufferPos() + 1);
buffer.put(value);
}
@ -3067,7 +3067,7 @@ abstract class BinaryWriter extends ByteOutput implements Writer {
}
pos -= length;
buffer.position(bufferPos() + 1);
Java8Compatibility.position(buffer, bufferPos() + 1);
buffer.put(value);
}

@ -107,7 +107,7 @@ final class ByteBufferWriter {
}
} finally {
// Restore the initial position.
buffer.position(initialPos);
Java8Compatibility.position(buffer, initialPos);
}
}

@ -1271,7 +1271,7 @@ public abstract class CodedOutputStream extends ByteOutput {
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
duplicated.clear();
Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
@ -1522,7 +1522,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void flush() {
// Update the position on the buffer.
byteBuffer.position(initialPosition + getTotalBytesWritten());
Java8Compatibility.position(byteBuffer, initialPosition + getTotalBytesWritten());
}
}
@ -1684,7 +1684,7 @@ public abstract class CodedOutputStream extends ByteOutput {
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
duplicated.clear();
Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
@ -1794,18 +1794,18 @@ public abstract class CodedOutputStream extends ByteOutput {
// Save the current position and increment past the length field. We'll come back
// and write the length field after the encoding is complete.
final int startOfBytes = buffer.position() + minLengthVarIntSize;
buffer.position(startOfBytes);
Java8Compatibility.position(buffer, startOfBytes);
// Encode the string.
encode(value);
// Now go back to the beginning and write the length.
int endOfBytes = buffer.position();
buffer.position(startPos);
Java8Compatibility.position(buffer, startPos);
writeUInt32NoTag(endOfBytes - startOfBytes);
// Reposition the buffer past the written data.
buffer.position(endOfBytes);
Java8Compatibility.position(buffer, endOfBytes);
} else {
final int length = Utf8.encodedLength(value);
writeUInt32NoTag(length);
@ -1813,7 +1813,7 @@ public abstract class CodedOutputStream extends ByteOutput {
}
} catch (UnpairedSurrogateException e) {
// Roll back the change and convert to an IOException.
buffer.position(startPos);
Java8Compatibility.position(buffer, startPos);
// TODO(nathanmittler): We should throw an IOException here instead.
inefficientWriteStringNoTag(value, e);
@ -1826,7 +1826,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void flush() {
// Update the position of the original buffer.
originalBuffer.position(buffer.position());
Java8Compatibility.position(originalBuffer, buffer.position());
}
@Override
@ -2014,7 +2014,7 @@ public abstract class CodedOutputStream extends ByteOutput {
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
duplicated.clear();
Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
@ -2150,7 +2150,7 @@ public abstract class CodedOutputStream extends ByteOutput {
// Save the current position and increment past the length field. We'll come back
// and write the length field after the encoding is complete.
int stringStart = bufferPos(position) + minLengthVarIntSize;
buffer.position(stringStart);
Java8Compatibility.position(buffer, stringStart);
// Encode the string.
Utf8.encodeUtf8(value, buffer);
@ -2187,7 +2187,7 @@ public abstract class CodedOutputStream extends ByteOutput {
@Override
public void flush() {
// Update the position of the original buffer.
originalBuffer.position(bufferPos(position));
Java8Compatibility.position(originalBuffer, bufferPos(position));
}
@Override
@ -2201,7 +2201,7 @@ public abstract class CodedOutputStream extends ByteOutput {
}
private void repositionBuffer(long pos) {
buffer.position(bufferPos(pos));
Java8Compatibility.position(buffer, bufferPos(pos));
}
private int bufferPos(long pos) {
@ -2478,7 +2478,7 @@ public abstract class CodedOutputStream extends ByteOutput {
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
duplicated.clear();
Java8Compatibility.clear(duplicated);
write(duplicated);
}
}
@ -2792,7 +2792,7 @@ public abstract class CodedOutputStream extends ByteOutput {
write(value.array(), value.arrayOffset(), value.capacity());
} else {
ByteBuffer duplicated = value.duplicate();
duplicated.clear();
Java8Compatibility.clear(duplicated);
write(duplicated);
}
}

@ -313,7 +313,11 @@ public final class Internal {
}
// ByteBuffer.equals() will only compare the remaining bytes, but we want to
// compare all the content.
return a.duplicate().clear().equals(b.duplicate().clear());
ByteBuffer aDuplicate = a.duplicate();
Java8Compatibility.clear(aDuplicate);
ByteBuffer bDuplicate = b.duplicate();
Java8Compatibility.clear(bDuplicate);
return aDuplicate.equals(bDuplicate);
}
/** Helper method for implementing {@link Message#equals(Object)} for bytes field. */
@ -353,7 +357,7 @@ public final class Internal {
bytes.capacity() > DEFAULT_BUFFER_SIZE ? DEFAULT_BUFFER_SIZE : bytes.capacity();
final byte[] buffer = new byte[bufferSize];
final ByteBuffer duplicated = bytes.duplicate();
duplicated.clear();
Java8Compatibility.clear(duplicated);
int h = bytes.capacity();
while (duplicated.remaining() > 0) {
final int length =

@ -140,9 +140,9 @@ class IterableByteBufferInputStream extends InputStream {
updateCurrentByteBufferPos(length);
} else {
int prevPos = currentByteBuffer.position();
currentByteBuffer.position(currentByteBufferPos);
Java8Compatibility.position(currentByteBuffer, currentByteBufferPos);
currentByteBuffer.get(output, offset, length);
currentByteBuffer.position(prevPos);
Java8Compatibility.position(currentByteBuffer, prevPos);
updateCurrentByteBufferPos(length);
}
return length;

@ -0,0 +1,67 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.protobuf;
import java.nio.Buffer;
/**
* Wrappers around {@link Buffer} methods that are covariantly overridden in Java 9+. See
* https://github.com/protocolbuffers/protobuf/issues/11393
*
* <p>TODO(b/270454719) remove when Java 8 support is no longer needed.
*/
final class Java8Compatibility {
static void clear(Buffer b) {
b.clear();
}
static void flip(Buffer b) {
b.flip();
}
static void limit(Buffer b, int limit) {
b.limit(limit);
}
static void mark(Buffer b) {
b.mark();
}
static void position(Buffer b, int position) {
b.position(position);
}
static void reset(Buffer b) {
b.reset();
}
private Java8Compatibility() {}
}

@ -5510,6 +5510,12 @@ final class MessageSchema<T> implements Schema<T> {
getMessageFieldSchema(pos).makeImmutable(UNSAFE.getObject(message, offset));
}
break;
case 60: // ONEOF_MESSAGE
case 68: // ONEOF_GROUP
if (isOneofPresent(message, numberAt(pos), pos)) {
getMessageFieldSchema(pos).makeImmutable(UNSAFE.getObject(message, offset));
}
break;
case 18: // DOUBLE_LIST:
case 19: // FLOAT_LIST:
case 20: // INT64_LIST:

@ -37,7 +37,6 @@ import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.InvalidMarkException;
@ -110,7 +109,7 @@ final class NioByteString extends ByteString.LeafByteString {
protected void copyToInternal(
byte[] target, int sourceOffset, int targetOffset, int numberToCopy) {
ByteBuffer slice = buffer.slice();
((Buffer) slice).position(sourceOffset);
Java8Compatibility.position(slice, sourceOffset);
slice.get(target, targetOffset, numberToCopy);
}
@ -224,7 +223,7 @@ final class NioByteString extends ByteString.LeafByteString {
@Override
public void mark(int readlimit) {
buf.mark();
Java8Compatibility.mark(buf);
}
@Override
@ -235,7 +234,7 @@ final class NioByteString extends ByteString.LeafByteString {
@Override
public void reset() throws IOException {
try {
buf.reset();
Java8Compatibility.reset(buf);
} catch (InvalidMarkException e) {
throw new IOException(e);
}
@ -286,8 +285,8 @@ final class NioByteString extends ByteString.LeafByteString {
}
ByteBuffer slice = buffer.slice();
((Buffer) slice).position(beginIndex - buffer.position());
((Buffer) slice).limit(endIndex - buffer.position());
Java8Compatibility.position(slice, beginIndex - buffer.position());
Java8Compatibility.limit(slice, endIndex - buffer.position());
return slice;
}
}

@ -1717,7 +1717,7 @@ public final class TextFormat {
if (n == -1) {
break;
}
buffer.flip();
Java8Compatibility.flip(buffer);
text.append(buffer, 0, n);
}
return text;

@ -770,7 +770,7 @@ final class Utf8 {
if (out.hasArray()) {
final int offset = out.arrayOffset();
int endIndex = Utf8.encode(in, out.array(), offset + out.position(), out.remaining());
out.position(endIndex - offset);
Java8Compatibility.position(out, endIndex - offset);
} else if (out.isDirect()) {
encodeUtf8Direct(in, out);
} else {
@ -801,7 +801,7 @@ final class Utf8 {
}
if (inIx == inLength) {
// Successfully encoded the entire string.
out.position(outIx + inIx);
Java8Compatibility.position(out, outIx + inIx);
return;
}
@ -844,7 +844,7 @@ final class Utf8 {
}
// Successfully encoded the entire string.
out.position(outIx);
Java8Compatibility.position(out, outIx);
} catch (IndexOutOfBoundsException e) {
// TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead.
@ -1545,7 +1545,7 @@ final class Utf8 {
}
if (inIx == inLimit) {
// We're done, it was ASCII encoded.
out.position((int) (outIx - address));
Java8Compatibility.position(out, (int) (outIx - address));
return;
}
@ -1585,7 +1585,7 @@ final class Utf8 {
}
// All bytes have been encoded.
out.position((int) (outIx - address));
Java8Compatibility.position(out, (int) (outIx - address));
}
/**

@ -125,6 +125,7 @@
<include>Internal.java</include>
<include>InvalidProtocolBufferException.java</include>
<include>IterableByteBufferInputStream.java</include>
<include>Java8Compatibility.java</include>
<include>JavaType.java</include>
<include>LazyField.java</include>
<include>LazyFieldLite.java</include>

@ -189,6 +189,18 @@ public class LiteTest {
}
}
@Test
public void testParsedOneofSubMessageIsImmutable() throws InvalidProtocolBufferException {
TestAllTypesLite message =
TestAllTypesLite.parseFrom(
TestAllTypesLite.newBuilder()
.setOneofNestedMessage(NestedMessage.newBuilder().addDd(1234).build())
.build()
.toByteArray());
IntArrayList subList = (IntArrayList) message.getOneofNestedMessage().getDdList();
assertThat(subList.isModifiable()).isFalse();
}
@Test
public void testMemoization() throws Exception {
GeneratedMessageLite<?, ?> message = TestUtilLite.getAllLiteExtensionsSet();
@ -2349,8 +2361,7 @@ public class LiteTest {
Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
Foo fooWithValueAndExtension =
fooWithOnlyValue
.toBuilder()
fooWithOnlyValue.toBuilder()
.setValue(1)
.setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build())
.build();
@ -2366,8 +2377,7 @@ public class LiteTest {
Foo fooWithOnlyValue = Foo.newBuilder().setValue(1).build();
Foo fooWithValueAndExtension =
fooWithOnlyValue
.toBuilder()
fooWithOnlyValue.toBuilder()
.setValue(1)
.setExtension(Bar.fooExt, Bar.newBuilder().setName("name").build())
.build();

@ -47,6 +47,7 @@ message TestAllTypesLite {
message NestedMessage {
optional int32 bb = 1;
optional int64 cc = 2;
repeated int32 dd = 3 [packed = true];
}
message NestedMessage2 {

Loading…
Cancel
Save