Fix cord handling in DynamicMessage and oneofs. (#18375)

* Fix cord handling in DynamicMessage and oneofs.

This fixes a memory corruption vulnerability for anyone using cord with dynamically built descriptor pools.

* Update staleness. Run using Bazel 6.3.2 docker image

* Silence expected ubsan failures from absl::Cord

---------

Co-authored-by: Mike Kruskal <mkruskal@google.com>
pull/18394/head
zhangskz 5 months ago committed by GitHub
parent 8a60b6527a
commit e67347986e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      .bazelrc
  2. 2
      ci/common.bazelrc
  3. 42
      java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
  4. 381
      java/core/src/test/java/com/google/protobuf/TestUtil.java
  5. 39
      java/core/src/test/java/com/google/protobuf/TextFormatTest.java
  6. 2
      python/google/protobuf/internal/descriptor_test.py
  7. 2
      python/google/protobuf/internal/field_mask_test.py
  8. 63
      python/google/protobuf/internal/message_test.py
  9. 3
      python/google/protobuf/internal/test_util.py
  10. 6
      python/google/protobuf/internal/unknown_fields_test.py
  11. 1
      src/file_lists.cmake
  12. 4
      src/google/protobuf/BUILD.bazel
  13. 35
      src/google/protobuf/arena_test_util.h
  14. 7
      src/google/protobuf/arena_unittest.cc
  15. 1
      src/google/protobuf/compiler/BUILD.bazel
  16. 28
      src/google/protobuf/compiler/command_line_interface_unittest.cc
  17. 22
      src/google/protobuf/compiler/cpp/field.cc
  18. 5
      src/google/protobuf/compiler/cpp/field.h
  19. 3
      src/google/protobuf/compiler/cpp/helpers.cc
  20. 10
      src/google/protobuf/compiler/cpp/tracker.cc
  21. 4
      src/google/protobuf/compiler/cpp/unittest.inc
  22. 10
      src/google/protobuf/descriptor.cc
  23. 8
      src/google/protobuf/descriptor.h
  24. 36
      src/google/protobuf/descriptor_lite.h
  25. 19
      src/google/protobuf/descriptor_unittest.cc
  26. 73
      src/google/protobuf/dynamic_message.cc
  27. 202
      src/google/protobuf/generated_message_reflection.cc
  28. 27
      src/google/protobuf/generated_message_tctable_gen.cc
  29. 6
      src/google/protobuf/generated_message_tctable_lite.cc
  30. 5
      src/google/protobuf/io/BUILD.bazel
  31. 9
      src/google/protobuf/io/zero_copy_stream_unittest.cc
  32. 2
      src/google/protobuf/json/json_test.cc
  33. 24
      src/google/protobuf/lite_unittest.cc
  34. 63
      src/google/protobuf/map_test.inc
  35. 8
      src/google/protobuf/message.cc
  36. 18
      src/google/protobuf/message_unittest.inc
  37. 17
      src/google/protobuf/port.h
  38. 5
      src/google/protobuf/port_def.inc
  39. 18
      src/google/protobuf/port_test.cc
  40. 17
      src/google/protobuf/test_util.h
  41. 12
      src/google/protobuf/test_util.inc
  42. BIN
      src/google/protobuf/testdata/golden_message
  43. BIN
      src/google/protobuf/testdata/golden_message_maps
  44. BIN
      src/google/protobuf/testdata/golden_message_oneof_implemented
  45. BIN
      src/google/protobuf/testdata/golden_message_proto3
  46. BIN
      src/google/protobuf/testdata/golden_packed_fields_message
  47. 1
      src/google/protobuf/testdata/text_format_unittest_data.txt
  48. 1
      src/google/protobuf/testdata/text_format_unittest_data_oneof_implemented.txt
  49. 1
      src/google/protobuf/testdata/text_format_unittest_data_pointy.txt
  50. 1
      src/google/protobuf/testdata/text_format_unittest_data_pointy_oneof.txt
  51. 1
      src/google/protobuf/testdata/text_format_unittest_extensions_data.txt
  52. 1
      src/google/protobuf/testdata/text_format_unittest_extensions_data_pointy.txt
  53. 2
      src/google/protobuf/unittest.proto
  54. 3
      src/google/protobuf/unittest_lite.proto
  55. 1
      src/google/protobuf/unittest_proto3_arena.proto
  56. 2
      src/google/protobuf/util/field_mask_util_test.cc
  57. 8
      src/google/protobuf/wire_format.cc

@ -26,6 +26,8 @@ build:ubsan --copt=-DUNDEFINED_SANITIZER=1
# Workaround for the fact that Bazel links with $CC, not $CXX # Workaround for the fact that Bazel links with $CC, not $CXX
# https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748 # https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748
build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr
# Abseil passes nullptr to memcmp with 0 size
build:ubsan --copt=-fno-sanitize=nonnull-attribute
# TODO: migrate all dependencies from WORKSPACE to MODULE.bazel # TODO: migrate all dependencies from WORKSPACE to MODULE.bazel
# https://github.com/protocolbuffers/protobuf/issues/14313 # https://github.com/protocolbuffers/protobuf/issues/14313

@ -34,3 +34,5 @@ build:ubsan --copt=-DUNDEFINED_SANITIZER=1
# Workaround for the fact that Bazel links with $CC, not $CXX # Workaround for the fact that Bazel links with $CC, not $CXX
# https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748 # https://github.com/bazelbuild/bazel/issues/11122#issuecomment-613746748
build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr build:ubsan --copt=-fno-sanitize=function --copt=-fno-sanitize=vptr
# Abseil passes nullptr to memcmp with 0 size
build:ubsan --copt=-fno-sanitize=nonnull-attribute

@ -13,7 +13,6 @@ import static com.google.common.truth.Truth.assertWithMessage;
import com.google.protobuf.CodedOutputStream.OutOfSpaceException; import com.google.protobuf.CodedOutputStream.OutOfSpaceException;
import protobuf_unittest.UnittestProto.SparseEnumMessage; import protobuf_unittest.UnittestProto.SparseEnumMessage;
import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestSparseEnum; import protobuf_unittest.UnittestProto.TestSparseEnum;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -327,47 +326,6 @@ public class CodedOutputStreamTest {
.isEqualTo(-75123905439571256L); .isEqualTo(-75123905439571256L);
} }
/** Tests writing a whole message with every field type. */
@Test
public void testWriteWholeMessage() throws Exception {
final byte[] expectedBytes = TestUtil.getGoldenMessage().toByteArray();
TestAllTypes message = TestUtil.getAllSet();
for (OutputType outputType : OutputType.values()) {
Coder coder = outputType.newCoder(message.getSerializedSize());
message.writeTo(coder.stream());
coder.stream().flush();
byte[] rawBytes = coder.toByteArray();
assertEqualBytes(outputType, expectedBytes, rawBytes);
}
// Try different block sizes.
for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
Coder coder = OutputType.STREAM.newCoder(blockSize);
message.writeTo(coder.stream());
coder.stream().flush();
assertEqualBytes(OutputType.STREAM, expectedBytes, coder.toByteArray());
}
}
/**
* Tests writing a whole message with every packed field type. Ensures the wire format of packed
* fields is compatible with C++.
*/
@Test
public void testWriteWholePackedFieldsMessage() throws Exception {
byte[] expectedBytes = TestUtil.getGoldenPackedFieldsMessage().toByteArray();
TestPackedTypes message = TestUtil.getPackedSet();
for (OutputType outputType : OutputType.values()) {
Coder coder = outputType.newCoder(message.getSerializedSize());
message.writeTo(coder.stream());
coder.stream().flush();
byte[] rawBytes = coder.toByteArray();
assertEqualBytes(outputType, expectedBytes, rawBytes);
}
}
/** /**
* Test writing a message containing a negative enum value. This used to fail because the size was * Test writing a message containing a negative enum value. This used to fail because the size was
* not properly computed as a sign-extended varint. * not properly computed as a sign-extended varint.

@ -210,10 +210,6 @@ import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.TestPackedTypes;
import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestRequired;
import protobuf_unittest.UnittestProto.TestUnpackedTypes; import protobuf_unittest.UnittestProto.TestUnpackedTypes;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -234,6 +230,281 @@ import org.junit.Assert;
public final class TestUtil { public final class TestUtil {
private TestUtil() {} private TestUtil() {}
public static final String ALL_FIELDS_SET_TEXT =
""
+ "optional_int32: 101\n"
+ "optional_int64: 102\n"
+ "optional_uint32: 103\n"
+ "optional_uint64: 104\n"
+ "optional_sint32: 105\n"
+ "optional_sint64: 106\n"
+ "optional_fixed32: 107\n"
+ "optional_fixed64: 108\n"
+ "optional_sfixed32: 109\n"
+ "optional_sfixed64: 110\n"
+ "optional_float: 111.0\n"
+ "optional_double: 112.0\n"
+ "optional_bool: true\n"
+ "optional_string: \"115\"\n"
+ "optional_bytes: \"116\"\n"
+ "OptionalGroup {\n"
+ " a: 117\n"
+ "}\n"
+ "optional_nested_message {\n"
+ " bb: 118\n"
+ "}\n"
+ "optional_foreign_message {\n"
+ " c: 119\n"
+ "}\n"
+ "optional_import_message {\n"
+ " d: 120\n"
+ "}\n"
+ "optional_nested_enum: BAZ\n"
+ "optional_foreign_enum: FOREIGN_BAZ\n"
+ "optional_import_enum: IMPORT_BAZ\n"
+ "optional_string_piece: \"124\"\n"
+ "optional_cord: \"125\"\n"
+ "optional_public_import_message {\n"
+ " e: 126\n"
+ "}\n"
+ "optional_lazy_message {\n"
+ " bb: 127\n"
+ "}\n"
+ "optional_unverified_lazy_message {\n"
+ " bb: 128\n"
+ "}\n"
+ "repeated_int32: 201\n"
+ "repeated_int32: 301\n"
+ "repeated_int64: 202\n"
+ "repeated_int64: 302\n"
+ "repeated_uint32: 203\n"
+ "repeated_uint32: 303\n"
+ "repeated_uint64: 204\n"
+ "repeated_uint64: 304\n"
+ "repeated_sint32: 205\n"
+ "repeated_sint32: 305\n"
+ "repeated_sint64: 206\n"
+ "repeated_sint64: 306\n"
+ "repeated_fixed32: 207\n"
+ "repeated_fixed32: 307\n"
+ "repeated_fixed64: 208\n"
+ "repeated_fixed64: 308\n"
+ "repeated_sfixed32: 209\n"
+ "repeated_sfixed32: 309\n"
+ "repeated_sfixed64: 210\n"
+ "repeated_sfixed64: 310\n"
+ "repeated_float: 211.0\n"
+ "repeated_float: 311.0\n"
+ "repeated_double: 212.0\n"
+ "repeated_double: 312.0\n"
+ "repeated_bool: true\n"
+ "repeated_bool: false\n"
+ "repeated_string: \"215\"\n"
+ "repeated_string: \"315\"\n"
+ "repeated_bytes: \"216\"\n"
+ "repeated_bytes: \"316\"\n"
+ "RepeatedGroup {\n"
+ " a: 217\n"
+ "}\n"
+ "RepeatedGroup {\n"
+ " a: 317\n"
+ "}\n"
+ "repeated_nested_message {\n"
+ " bb: 218\n"
+ "}\n"
+ "repeated_nested_message {\n"
+ " bb: 318\n"
+ "}\n"
+ "repeated_foreign_message {\n"
+ " c: 219\n"
+ "}\n"
+ "repeated_foreign_message {\n"
+ " c: 319\n"
+ "}\n"
+ "repeated_import_message {\n"
+ " d: 220\n"
+ "}\n"
+ "repeated_import_message {\n"
+ " d: 320\n"
+ "}\n"
+ "repeated_nested_enum: BAR\n"
+ "repeated_nested_enum: BAZ\n"
+ "repeated_foreign_enum: FOREIGN_BAR\n"
+ "repeated_foreign_enum: FOREIGN_BAZ\n"
+ "repeated_import_enum: IMPORT_BAR\n"
+ "repeated_import_enum: IMPORT_BAZ\n"
+ "repeated_string_piece: \"224\"\n"
+ "repeated_string_piece: \"324\"\n"
+ "repeated_cord: \"225\"\n"
+ "repeated_cord: \"325\"\n"
+ "repeated_lazy_message {\n"
+ " bb: 227\n"
+ "}\n"
+ "repeated_lazy_message {\n"
+ " bb: 327\n"
+ "}\n"
+ "default_int32: 401\n"
+ "default_int64: 402\n"
+ "default_uint32: 403\n"
+ "default_uint64: 404\n"
+ "default_sint32: 405\n"
+ "default_sint64: 406\n"
+ "default_fixed32: 407\n"
+ "default_fixed64: 408\n"
+ "default_sfixed32: 409\n"
+ "default_sfixed64: 410\n"
+ "default_float: 411.0\n"
+ "default_double: 412.0\n"
+ "default_bool: false\n"
+ "default_string: \"415\"\n"
+ "default_bytes: \"416\"\n"
+ "default_nested_enum: FOO\n"
+ "default_foreign_enum: FOREIGN_FOO\n"
+ "default_import_enum: IMPORT_FOO\n"
+ "default_string_piece: \"424\"\n"
+ "default_cord: \"425\"\n"
+ "oneof_bytes: \"604\"\n";
public static final String ALL_EXTENSIONS_SET_TEXT =
""
+ "[protobuf_unittest.optional_int32_extension]: 101\n"
+ "[protobuf_unittest.optional_int64_extension]: 102\n"
+ "[protobuf_unittest.optional_uint32_extension]: 103\n"
+ "[protobuf_unittest.optional_uint64_extension]: 104\n"
+ "[protobuf_unittest.optional_sint32_extension]: 105\n"
+ "[protobuf_unittest.optional_sint64_extension]: 106\n"
+ "[protobuf_unittest.optional_fixed32_extension]: 107\n"
+ "[protobuf_unittest.optional_fixed64_extension]: 108\n"
+ "[protobuf_unittest.optional_sfixed32_extension]: 109\n"
+ "[protobuf_unittest.optional_sfixed64_extension]: 110\n"
+ "[protobuf_unittest.optional_float_extension]: 111.0\n"
+ "[protobuf_unittest.optional_double_extension]: 112.0\n"
+ "[protobuf_unittest.optional_bool_extension]: true\n"
+ "[protobuf_unittest.optional_string_extension]: \"115\"\n"
+ "[protobuf_unittest.optional_bytes_extension]: \"116\"\n"
+ "[protobuf_unittest.optionalgroup_extension] {\n"
+ " a: 117\n"
+ "}\n"
+ "[protobuf_unittest.optional_nested_message_extension] {\n"
+ " bb: 118\n"
+ "}\n"
+ "[protobuf_unittest.optional_foreign_message_extension] {\n"
+ " c: 119\n"
+ "}\n"
+ "[protobuf_unittest.optional_import_message_extension] {\n"
+ " d: 120\n"
+ "}\n"
+ "[protobuf_unittest.optional_nested_enum_extension]: BAZ\n"
+ "[protobuf_unittest.optional_foreign_enum_extension]: FOREIGN_BAZ\n"
+ "[protobuf_unittest.optional_import_enum_extension]: IMPORT_BAZ\n"
+ "[protobuf_unittest.optional_string_piece_extension]: \"124\"\n"
+ "[protobuf_unittest.optional_cord_extension]: \"125\"\n"
+ "[protobuf_unittest.optional_public_import_message_extension] {\n"
+ " e: 126\n"
+ "}\n"
+ "[protobuf_unittest.optional_lazy_message_extension] {\n"
+ " bb: 127\n"
+ "}\n"
+ "[protobuf_unittest.optional_unverified_lazy_message_extension] {\n"
+ " bb: 128\n"
+ "}\n"
+ "[protobuf_unittest.repeated_int32_extension]: 201\n"
+ "[protobuf_unittest.repeated_int32_extension]: 301\n"
+ "[protobuf_unittest.repeated_int64_extension]: 202\n"
+ "[protobuf_unittest.repeated_int64_extension]: 302\n"
+ "[protobuf_unittest.repeated_uint32_extension]: 203\n"
+ "[protobuf_unittest.repeated_uint32_extension]: 303\n"
+ "[protobuf_unittest.repeated_uint64_extension]: 204\n"
+ "[protobuf_unittest.repeated_uint64_extension]: 304\n"
+ "[protobuf_unittest.repeated_sint32_extension]: 205\n"
+ "[protobuf_unittest.repeated_sint32_extension]: 305\n"
+ "[protobuf_unittest.repeated_sint64_extension]: 206\n"
+ "[protobuf_unittest.repeated_sint64_extension]: 306\n"
+ "[protobuf_unittest.repeated_fixed32_extension]: 207\n"
+ "[protobuf_unittest.repeated_fixed32_extension]: 307\n"
+ "[protobuf_unittest.repeated_fixed64_extension]: 208\n"
+ "[protobuf_unittest.repeated_fixed64_extension]: 308\n"
+ "[protobuf_unittest.repeated_sfixed32_extension]: 209\n"
+ "[protobuf_unittest.repeated_sfixed32_extension]: 309\n"
+ "[protobuf_unittest.repeated_sfixed64_extension]: 210\n"
+ "[protobuf_unittest.repeated_sfixed64_extension]: 310\n"
+ "[protobuf_unittest.repeated_float_extension]: 211.0\n"
+ "[protobuf_unittest.repeated_float_extension]: 311.0\n"
+ "[protobuf_unittest.repeated_double_extension]: 212.0\n"
+ "[protobuf_unittest.repeated_double_extension]: 312.0\n"
+ "[protobuf_unittest.repeated_bool_extension]: true\n"
+ "[protobuf_unittest.repeated_bool_extension]: false\n"
+ "[protobuf_unittest.repeated_string_extension]: \"215\"\n"
+ "[protobuf_unittest.repeated_string_extension]: \"315\"\n"
+ "[protobuf_unittest.repeated_bytes_extension]: \"216\"\n"
+ "[protobuf_unittest.repeated_bytes_extension]: \"316\"\n"
+ "[protobuf_unittest.repeatedgroup_extension] {\n"
+ " a: 217\n"
+ "}\n"
+ "[protobuf_unittest.repeatedgroup_extension] {\n"
+ " a: 317\n"
+ "}\n"
+ "[protobuf_unittest.repeated_nested_message_extension] {\n"
+ " bb: 218\n"
+ "}\n"
+ "[protobuf_unittest.repeated_nested_message_extension] {\n"
+ " bb: 318\n"
+ "}\n"
+ "[protobuf_unittest.repeated_foreign_message_extension] {\n"
+ " c: 219\n"
+ "}\n"
+ "[protobuf_unittest.repeated_foreign_message_extension] {\n"
+ " c: 319\n"
+ "}\n"
+ "[protobuf_unittest.repeated_import_message_extension] {\n"
+ " d: 220\n"
+ "}\n"
+ "[protobuf_unittest.repeated_import_message_extension] {\n"
+ " d: 320\n"
+ "}\n"
+ "[protobuf_unittest.repeated_nested_enum_extension]: BAR\n"
+ "[protobuf_unittest.repeated_nested_enum_extension]: BAZ\n"
+ "[protobuf_unittest.repeated_foreign_enum_extension]: FOREIGN_BAR\n"
+ "[protobuf_unittest.repeated_foreign_enum_extension]: FOREIGN_BAZ\n"
+ "[protobuf_unittest.repeated_import_enum_extension]: IMPORT_BAR\n"
+ "[protobuf_unittest.repeated_import_enum_extension]: IMPORT_BAZ\n"
+ "[protobuf_unittest.repeated_string_piece_extension]: \"224\"\n"
+ "[protobuf_unittest.repeated_string_piece_extension]: \"324\"\n"
+ "[protobuf_unittest.repeated_cord_extension]: \"225\"\n"
+ "[protobuf_unittest.repeated_cord_extension]: \"325\"\n"
+ "[protobuf_unittest.repeated_lazy_message_extension] {\n"
+ " bb: 227\n"
+ "}\n"
+ "[protobuf_unittest.repeated_lazy_message_extension] {\n"
+ " bb: 327\n"
+ "}\n"
+ "[protobuf_unittest.default_int32_extension]: 401\n"
+ "[protobuf_unittest.default_int64_extension]: 402\n"
+ "[protobuf_unittest.default_uint32_extension]: 403\n"
+ "[protobuf_unittest.default_uint64_extension]: 404\n"
+ "[protobuf_unittest.default_sint32_extension]: 405\n"
+ "[protobuf_unittest.default_sint64_extension]: 406\n"
+ "[protobuf_unittest.default_fixed32_extension]: 407\n"
+ "[protobuf_unittest.default_fixed64_extension]: 408\n"
+ "[protobuf_unittest.default_sfixed32_extension]: 409\n"
+ "[protobuf_unittest.default_sfixed64_extension]: 410\n"
+ "[protobuf_unittest.default_float_extension]: 411.0\n"
+ "[protobuf_unittest.default_double_extension]: 412.0\n"
+ "[protobuf_unittest.default_bool_extension]: false\n"
+ "[protobuf_unittest.default_string_extension]: \"415\"\n"
+ "[protobuf_unittest.default_bytes_extension]: \"416\"\n"
+ "[protobuf_unittest.default_nested_enum_extension]: FOO\n"
+ "[protobuf_unittest.default_foreign_enum_extension]: FOREIGN_FOO\n"
+ "[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO\n"
+ "[protobuf_unittest.default_string_piece_extension]: \"424\"\n"
+ "[protobuf_unittest.default_cord_extension]: \"425\"\n"
+ "[protobuf_unittest.oneof_uint32_extension]: 601\n"
+ "[protobuf_unittest.oneof_nested_message_extension] {\n"
+ " bb: 602\n"
+ "}\n"
+ "[protobuf_unittest.oneof_string_extension]: \"603\"\n"
+ "[protobuf_unittest.oneof_bytes_extension]: \"604\"\n";
public static final TestRequired TEST_REQUIRED_UNINITIALIZED = public static final TestRequired TEST_REQUIRED_UNINITIALIZED =
TestRequired.newBuilder().setA(1).buildPartial(); TestRequired.newBuilder().setA(1).buildPartial();
public static final TestRequired TEST_REQUIRED_INITIALIZED = public static final TestRequired TEST_REQUIRED_INITIALIZED =
@ -3764,108 +4035,6 @@ public final class TestUtil {
} }
} }
/** @param filePath The path relative to {@link #getTestDataDir}. */
public static String readTextFromFile(String filePath) {
return readBytesFromFile(filePath)
.toStringUtf8()
.replace(System.getProperty("line.separator"), "\n");
}
private static File getTestDataDir() {
// Search each parent directory looking for "src/google/protobuf".
File ancestor = new File(System.getProperty("protobuf.dir", "."));
String initialPath = ancestor.getAbsolutePath();
try {
ancestor = ancestor.getCanonicalFile();
} catch (IOException e) {
throw new RuntimeException("Couldn't get canonical name of working directory.", e);
}
String srcRootCheck = "src/google/protobuf";
// If we're running w/ Bazel on Windows, we're not in a sandbox, so we
// we must change our source root check condition to find the true test data dir.
String testBinaryName = System.getenv("TEST_BINARY");
if (testBinaryName != null && testBinaryName.endsWith(".exe")) {
srcRootCheck = srcRootCheck + "/descriptor.cc";
}
while (ancestor != null && ancestor.exists()) {
// Identify the true source root.
if (new File(ancestor, srcRootCheck).exists()) {
return new File(ancestor, "src/google/protobuf/testdata");
}
ancestor = ancestor.getParentFile();
}
throw new RuntimeException(
"Could not find golden files. This test must be run from within the "
+ "protobuf source package so that it can read test data files from the "
+ "C++ source tree: "
+ initialPath);
}
/** @param filename The path relative to {@link #getTestDataDir}. */
public static ByteString readBytesFromFile(String filename) {
File fullPath = new File(getTestDataDir(), filename);
try {
RandomAccessFile file = new RandomAccessFile(fullPath, "r");
byte[] content = new byte[(int) file.length()];
file.readFully(content);
return ByteString.copyFrom(content);
} catch (IOException e) {
// Throw a RuntimeException here so that we can call this function from
// static initializers.
throw new IllegalArgumentException("Couldn't read file: " + fullPath.getPath(), e);
}
}
// END FULL-RUNTIME
private static ByteString readBytesFromResource(String name) {
try {
InputStream in = TestUtil.class.getResourceAsStream(name);
if (in == null) { //
throw new RuntimeException("Tests data file " + name + " is missing.");
}
return ByteString.readFrom(in);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Get the bytes of the "golden message". This is a serialized TestAllTypes with all fields set as
* they would be by {@link #setAllFields(TestAllTypes.Builder)}, but it is loaded from a file on
* disk rather than generated dynamically. The file is actually generated by C++ code, so testing
* against it verifies compatibility with C++.
*/
public static ByteString getGoldenMessage() {
if (goldenMessage == null) {
goldenMessage =
readBytesFromResource("/google/protobuf/testdata/golden_message_oneof_implemented");
}
return goldenMessage;
}
private static ByteString goldenMessage = null;
/**
* Get the bytes of the "golden packed fields message". This is a serialized TestPackedTypes with
* all fields set as they would be by {@link #setPackedFields(TestPackedTypes.Builder)}, but it is
* loaded from a file on disk rather than generated dynamically. The file is actually generated by
* C++ code, so testing against it verifies compatibility with C++.
*/
public static ByteString getGoldenPackedFieldsMessage() {
if (goldenPackedFieldsMessage == null) {
goldenPackedFieldsMessage =
readBytesFromResource("/google/protobuf/testdata/golden_packed_fields_message");
}
return goldenPackedFieldsMessage;
}
private static ByteString goldenPackedFieldsMessage = null;
// BEGIN FULL-RUNTIME
/** /**
* Mock implementation of {@link GeneratedMessage.BuilderParent} for testing. * Mock implementation of {@link GeneratedMessage.BuilderParent} for testing.
* *

@ -59,11 +59,6 @@ public class TextFormatTest {
"\\\"A string with \\' characters \\n and \\r newlines " "\\\"A string with \\' characters \\n and \\r newlines "
+ "and \\t tabs and \\001 slashes \\\\"; + "and \\t tabs and \\001 slashes \\\\";
private static final String ALL_FIELDS_SET_TEXT =
TestUtil.readTextFromFile("text_format_unittest_data_oneof_implemented.txt");
private static final String ALL_EXTENSIONS_SET_TEXT =
TestUtil.readTextFromFile("text_format_unittest_extensions_data.txt");
private static final String EXOTIC_TEXT = private static final String EXOTIC_TEXT =
"" ""
+ "repeated_int32: -1\n" + "repeated_int32: -1\n"
@ -139,12 +134,7 @@ public class TextFormatTest {
public void testPrintMessage() throws Exception { public void testPrintMessage() throws Exception {
String javaText = TextFormat.printer().printToString(TestUtil.getAllSet()); String javaText = TextFormat.printer().printToString(TestUtil.getAllSet());
// Java likes to add a trailing ".0" to floats and doubles. C printf assertThat(javaText).isEqualTo(TestUtil.ALL_FIELDS_SET_TEXT);
// (with %g format) does not. Our golden files are used for both
// C++ and Java TextFormat classes, so we need to conform.
javaText = javaText.replace(".0\n", "\n");
assertThat(javaText).isEqualTo(ALL_FIELDS_SET_TEXT);
} }
@Test @Test
@ -159,12 +149,7 @@ public class TextFormatTest {
public void testPrintMessageBuilder() throws Exception { public void testPrintMessageBuilder() throws Exception {
String javaText = TextFormat.printer().printToString(TestUtil.getAllSetBuilder()); String javaText = TextFormat.printer().printToString(TestUtil.getAllSetBuilder());
// Java likes to add a trailing ".0" to floats and doubles. C printf assertThat(javaText).isEqualTo(TestUtil.ALL_FIELDS_SET_TEXT);
// (with %g format) does not. Our golden files are used for both
// C++ and Java TextFormat classes, so we need to conform.
javaText = javaText.replace(".0\n", "\n");
assertThat(javaText).isEqualTo(ALL_FIELDS_SET_TEXT);
} }
/** Print TestAllExtensions and compare with golden file. */ /** Print TestAllExtensions and compare with golden file. */
@ -172,12 +157,7 @@ public class TextFormatTest {
public void testPrintExtensions() throws Exception { public void testPrintExtensions() throws Exception {
String javaText = TextFormat.printer().printToString(TestUtil.getAllExtensionsSet()); String javaText = TextFormat.printer().printToString(TestUtil.getAllExtensionsSet());
// Java likes to add a trailing ".0" to floats and doubles. C printf assertThat(javaText).isEqualTo(TestUtil.ALL_EXTENSIONS_SET_TEXT);
// (with %g format) does not. Our golden files are used for both
// C++ and Java TextFormat classes, so we need to conform.
javaText = javaText.replace(".0\n", "\n");
assertThat(javaText).isEqualTo(ALL_EXTENSIONS_SET_TEXT);
} }
// Creates an example unknown field set. // Creates an example unknown field set.
@ -353,13 +333,13 @@ public class TextFormatTest {
@Test @Test
public void testMerge() throws Exception { public void testMerge() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(ALL_FIELDS_SET_TEXT, builder); TextFormat.merge(TestUtil.ALL_FIELDS_SET_TEXT, builder);
TestUtil.assertAllFieldsSet(builder.build()); TestUtil.assertAllFieldsSet(builder.build());
} }
@Test @Test
public void testParse() throws Exception { public void testParse() throws Exception {
TestUtil.assertAllFieldsSet(TextFormat.parse(ALL_FIELDS_SET_TEXT, TestAllTypes.class)); TestUtil.assertAllFieldsSet(TextFormat.parse(TestUtil.ALL_FIELDS_SET_TEXT, TestAllTypes.class));
} }
@Test @Test
@ -399,14 +379,15 @@ public class TextFormatTest {
@Test @Test
public void testMergeReader() throws Exception { public void testMergeReader() throws Exception {
TestAllTypes.Builder builder = TestAllTypes.newBuilder(); TestAllTypes.Builder builder = TestAllTypes.newBuilder();
TextFormat.merge(new StringReader(ALL_FIELDS_SET_TEXT), builder); TextFormat.merge(new StringReader(TestUtil.ALL_FIELDS_SET_TEXT), builder);
TestUtil.assertAllFieldsSet(builder.build()); TestUtil.assertAllFieldsSet(builder.build());
} }
@Test @Test
public void testMergeExtensions() throws Exception { public void testMergeExtensions() throws Exception {
TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
TextFormat.merge(ALL_EXTENSIONS_SET_TEXT, TestUtil.getFullExtensionRegistry(), builder); TextFormat.merge(
TestUtil.ALL_EXTENSIONS_SET_TEXT, TestUtil.getFullExtensionRegistry(), builder);
TestUtil.assertAllExtensionsSet(builder.build()); TestUtil.assertAllExtensionsSet(builder.build());
} }
@ -414,7 +395,9 @@ public class TextFormatTest {
public void testParseExtensions() throws Exception { public void testParseExtensions() throws Exception {
TestUtil.assertAllExtensionsSet( TestUtil.assertAllExtensionsSet(
TextFormat.parse( TextFormat.parse(
ALL_EXTENSIONS_SET_TEXT, TestUtil.getFullExtensionRegistry(), TestAllExtensions.class)); TestUtil.ALL_EXTENSIONS_SET_TEXT,
TestUtil.getFullExtensionRegistry(),
TestAllExtensions.class));
} }
@Test @Test

@ -719,7 +719,7 @@ class GeneratedDescriptorTest(unittest.TestCase):
excepted_dict['new_key'] = 'new' excepted_dict['new_key'] = 'new'
self.assertNotEqual(mapping, excepted_dict) self.assertNotEqual(mapping, excepted_dict)
self.assertRaises(KeyError, mapping.__getitem__, 'key_error') self.assertRaises(KeyError, mapping.__getitem__, 'key_error')
self.assertRaises(KeyError, mapping.__getitem__, len(mapping) + 1) self.assertRaises(KeyError, mapping.__getitem__, len(mapping) * 2)
# TODO: Add __repr__ support for DescriptorMapping. # TODO: Add __repr__ support for DescriptorMapping.
if api_implementation.Type() == 'cpp': if api_implementation.Type() == 'cpp':
self.assertEqual(str(mapping)[0], '<') self.assertEqual(str(mapping)[0], '<')

@ -53,7 +53,7 @@ class FieldMaskTest(unittest.TestCase):
mask = field_mask_pb2.FieldMask() mask = field_mask_pb2.FieldMask()
msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR msg_descriptor = unittest_pb2.TestAllTypes.DESCRIPTOR
mask.AllFieldsFromDescriptor(msg_descriptor) mask.AllFieldsFromDescriptor(msg_descriptor)
self.assertEqual(79, len(mask.paths)) self.assertEqual(80, len(mask.paths))
self.assertTrue(mask.IsValidForDescriptor(msg_descriptor)) self.assertTrue(mask.IsValidForDescriptor(msg_descriptor))
for field in msg_descriptor.fields: for field in msg_descriptor.fields:
self.assertTrue(field.name in mask.paths) self.assertTrue(field.name in mask.paths)

@ -63,35 +63,6 @@ class MessageTest(unittest.TestCase):
message_module.TestAllTypes.FromString(bad_utf8_data) message_module.TestAllTypes.FromString(bad_utf8_data)
self.assertIn('TestAllTypes.optional_string', str(context.exception)) self.assertIn('TestAllTypes.optional_string', str(context.exception))
def testGoldenMessage(self, message_module):
# Proto3 doesn't have the "default_foo" members or foreign enums,
# and doesn't preserve unknown fields, so for proto3 we use a golden
# message that doesn't have these fields set.
if message_module is unittest_pb2:
golden_data = test_util.GoldenFileData('golden_message_oneof_implemented')
else:
golden_data = test_util.GoldenFileData('golden_message_proto3')
golden_message = message_module.TestAllTypes()
golden_message.ParseFromString(golden_data)
if message_module is unittest_pb2:
test_util.ExpectAllFieldsSet(self, golden_message)
self.assertEqual(golden_data, golden_message.SerializeToString())
golden_copy = copy.deepcopy(golden_message)
self.assertEqual(golden_data, golden_copy.SerializeToString())
def testGoldenPackedMessage(self, message_module):
golden_data = test_util.GoldenFileData('golden_packed_fields_message')
golden_message = message_module.TestPackedTypes()
parsed_bytes = golden_message.ParseFromString(golden_data)
all_set = message_module.TestPackedTypes()
test_util.SetAllPackedFields(all_set)
self.assertEqual(parsed_bytes, len(golden_data))
self.assertEqual(all_set, golden_message)
self.assertEqual(golden_data, all_set.SerializeToString())
golden_copy = copy.deepcopy(golden_message)
self.assertEqual(golden_data, golden_copy.SerializeToString())
def testParseErrors(self, message_module): def testParseErrors(self, message_module):
msg = message_module.TestAllTypes() msg = message_module.TestAllTypes()
self.assertRaises(TypeError, msg.FromString, 0) self.assertRaises(TypeError, msg.FromString, 0)
@ -147,7 +118,9 @@ class MessageTest(unittest.TestCase):
golden_message.SerializeToString(deterministic=BadArg()) golden_message.SerializeToString(deterministic=BadArg())
def testPickleSupport(self, message_module): def testPickleSupport(self, message_module):
golden_data = test_util.GoldenFileData('golden_message') golden_message = message_module.TestAllTypes()
test_util.SetAllFields(golden_message)
golden_data = golden_message.SerializeToString()
golden_message = message_module.TestAllTypes() golden_message = message_module.TestAllTypes()
golden_message.ParseFromString(golden_data) golden_message.ParseFromString(golden_data)
pickled_message = pickle.dumps(golden_message) pickled_message = pickle.dumps(golden_message)
@ -1424,36 +1397,6 @@ class Proto2Test(unittest.TestCase):
all_set.Extensions[unittest_pb2.packed_float_extension].extend([61.0, 71.0]) all_set.Extensions[unittest_pb2.packed_float_extension].extend([61.0, 71.0])
self.assertNotEqual(all_set, copy) self.assertNotEqual(all_set, copy)
def testGoldenExtensions(self):
golden_data = test_util.GoldenFileData('golden_message')
golden_message = unittest_pb2.TestAllExtensions()
golden_message.ParseFromString(golden_data)
all_set = unittest_pb2.TestAllExtensions()
test_util.SetAllExtensions(all_set)
self.assertEqual(all_set, golden_message)
self.assertEqual(golden_data, golden_message.SerializeToString())
golden_copy = copy.deepcopy(golden_message)
self.assertEqual(golden_message, golden_copy)
# Depend on a specific serialization order for extensions is not
# reasonable to guarantee.
if api_implementation.Type() != 'upb':
self.assertEqual(golden_data, golden_copy.SerializeToString())
def testGoldenPackedExtensions(self):
golden_data = test_util.GoldenFileData('golden_packed_fields_message')
golden_message = unittest_pb2.TestPackedExtensions()
golden_message.ParseFromString(golden_data)
all_set = unittest_pb2.TestPackedExtensions()
test_util.SetAllPackedExtensions(all_set)
self.assertEqual(all_set, golden_message)
self.assertEqual(golden_data, all_set.SerializeToString())
golden_copy = copy.deepcopy(golden_message)
self.assertEqual(golden_message, golden_copy)
# Depend on a specific serialization order for extensions is not
# reasonable to guarantee.
if api_implementation.Type() != 'upb':
self.assertEqual(golden_data, golden_copy.SerializeToString())
def testPickleIncompleteProto(self): def testPickleIncompleteProto(self):
golden_message = unittest_pb2.TestRequired(a=1) golden_message = unittest_pb2.TestRequired(a=1)
pickled_message = pickle.dumps(golden_message) pickled_message = pickle.dumps(golden_message)

@ -77,6 +77,7 @@ def SetAllNonLazyFields(message):
message.optional_string_piece = u'124' message.optional_string_piece = u'124'
message.optional_cord = u'125' message.optional_cord = u'125'
message.optional_bytes_cord = b'optional bytes cord'
# #
# Repeated fields. # Repeated fields.
@ -247,6 +248,7 @@ def SetAllExtensions(message):
extensions[pb2.optional_string_piece_extension] = u'124' extensions[pb2.optional_string_piece_extension] = u'124'
extensions[pb2.optional_cord_extension] = u'125' extensions[pb2.optional_cord_extension] = u'125'
extensions[pb2.optional_bytes_cord_extension] = b'optional bytes cord'
# #
# Repeated fields. # Repeated fields.
@ -423,6 +425,7 @@ def ExpectAllFieldsSet(test_case, message):
test_case.assertTrue(message.HasField('optional_string_piece')) test_case.assertTrue(message.HasField('optional_string_piece'))
test_case.assertTrue(message.HasField('optional_cord')) test_case.assertTrue(message.HasField('optional_cord'))
test_case.assertTrue(message.HasField('optional_bytes_cord'))
test_case.assertEqual(101, message.optional_int32) test_case.assertEqual(101, message.optional_int32)
test_case.assertEqual(102, message.optional_int64) test_case.assertEqual(102, message.optional_int64)

@ -212,7 +212,7 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
unknown_field_set, unknown_field_set,
(17, 0, 117)) (17, 0, 117))
self.assertEqual(98, len(unknown_field_set)) self.assertEqual(99, len(unknown_field_set))
def testCopyFrom(self): def testCopyFrom(self):
message = unittest_pb2.TestEmptyMessage() message = unittest_pb2.TestEmptyMessage()
@ -250,7 +250,7 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
self.empty_message.Clear() self.empty_message.Clear()
# All cleared, even unknown fields. # All cleared, even unknown fields.
self.assertEqual(self.empty_message.SerializeToString(), b'') self.assertEqual(self.empty_message.SerializeToString(), b'')
self.assertEqual(len(unknown_field_set), 98) self.assertEqual(len(unknown_field_set), 99)
@unittest.skipIf((sys.version_info.major, sys.version_info.minor) < (3, 4), @unittest.skipIf((sys.version_info.major, sys.version_info.minor) < (3, 4),
'tracemalloc requires python 3.4+') 'tracemalloc requires python 3.4+')
@ -309,7 +309,7 @@ class UnknownFieldsAccessorsTest(unittest.TestCase):
def testUnknownExtensions(self): def testUnknownExtensions(self):
message = unittest_pb2.TestEmptyMessageWithExtensions() message = unittest_pb2.TestEmptyMessageWithExtensions()
message.ParseFromString(self.all_fields_data) message.ParseFromString(self.all_fields_data)
self.assertEqual(len(unknown_fields.UnknownFieldSet(message)), 98) self.assertEqual(len(unknown_fields.UnknownFieldSet(message)), 99)
self.assertEqual(message.SerializeToString(), self.all_fields_data) self.assertEqual(message.SerializeToString(), self.all_fields_data)

@ -117,6 +117,7 @@ set(libprotobuf_hdrs
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.pb.h ${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor.pb.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_database.h ${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_database.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_legacy.h ${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_legacy.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_lite.h
${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_visitor.h ${protobuf_SOURCE_DIR}/src/google/protobuf/descriptor_visitor.h
${protobuf_SOURCE_DIR}/src/google/protobuf/dynamic_message.h ${protobuf_SOURCE_DIR}/src/google/protobuf/dynamic_message.h
${protobuf_SOURCE_DIR}/src/google/protobuf/endian.h ${protobuf_SOURCE_DIR}/src/google/protobuf/endian.h

@ -238,6 +238,7 @@ cc_test(
deps = [ deps = [
":port_def", ":port_def",
":varint_shuffle", ":varint_shuffle",
"@com_google_absl//absl/base:config",
"@com_google_absl//absl/log:absl_check", "@com_google_absl//absl/log:absl_check",
"@com_google_googletest//:gtest", "@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
@ -436,6 +437,7 @@ cc_library(
"//src/google/protobuf/io", "//src/google/protobuf/io",
"//src/google/protobuf/stubs:lite", "//src/google/protobuf/stubs:lite",
"@com_google_absl//absl/base", "@com_google_absl//absl/base",
"@com_google_absl//absl/base:config",
"@com_google_absl//absl/container:btree", "@com_google_absl//absl/container:btree",
"@com_google_absl//absl/container:flat_hash_set", "@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/hash", "@com_google_absl//absl/hash",
@ -482,6 +484,7 @@ cc_library(
"descriptor.pb.h", "descriptor.pb.h",
"descriptor_database.h", "descriptor_database.h",
"descriptor_legacy.h", "descriptor_legacy.h",
"descriptor_lite.h",
"descriptor_visitor.h", "descriptor_visitor.h",
"dynamic_message.h", "dynamic_message.h",
"feature_resolver.h", "feature_resolver.h",
@ -1256,7 +1259,6 @@ cc_test(
"message_unittest.cc", "message_unittest.cc",
"message_unittest.inc", "message_unittest.inc",
], ],
data = [":testdata"],
deps = [ deps = [
":cc_test_protos", ":cc_test_protos",
":protobuf", ":protobuf",

@ -18,41 +18,6 @@
namespace google { namespace google {
namespace protobuf { namespace protobuf {
template <typename T, bool use_arena>
void TestParseCorruptedString(const T& message) {
int success_count = 0;
std::string s;
{
// Map order is not deterministic. To make the test deterministic we want
// to serialize the proto deterministically.
io::StringOutputStream output(&s);
io::CodedOutputStream out(&output);
out.SetSerializationDeterministic(true);
message.SerializePartialToCodedStream(&out);
}
const int kMaxIters = 900;
const int stride = s.size() <= kMaxIters ? 1 : s.size() / kMaxIters;
const int start = stride == 1 || use_arena ? 0 : (stride + 1) / 2;
for (int i = start; i < s.size(); i += stride) {
for (int c = 1 + (i % 17); c < 256; c += 2 * c + (i & 3)) {
s[i] ^= c;
Arena arena;
T* message = Arena::CreateMessage<T>(use_arena ? &arena : nullptr);
if (message->ParseFromString(s)) {
++success_count;
}
if (!use_arena) {
delete message;
}
s[i] ^= c; // Restore s to its original state.
}
}
// This next line is a low bar. But getting through the test without crashing
// due to use-after-free or other bugs is a big part of what we're checking.
ABSL_CHECK_GT(success_count, 0);
}
namespace internal { namespace internal {
struct ArenaTestPeer { struct ArenaTestPeer {

@ -1308,13 +1308,6 @@ TEST(ArenaTest, NoHeapAllocationsTest) {
arena.Reset(); arena.Reset();
} }
TEST(ArenaTest, ParseCorruptedString) {
TestAllTypes message;
TestUtil::SetAllFields(&message);
TestParseCorruptedString<TestAllTypes, true>(message);
TestParseCorruptedString<TestAllTypes, false>(message);
}
#if PROTOBUF_RTTI #if PROTOBUF_RTTI
// Test construction on an arena via generic MessageLite interface. We should be // Test construction on an arena via generic MessageLite interface. We should be
// able to successfully deserialize on the arena without incurring heap // able to successfully deserialize on the arena without incurring heap

@ -323,6 +323,7 @@ cc_test(
"//:protobuf", "//:protobuf",
"//src/google/protobuf:cc_test_protos", "//src/google/protobuf:cc_test_protos",
"//src/google/protobuf:test_textproto", "//src/google/protobuf:test_textproto",
"//src/google/protobuf:test_util",
"//src/google/protobuf:test_util2", "//src/google/protobuf:test_util2",
"//src/google/protobuf/compiler/cpp:names", "//src/google/protobuf/compiler/cpp:names",
"//src/google/protobuf/io", "//src/google/protobuf/io",

@ -47,6 +47,7 @@
#include "google/protobuf/compiler/subprocess.h" #include "google/protobuf/compiler/subprocess.h"
#include "google/protobuf/io/io_win32.h" #include "google/protobuf/io/io_win32.h"
#include "google/protobuf/test_textproto.h" #include "google/protobuf/test_textproto.h"
#include "google/protobuf/test_util.h"
#include "google/protobuf/test_util2.h" #include "google/protobuf/test_util2.h"
#include "google/protobuf/unittest.pb.h" #include "google/protobuf/unittest.pb.h"
#include "google/protobuf/unittest_custom_options.pb.h" #include "google/protobuf/unittest_custom_options.pb.h"
@ -3998,7 +3999,16 @@ class EncodeDecodeTest : public testing::TestWithParam<EncodeDecodeTestMode> {
std::string unittest_proto_descriptor_set_filename_; std::string unittest_proto_descriptor_set_filename_;
}; };
static void WriteGoldenMessage(const std::string& filename) {
protobuf_unittest::TestAllTypes message;
TestUtil::SetAllFields(&message);
std::string golden = message.SerializeAsString();
ABSL_CHECK_OK(File::SetContents(filename, golden, true));
}
TEST_P(EncodeDecodeTest, Encode) { TEST_P(EncodeDecodeTest, Encode) {
std::string golden_path = absl::StrCat(TestTempDir(), "/golden_message");
WriteGoldenMessage(golden_path);
RedirectStdinFromFile(TestUtil::GetTestDataPath( RedirectStdinFromFile(TestUtil::GetTestDataPath(
"google/protobuf/" "google/protobuf/"
"testdata/text_format_unittest_data_oneof_implemented.txt")); "testdata/text_format_unittest_data_oneof_implemented.txt"));
@ -4008,14 +4018,14 @@ TEST_P(EncodeDecodeTest, Encode) {
} }
EXPECT_TRUE( EXPECT_TRUE(
Run(absl::StrCat(args, " --encode=protobuf_unittest.TestAllTypes"))); Run(absl::StrCat(args, " --encode=protobuf_unittest.TestAllTypes")));
ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath( ExpectStdoutMatchesBinaryFile(golden_path);
"google/protobuf/testdata/golden_message_oneof_implemented"));
ExpectStderrMatchesText(""); ExpectStderrMatchesText("");
} }
TEST_P(EncodeDecodeTest, Decode) { TEST_P(EncodeDecodeTest, Decode) {
RedirectStdinFromFile(TestUtil::GetTestDataPath( std::string golden_path = absl::StrCat(TestTempDir(), "/golden_message");
"google/protobuf/testdata/golden_message_oneof_implemented")); WriteGoldenMessage(golden_path);
RedirectStdinFromFile(golden_path);
EXPECT_TRUE( EXPECT_TRUE(
Run("google/protobuf/unittest.proto" Run("google/protobuf/unittest.proto"
" --decode=protobuf_unittest.TestAllTypes")); " --decode=protobuf_unittest.TestAllTypes"));
@ -4068,6 +4078,8 @@ TEST_P(EncodeDecodeTest, ProtoParseError) {
} }
TEST_P(EncodeDecodeTest, EncodeDeterministicOutput) { TEST_P(EncodeDecodeTest, EncodeDeterministicOutput) {
std::string golden_path = absl::StrCat(TestTempDir(), "/golden_message");
WriteGoldenMessage(golden_path);
RedirectStdinFromFile(TestUtil::GetTestDataPath( RedirectStdinFromFile(TestUtil::GetTestDataPath(
"google/protobuf/" "google/protobuf/"
"testdata/text_format_unittest_data_oneof_implemented.txt")); "testdata/text_format_unittest_data_oneof_implemented.txt"));
@ -4077,14 +4089,14 @@ TEST_P(EncodeDecodeTest, EncodeDeterministicOutput) {
} }
EXPECT_TRUE(Run(absl::StrCat( EXPECT_TRUE(Run(absl::StrCat(
args, " --encode=protobuf_unittest.TestAllTypes --deterministic_output"))); args, " --encode=protobuf_unittest.TestAllTypes --deterministic_output")));
ExpectStdoutMatchesBinaryFile(TestUtil::GetTestDataPath( ExpectStdoutMatchesBinaryFile(golden_path);
"google/protobuf/testdata/golden_message_oneof_implemented"));
ExpectStderrMatchesText(""); ExpectStderrMatchesText("");
} }
TEST_P(EncodeDecodeTest, DecodeDeterministicOutput) { TEST_P(EncodeDecodeTest, DecodeDeterministicOutput) {
RedirectStdinFromFile(TestUtil::GetTestDataPath( std::string golden_path = absl::StrCat(TestTempDir(), "/golden_message");
"google/protobuf/testdata/golden_message_oneof_implemented")); WriteGoldenMessage(golden_path);
RedirectStdinFromFile(golden_path);
EXPECT_FALSE( EXPECT_FALSE(
Run("google/protobuf/unittest.proto" Run("google/protobuf/unittest.proto"
" --decode=protobuf_unittest.TestAllTypes --deterministic_output")); " --decode=protobuf_unittest.TestAllTypes --deterministic_output"));

@ -115,7 +115,6 @@ FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor,
break; break;
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
is_string_ = true; is_string_ = true;
string_type_ = descriptor->options().ctype();
is_inlined_ = IsStringInlined(descriptor, options); is_inlined_ = IsStringInlined(descriptor, options);
is_bytes_ = descriptor->type() == FieldDescriptor::TYPE_BYTES; is_bytes_ = descriptor->type() == FieldDescriptor::TYPE_BYTES;
has_default_constexpr_constructor_ = is_repeated_or_map; has_default_constexpr_constructor_ = is_repeated_or_map;
@ -242,15 +241,18 @@ std::unique_ptr<FieldGeneratorBase> MakeGenerator(const FieldDescriptor* field,
case FieldDescriptor::CPPTYPE_MESSAGE: case FieldDescriptor::CPPTYPE_MESSAGE:
return MakeSinguarMessageGenerator(field, options, scc); return MakeSinguarMessageGenerator(field, options, scc);
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
if (field->type() == FieldDescriptor::TYPE_BYTES && switch (field->cpp_string_type()) {
field->options().ctype() == FieldOptions::CORD) { case FieldDescriptor::CppStringType::kCord:
if (field->real_containing_oneof()) { if (field->type() == FieldDescriptor::TYPE_BYTES) {
return MakeOneofCordGenerator(field, options, scc); if (field->real_containing_oneof()) {
} else { return MakeOneofCordGenerator(field, options, scc);
return MakeSingularCordGenerator(field, options, scc); } else {
} return MakeSingularCordGenerator(field, options, scc);
} else { }
return MakeSinguarStringGenerator(field, options, scc); }
ABSL_FALLTHROUGH_INTENDED;
default:
return MakeSinguarStringGenerator(field, options, scc);
} }
case FieldDescriptor::CPPTYPE_ENUM: case FieldDescriptor::CPPTYPE_ENUM:
return MakeSinguarEnumGenerator(field, options, scc); return MakeSinguarEnumGenerator(field, options, scc);

@ -84,9 +84,6 @@ class FieldGeneratorBase {
// Returns true if the field API uses bytes (void) instead of chars. // Returns true if the field API uses bytes (void) instead of chars.
bool is_bytes() const { return is_bytes_; } bool is_bytes() const { return is_bytes_; }
// Returns the public API string type for string fields.
FieldOptions::CType string_type() const { return string_type_; }
// Returns true if this field is part of a oneof field. // Returns true if this field is part of a oneof field.
bool is_oneof() const { return is_oneof_; } bool is_oneof() const { return is_oneof_; }
@ -202,7 +199,6 @@ class FieldGeneratorBase {
bool is_lazy_ = false; bool is_lazy_ = false;
bool is_weak_ = false; bool is_weak_ = false;
bool is_oneof_ = false; bool is_oneof_ = false;
FieldOptions::CType string_type_ = FieldOptions::STRING;
bool has_default_constexpr_constructor_ = false; bool has_default_constexpr_constructor_ = false;
}; };
@ -249,7 +245,6 @@ class FieldGenerator {
bool is_foreign() const { return impl_->is_foreign(); } bool is_foreign() const { return impl_->is_foreign(); }
bool is_string() const { return impl_->is_string(); } bool is_string() const { return impl_->is_string(); }
bool is_bytes() const { return impl_->is_bytes(); } bool is_bytes() const { return impl_->is_bytes(); }
FieldOptions::CType string_type() const { return impl_->string_type(); }
bool is_oneof() const { return impl_->is_oneof(); } bool is_oneof() const { return impl_->is_oneof(); }
bool is_inlined() const { return impl_->is_inlined(); } bool is_inlined() const { return impl_->is_inlined(); }
bool has_default_constexpr_constructor() const { bool has_default_constexpr_constructor() const {

@ -1351,7 +1351,8 @@ MessageAnalysis MessageSCCAnalyzer::GetSCCAnalysis(const SCC* scc) {
switch (field->type()) { switch (field->type()) {
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
if (field->options().ctype() == FieldOptions::CORD) { if (field->cpp_string_type() ==
FieldDescriptor::CppStringType::kCord) {
result.contains_cord = true; result.contains_cord = true;
} }
break; break;

@ -214,7 +214,8 @@ Getters RepeatedFieldGetters(const FieldDescriptor* field,
Getters StringFieldGetters(const FieldDescriptor* field, const Options& opts) { Getters StringFieldGetters(const FieldDescriptor* field, const Options& opts) {
std::string member = FieldMemberName(field, ShouldSplit(field, opts)); std::string member = FieldMemberName(field, ShouldSplit(field, opts));
bool is_std_string = field->options().ctype() == FieldOptions::STRING; bool is_std_string =
field->cpp_string_type() == FieldDescriptor::CppStringType::kString;
Getters getters; Getters getters;
if (is_std_string && !field->default_value_string().empty()) { if (is_std_string && !field->default_value_string().empty()) {
@ -234,7 +235,8 @@ Getters StringOneofGetters(const FieldDescriptor* field,
ABSL_CHECK(oneof != nullptr); ABSL_CHECK(oneof != nullptr);
std::string member = FieldMemberName(field, ShouldSplit(field, opts)); std::string member = FieldMemberName(field, ShouldSplit(field, opts));
bool is_std_string = field->options().ctype() == FieldOptions::STRING; bool is_std_string =
field->cpp_string_type() == FieldDescriptor::CppStringType::kString;
std::string field_ptr = member; std::string field_ptr = member;
if (is_std_string) { if (is_std_string) {
@ -251,8 +253,8 @@ Getters StringOneofGetters(const FieldDescriptor* field,
} }
Getters getters; Getters getters;
if (field->default_value_string().empty() || if (field->default_value_string().empty()
field->options().ctype() == FieldOptions::STRING_PIECE) { ) {
getters.base = absl::Substitute("$0 ? $1 : nullptr", has, field_ptr); getters.base = absl::Substitute("$0 ? $1 : nullptr", has, field_ptr);
} else { } else {
getters.base = getters.base =

@ -425,6 +425,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
message1.set_optional_string("abc"); message1.set_optional_string("abc");
message1.mutable_optional_nested_message()->set_bb(1); message1.mutable_optional_nested_message()->set_bb(1);
message1.set_optional_nested_enum(UNITTEST::TestAllTypes::FOO); message1.set_optional_nested_enum(UNITTEST::TestAllTypes::FOO);
message1.set_optional_bytes_cord("bytes cord");
message1.add_repeated_int32(1); message1.add_repeated_int32(1);
message1.add_repeated_int32(2); message1.add_repeated_int32(2);
message1.add_repeated_string("a"); message1.add_repeated_string("a");
@ -438,6 +439,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
message2.set_optional_string("def"); message2.set_optional_string("def");
message2.mutable_optional_nested_message()->set_bb(2); message2.mutable_optional_nested_message()->set_bb(2);
message2.set_optional_nested_enum(UNITTEST::TestAllTypes::BAR); message2.set_optional_nested_enum(UNITTEST::TestAllTypes::BAR);
message2.set_optional_bytes_cord("bytes cord");
message2.add_repeated_int32(3); message2.add_repeated_int32(3);
message2.add_repeated_string("c"); message2.add_repeated_string("c");
message2.add_repeated_nested_message()->set_bb(9); message2.add_repeated_nested_message()->set_bb(9);
@ -449,6 +451,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
EXPECT_EQ("def", message1.optional_string()); EXPECT_EQ("def", message1.optional_string());
EXPECT_EQ(2, message1.optional_nested_message().bb()); EXPECT_EQ(2, message1.optional_nested_message().bb());
EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message1.optional_nested_enum()); EXPECT_EQ(UNITTEST::TestAllTypes::BAR, message1.optional_nested_enum());
EXPECT_EQ(absl::Cord("bytes cord"), message1.optional_bytes_cord());
ASSERT_EQ(1, message1.repeated_int32_size()); ASSERT_EQ(1, message1.repeated_int32_size());
EXPECT_EQ(3, message1.repeated_int32(0)); EXPECT_EQ(3, message1.repeated_int32(0));
ASSERT_EQ(1, message1.repeated_string_size()); ASSERT_EQ(1, message1.repeated_string_size());
@ -462,6 +465,7 @@ TEST(GENERATED_MESSAGE_TEST_NAME, SwapWithOther) {
EXPECT_EQ("abc", message2.optional_string()); EXPECT_EQ("abc", message2.optional_string());
EXPECT_EQ(1, message2.optional_nested_message().bb()); EXPECT_EQ(1, message2.optional_nested_message().bb());
EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.optional_nested_enum()); EXPECT_EQ(UNITTEST::TestAllTypes::FOO, message2.optional_nested_enum());
EXPECT_EQ(absl::Cord("bytes cord"), message2.optional_bytes_cord());
ASSERT_EQ(2, message2.repeated_int32_size()); ASSERT_EQ(2, message2.repeated_int32_size());
EXPECT_EQ(1, message2.repeated_int32(0)); EXPECT_EQ(1, message2.repeated_int32(0));
EXPECT_EQ(2, message2.repeated_int32(1)); EXPECT_EQ(2, message2.repeated_int32(1));

@ -3790,6 +3790,16 @@ bool FieldDescriptor::legacy_enum_field_treated_as_closed() const {
enum_type()->is_closed()); enum_type()->is_closed());
} }
FieldDescriptor::CppStringType FieldDescriptor::cpp_string_type() const {
ABSL_DCHECK(cpp_type() == FieldDescriptor::CPPTYPE_STRING);
switch (internal::cpp::EffectiveStringCType(this)) {
case FieldOptions::CORD:
return CppStringType::kCord;
default:
return CppStringType::kString;
}
}
// Location methods =============================================== // Location methods ===============================================
bool FileDescriptor::GetSourceLocation(const std::vector<int>& path, bool FileDescriptor::GetSourceLocation(const std::vector<int>& path,

@ -49,6 +49,7 @@
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
#include "google/protobuf/descriptor_lite.h"
#include "google/protobuf/extension_set.h" #include "google/protobuf/extension_set.h"
#include "google/protobuf/port.h" #include "google/protobuf/port.h"
@ -731,7 +732,8 @@ PROTOBUF_INTERNAL_CHECK_CLASS_SIZE(Descriptor, 152);
// - Given a DescriptorPool, call DescriptorPool::FindExtensionByNumber() or // - Given a DescriptorPool, call DescriptorPool::FindExtensionByNumber() or
// DescriptorPool::FindExtensionByPrintableName(). // DescriptorPool::FindExtensionByPrintableName().
// Use DescriptorPool to construct your own descriptors. // Use DescriptorPool to construct your own descriptors.
class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase { class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
public internal::FieldDescriptorLite {
public: public:
typedef FieldDescriptorProto Proto; typedef FieldDescriptorProto Proto;
@ -843,6 +845,10 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase {
const char* cpp_type_name() const; // Name of the C++ type. const char* cpp_type_name() const; // Name of the C++ type.
Label label() const; // optional/required/repeated Label label() const; // optional/required/repeated
#ifndef SWIG
CppStringType cpp_string_type() const; // The C++ string type of this field.
#endif
bool is_required() const; // shorthand for label() == LABEL_REQUIRED bool is_required() const; // shorthand for label() == LABEL_REQUIRED
bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL
bool is_repeated() const; // shorthand for label() == LABEL_REPEATED bool is_repeated() const; // shorthand for label() == LABEL_REPEATED

@ -0,0 +1,36 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
//
// This file contains definitions for the descriptors, so they can be used
// without importing descriptor.h
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_LITE_H__
#define GOOGLE_PROTOBUF_DESCRIPTOR_LITE_H__
namespace google {
namespace protobuf {
namespace internal {
class FieldDescriptorLite {
public:
// Identifies the storage type of a C++ string field. This corresponds to
// pb.CppFeatures.StringType, but is compatible with ctype prior to Edition
// 2024. 0 is reserved for errors.
#ifndef SWIG
enum class CppStringType {
kView = 1,
kCord = 2,
kString = 3,
};
#endif
};
} // namespace internal
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_DESCRIPTOR_LITE_H__

@ -7298,6 +7298,20 @@ TEST_F(FeaturesTest, Proto2Features) {
} }
field { name: "utf8" number: 6 label: LABEL_REPEATED type: TYPE_STRING } field { name: "utf8" number: 6 label: LABEL_REPEATED type: TYPE_STRING }
field { name: "req" number: 7 label: LABEL_REQUIRED type: TYPE_INT32 } field { name: "req" number: 7 label: LABEL_REQUIRED type: TYPE_INT32 }
field {
name: "cord"
number: 8
label: LABEL_OPTIONAL
type: TYPE_BYTES
options { ctype: CORD }
}
field {
name: "piece"
number: 9
label: LABEL_OPTIONAL
type: TYPE_STRING
options { ctype: STRING_PIECE }
}
} }
enum_type { enum_type {
name: "Foo2" name: "Foo2"
@ -7351,6 +7365,11 @@ TEST_F(FeaturesTest, Proto2Features) {
EXPECT_TRUE(message->FindFieldByName("req")->is_required()); EXPECT_TRUE(message->FindFieldByName("req")->is_required());
EXPECT_TRUE(file->enum_type(0)->is_closed()); EXPECT_TRUE(file->enum_type(0)->is_closed());
EXPECT_EQ(message->FindFieldByName("str")->cpp_string_type(),
FieldDescriptor::CppStringType::kString);
EXPECT_EQ(message->FindFieldByName("cord")->cpp_string_type(),
FieldDescriptor::CppStringType::kCord);
// Check round-trip consistency. // Check round-trip consistency.
FileDescriptorProto proto; FileDescriptorProto proto;
file->CopyTo(&proto); file->CopyTo(&proto);

@ -117,9 +117,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
} }
case FD::CPPTYPE_STRING: case FD::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: return sizeof(RepeatedField<absl::Cord>);
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return sizeof(RepeatedPtrField<std::string>); return sizeof(RepeatedPtrField<std::string>);
} }
break; break;
@ -147,9 +149,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) {
return sizeof(Message*); return sizeof(Message*);
case FD::CPPTYPE_STRING: case FD::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: return sizeof(absl::Cord);
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return sizeof(ArenaStringPtr); return sizeof(ArenaStringPtr);
} }
break; break;
@ -345,6 +349,7 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
// constructor.) // constructor.)
const Descriptor* descriptor = type_info_->type; const Descriptor* descriptor = type_info_->type;
Arena* arena = GetArena();
// Initialize oneof cases. // Initialize oneof cases.
int oneof_count = 0; int oneof_count = 0;
for (int i = 0; i < descriptor->oneof_decl_count(); ++i) { for (int i = 0; i < descriptor->oneof_decl_count(); ++i) {
@ -390,9 +395,31 @@ void DynamicMessage::SharedCtor(bool lock_factory) {
break; break;
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: if (!field->is_repeated()) {
if (field->has_default_value()) {
new (field_ptr) absl::Cord(field->default_value_string());
} else {
new (field_ptr) absl::Cord;
}
if (arena != nullptr) {
// Cord does not support arena so here we need to notify arena
// to remove the data it allocated on the heap by calling its
// destructor.
arena->OwnDestructor(static_cast<absl::Cord*>(field_ptr));
}
} else {
new (field_ptr) RepeatedField<absl::Cord>(arena);
if (arena != nullptr) {
// Needs to destroy Cord elements.
arena->OwnDestructor(
static_cast<RepeatedField<absl::Cord>*>(field_ptr));
}
}
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
if (!field->is_repeated()) { if (!field->is_repeated()) {
ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr(); ArenaStringPtr* asp = new (field_ptr) ArenaStringPtr();
asp->InitDefault(); asp->InitDefault();
@ -482,9 +509,12 @@ DynamicMessage::~DynamicMessage() {
if (*(reinterpret_cast<const int32_t*>(field_ptr)) == field->number()) { if (*(reinterpret_cast<const int32_t*>(field_ptr)) == field->number()) {
field_ptr = MutableOneofFieldRaw(field); field_ptr = MutableOneofFieldRaw(field);
if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: { delete *reinterpret_cast<absl::Cord**>(field_ptr);
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString: {
reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(); reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
break; break;
} }
@ -516,9 +546,13 @@ DynamicMessage::~DynamicMessage() {
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: reinterpret_cast<RepeatedField<absl::Cord>*>(field_ptr)
->~RepeatedField<absl::Cord>();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
reinterpret_cast<RepeatedPtrField<std::string>*>(field_ptr) reinterpret_cast<RepeatedPtrField<std::string>*>(field_ptr)
->~RepeatedPtrField<std::string>(); ->~RepeatedPtrField<std::string>();
break; break;
@ -536,9 +570,12 @@ DynamicMessage::~DynamicMessage() {
} }
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: { reinterpret_cast<absl::Cord*>(field_ptr)->~Cord();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString: {
reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy(); reinterpret_cast<ArenaStringPtr*>(field_ptr)->Destroy();
break; break;
} }

@ -385,9 +385,13 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: total_size += GetRaw<RepeatedField<absl::Cord>>(message, field)
.SpaceUsedExcludingSelfLong();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
total_size += total_size +=
GetRaw<RepeatedPtrField<std::string> >(message, field) GetRaw<RepeatedPtrField<std::string> >(message, field)
.SpaceUsedExcludingSelfLong(); .SpaceUsedExcludingSelfLong();
@ -426,8 +430,8 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
break; break;
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
total_size += GetField<absl::Cord*>(message, field) total_size += GetField<absl::Cord*>(message, field)
->EstimatedMemoryUsage(); ->EstimatedMemoryUsage();
@ -439,8 +443,8 @@ size_t Reflection::SpaceUsedLong(const Message& message) const {
sizeof(absl::Cord); sizeof(absl::Cord);
} }
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
const std::string* ptr = const std::string* ptr =
&GetField<InlinedStringField>(message, field).GetNoArena(); &GetField<InlinedStringField>(message, field).GetNoArena();
@ -536,15 +540,14 @@ struct OneofFieldMover {
to->SetString(from->GetString()); to->SetString(from->GetString());
break; break;
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
to->SetCord(from->GetCord()); to->SetCord(from->GetCord());
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString:
to->SetArenaStringPtr(from->GetArenaStringPtr()); to->SetArenaStringPtr(from->GetArenaStringPtr());
break; break;
}
} }
break; break;
default: default:
@ -607,9 +610,19 @@ template <bool unsafe_shallow_swap>
void SwapFieldHelper::SwapRepeatedStringField(const Reflection* r, Message* lhs, void SwapFieldHelper::SwapRepeatedStringField(const Reflection* r, Message* lhs,
Message* rhs, Message* rhs,
const FieldDescriptor* field) { const FieldDescriptor* field) {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: case FieldDescriptor::CppStringType::kCord: {
case FieldOptions::STRING: { auto* lhs_cord = r->MutableRaw<RepeatedField<absl::Cord>>(lhs, field);
auto* rhs_cord = r->MutableRaw<RepeatedField<absl::Cord>>(rhs, field);
if (unsafe_shallow_swap) {
lhs_cord->InternalSwap(rhs_cord);
} else {
lhs_cord->Swap(rhs_cord);
}
break;
}
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString: {
auto* lhs_string = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field); auto* lhs_string = r->MutableRaw<RepeatedPtrFieldBase>(lhs, field);
auto* rhs_string = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field); auto* rhs_string = r->MutableRaw<RepeatedPtrFieldBase>(rhs, field);
if (unsafe_shallow_swap) { if (unsafe_shallow_swap) {
@ -673,14 +686,14 @@ template <bool unsafe_shallow_swap>
void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs, void SwapFieldHelper::SwapStringField(const Reflection* r, Message* lhs,
Message* rhs, Message* rhs,
const FieldDescriptor* field) { const FieldDescriptor* field) {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
// Always shallow swap for Cord. // Always shallow swap for Cord.
std::swap(*r->MutableRaw<absl::Cord>(lhs, field), std::swap(*r->MutableRaw<absl::Cord>(lhs, field),
*r->MutableRaw<absl::Cord>(rhs, field)); *r->MutableRaw<absl::Cord>(rhs, field));
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
if (r->IsInlined(field)) { if (r->IsInlined(field)) {
SwapFieldHelper::SwapInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs, SwapFieldHelper::SwapInlinedStrings<unsafe_shallow_swap>(r, lhs, rhs,
field); field);
@ -1150,7 +1163,9 @@ void Reflection::SwapFieldsImpl(
// may depend on the information in has bits. // may depend on the information in has bits.
if (!field->is_repeated()) { if (!field->is_repeated()) {
SwapBit(message1, message2, field); SwapBit(message1, message2, field);
if (field->options().ctype() == FieldOptions::STRING && if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
field->cpp_string_type() ==
FieldDescriptor::CppStringType::kString &&
IsInlined(field)) { IsInlined(field)) {
ABSL_DCHECK(!unsafe_shallow_swap || ABSL_DCHECK(!unsafe_shallow_swap ||
message1->GetArena() == message2->GetArena()); message1->GetArena() == message2->GetArena());
@ -1259,9 +1274,10 @@ void Reflection::InternalSwap(Message* lhs, Message* rhs) const {
int inlined_string_count = 0; int inlined_string_count = 0;
for (int i = 0; i < descriptor_->field_count(); i++) { for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i); const FieldDescriptor* field = descriptor_->field(i);
if (field->cpp_type() != FieldDescriptor::CPPTYPE_STRING) continue;
if (field->is_extension() || field->is_repeated() || if (field->is_extension() || field->is_repeated() ||
schema_.InRealOneof(field) || schema_.InRealOneof(field) ||
field->options().ctype() != FieldOptions::STRING || field->cpp_string_type() != FieldDescriptor::CppStringType::kString ||
!IsInlined(field)) { !IsInlined(field)) {
continue; continue;
} }
@ -1309,6 +1325,10 @@ int Reflection::FieldSize(const Message& message,
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
return GetRaw<RepeatedField<absl::Cord> >(message, field).size();
}
ABSL_FALLTHROUGH_INTENDED;
case FieldDescriptor::CPPTYPE_MESSAGE: case FieldDescriptor::CPPTYPE_MESSAGE:
if (IsMapFieldInApi(field)) { if (IsMapFieldInApi(field)) {
const internal::MapFieldBase& map = const internal::MapFieldBase& map =
@ -1367,8 +1387,8 @@ void Reflection::ClearField(Message* message,
break; break;
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (field->has_default_value()) { if (field->has_default_value()) {
*MutableRaw<absl::Cord>(message, field) = *MutableRaw<absl::Cord>(message, field) =
field->default_value_string(); field->default_value_string();
@ -1376,8 +1396,8 @@ void Reflection::ClearField(Message* message,
MutableRaw<absl::Cord>(message, field)->Clear(); MutableRaw<absl::Cord>(message, field)->Clear();
} }
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
// Currently, string with default value can't be inlined. So we // Currently, string with default value can't be inlined. So we
// don't have to handle default value here. // don't have to handle default value here.
@ -1424,9 +1444,12 @@ void Reflection::ClearField(Message* message,
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: MutableRaw<RepeatedField<absl::Cord>>(message, field)->Clear();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
MutableRaw<RepeatedPtrField<std::string> >(message, field)->Clear(); MutableRaw<RepeatedPtrField<std::string> >(message, field)->Clear();
break; break;
} }
@ -1474,9 +1497,12 @@ void Reflection::RemoveLast(Message* message,
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: MutableRaw<RepeatedField<absl::Cord>>(message, field)->RemoveLast();
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
MutableRaw<RepeatedPtrField<std::string> >(message, field) MutableRaw<RepeatedPtrField<std::string> >(message, field)
->RemoveLast(); ->RemoveLast();
break; break;
@ -1568,6 +1594,12 @@ void Reflection::SwapElements(Message* message, const FieldDescriptor* field,
#undef HANDLE_TYPE #undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
MutableRaw<RepeatedField<absl::Cord> >(message, field)
->SwapElements(index1, index2);
break;
}
ABSL_FALLTHROUGH_INTENDED;
case FieldDescriptor::CPPTYPE_MESSAGE: case FieldDescriptor::CPPTYPE_MESSAGE:
if (IsMapFieldInApi(field)) { if (IsMapFieldInApi(field)) {
MutableRaw<MapFieldBase>(message, field) MutableRaw<MapFieldBase>(message, field)
@ -1774,15 +1806,15 @@ std::string Reflection::GetString(const Message& message,
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return field->default_value_string(); return field->default_value_string();
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
return std::string(*GetField<absl::Cord*>(message, field)); return std::string(*GetField<absl::Cord*>(message, field));
} else { } else {
return std::string(GetField<absl::Cord>(message, field)); return std::string(GetField<absl::Cord>(message, field));
} }
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
return GetField<InlinedStringField>(message, field).GetNoArena(); return GetField<InlinedStringField>(message, field).GetNoArena();
} else { } else {
@ -1790,6 +1822,7 @@ std::string Reflection::GetString(const Message& message,
return str.IsDefault() ? field->default_value_string() : str.Get(); return str.IsDefault() ? field->default_value_string() : str.Get();
} }
} }
internal::Unreachable();
} }
} }
@ -1805,8 +1838,8 @@ const std::string& Reflection::GetStringReference(const Message& message,
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return field->default_value_string(); return field->default_value_string();
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
absl::CopyCordToString(*GetField<absl::Cord*>(message, field), absl::CopyCordToString(*GetField<absl::Cord*>(message, field),
scratch); scratch);
@ -1814,8 +1847,8 @@ const std::string& Reflection::GetStringReference(const Message& message,
absl::CopyCordToString(GetField<absl::Cord>(message, field), scratch); absl::CopyCordToString(GetField<absl::Cord>(message, field), scratch);
} }
return *scratch; return *scratch;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
return GetField<InlinedStringField>(message, field).GetNoArena(); return GetField<InlinedStringField>(message, field).GetNoArena();
} else { } else {
@ -1823,6 +1856,7 @@ const std::string& Reflection::GetStringReference(const Message& message,
return str.IsDefault() ? field->default_value_string() : str.Get(); return str.IsDefault() ? field->default_value_string() : str.Get();
} }
} }
internal::Unreachable();
} }
} }
@ -1836,15 +1870,15 @@ absl::Cord Reflection::GetCord(const Message& message,
if (schema_.InRealOneof(field) && !HasOneofField(message, field)) { if (schema_.InRealOneof(field) && !HasOneofField(message, field)) {
return absl::Cord(field->default_value_string()); return absl::Cord(field->default_value_string());
} }
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
return *GetField<absl::Cord*>(message, field); return *GetField<absl::Cord*>(message, field);
} else { } else {
return GetField<absl::Cord>(message, field); return GetField<absl::Cord>(message, field);
} }
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (IsInlined(field)) { if (IsInlined(field)) {
return absl::Cord( return absl::Cord(
GetField<InlinedStringField>(message, field).GetNoArena()); GetField<InlinedStringField>(message, field).GetNoArena());
@ -1854,9 +1888,7 @@ absl::Cord Reflection::GetCord(const Message& message,
: str.Get()); : str.Get());
} }
} }
internal::Unreachable();
ABSL_LOG(FATAL) << "Can't get here.";
return absl::Cord(); // Make compiler happy.
} }
} }
@ -1868,8 +1900,8 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
return MutableExtensionSet(message)->SetString( return MutableExtensionSet(message)->SetString(
field->number(), field->type(), std::move(value), field); field->number(), field->type(), std::move(value), field);
} else { } else {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
if (!HasOneofField(*message, field)) { if (!HasOneofField(*message, field)) {
ClearOneof(message, field->containing_oneof()); ClearOneof(message, field->containing_oneof());
@ -1881,8 +1913,8 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
} }
*MutableField<absl::Cord>(message, field) = value; *MutableField<absl::Cord>(message, field) = value;
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
if (IsInlined(field)) { if (IsInlined(field)) {
const uint32_t index = schema_.InlinedStringIndex(field); const uint32_t index = schema_.InlinedStringIndex(field);
ABSL_DCHECK_GT(index, 0); ABSL_DCHECK_GT(index, 0);
@ -1920,8 +1952,8 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
MutableExtensionSet(message)->MutableString( MutableExtensionSet(message)->MutableString(
field->number(), field->type(), field)); field->number(), field->type(), field));
} else { } else {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
if (schema_.InRealOneof(field)) { if (schema_.InRealOneof(field)) {
if (!HasOneofField(*message, field)) { if (!HasOneofField(*message, field)) {
ClearOneof(message, field->containing_oneof()); ClearOneof(message, field->containing_oneof());
@ -1933,8 +1965,8 @@ void Reflection::SetString(Message* message, const FieldDescriptor* field,
*MutableField<absl::Cord>(message, field) = value; *MutableField<absl::Cord>(message, field) = value;
} }
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
// Oneof string fields are never set as a default instance. // Oneof string fields are never set as a default instance.
// We just need to pass some arbitrary default string to make it work. // We just need to pass some arbitrary default string to make it work.
// This allows us to not have the real default accessible from // This allows us to not have the real default accessible from
@ -1970,11 +2002,14 @@ std::string Reflection::GetRepeatedString(const Message& message,
if (field->is_extension()) { if (field->is_extension()) {
return GetExtensionSet(message).GetRepeatedString(field->number(), index); return GetExtensionSet(message).GetRepeatedString(field->number(), index);
} else { } else {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: return std::string(GetRepeatedField<absl::Cord>(message, field, index));
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return GetRepeatedPtrField<std::string>(message, field, index); return GetRepeatedPtrField<std::string>(message, field, index);
} }
internal::Unreachable();
} }
} }
@ -1986,11 +2021,16 @@ const std::string& Reflection::GetRepeatedStringReference(
if (field->is_extension()) { if (field->is_extension()) {
return GetExtensionSet(message).GetRepeatedString(field->number(), index); return GetExtensionSet(message).GetRepeatedString(field->number(), index);
} else { } else {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: absl::CopyCordToString(
GetRepeatedField<absl::Cord>(message, field, index), scratch);
return *scratch;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return GetRepeatedPtrField<std::string>(message, field, index); return GetRepeatedPtrField<std::string>(message, field, index);
} }
internal::Unreachable();
} }
} }
@ -2003,9 +2043,12 @@ void Reflection::SetRepeatedString(Message* message,
MutableExtensionSet(message)->SetRepeatedString(field->number(), index, MutableExtensionSet(message)->SetRepeatedString(field->number(), index,
std::move(value)); std::move(value));
} else { } else {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: SetRepeatedField<absl::Cord>(message, field, index, absl::Cord(value));
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
MutableRepeatedField<std::string>(message, field, index) MutableRepeatedField<std::string>(message, field, index)
->assign(std::move(value)); ->assign(std::move(value));
break; break;
@ -2021,9 +2064,12 @@ void Reflection::AddString(Message* message, const FieldDescriptor* field,
MutableExtensionSet(message)->AddString(field->number(), field->type(), MutableExtensionSet(message)->AddString(field->number(), field->type(),
std::move(value), field); std::move(value), field);
} else { } else {
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: // TODO: Support other string reps. case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: AddField<absl::Cord>(message, field, absl::Cord(value));
break;
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
AddField<std::string>(message, field)->assign(std::move(value)); AddField<std::string>(message, field)->assign(std::move(value));
break; break;
} }
@ -2688,9 +2734,9 @@ static Type* AllocIfDefault(const FieldDescriptor* field, Type*& ptr,
// be e.g. char). // be e.g. char).
if (field->cpp_type() < FieldDescriptor::CPPTYPE_STRING || if (field->cpp_type() < FieldDescriptor::CPPTYPE_STRING ||
(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD)) { field->cpp_string_type() == FieldDescriptor::CppStringType::kCord)) {
ptr = reinterpret_cast<Type*>( ptr =
Arena::CreateMessage<RepeatedField<int32_t>>(arena)); reinterpret_cast<Type*>(Arena::Create<RepeatedField<int32_t>>(arena));
} else { } else {
ptr = reinterpret_cast<Type*>( ptr = reinterpret_cast<Type*>(
Arena::CreateMessage<RepeatedPtrFieldBase>(arena)); Arena::CreateMessage<RepeatedPtrFieldBase>(arena));
@ -2864,11 +2910,11 @@ bool Reflection::HasBit(const Message& message,
// (which uses HasField()) needs to be consistent with this. // (which uses HasField()) needs to be consistent with this.
switch (field->cpp_type()) { switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
return !GetField<const absl::Cord>(message, field).empty(); return !GetField<const absl::Cord>(message, field).empty();
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
if (IsInlined(field)) { if (IsInlined(field)) {
return !GetField<InlinedStringField>(message, field) return !GetField<InlinedStringField>(message, field)
.GetNoArena() .GetNoArena()
@ -2878,7 +2924,7 @@ bool Reflection::HasBit(const Message& message,
return GetField<ArenaStringPtr>(message, field).Get().size() > 0; return GetField<ArenaStringPtr>(message, field).Get().size() > 0;
} }
} }
return false; internal::Unreachable();
case FieldDescriptor::CPPTYPE_BOOL: case FieldDescriptor::CPPTYPE_BOOL:
return GetRaw<bool>(message, field) != false; return GetRaw<bool>(message, field) != false;
case FieldDescriptor::CPPTYPE_INT32: case FieldDescriptor::CPPTYPE_INT32:
@ -2979,12 +3025,12 @@ void Reflection::ClearOneof(Message* message,
if (message->GetArena() == nullptr) { if (message->GetArena() == nullptr) {
switch (field->cpp_type()) { switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING: { case FieldDescriptor::CPPTYPE_STRING: {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
delete *MutableRaw<absl::Cord*>(message, field); delete *MutableRaw<absl::Cord*>(message, field);
break; break;
default: case FieldDescriptor::CppStringType::kView:
case FieldOptions::STRING: { case FieldDescriptor::CppStringType::kString: {
// Oneof string fields are never set as a default instance. // Oneof string fields are never set as a default instance.
// We just need to pass some arbitrary default string to make it // We just need to pass some arbitrary default string to make it
// work. This allows us to not have the real default accessible // work. This allows us to not have the real default accessible

@ -112,10 +112,10 @@ TailCallTableInfo::FastFieldInfo::Field MakeFastFieldEntry(
: field->is_repeated() ? PROTOBUF_PICK_FUNCTION(fn##R) \ : field->is_repeated() ? PROTOBUF_PICK_FUNCTION(fn##R) \
: PROTOBUF_PICK_FUNCTION(fn##S)) : PROTOBUF_PICK_FUNCTION(fn##S))
#define PROTOBUF_PICK_STRING_FUNCTION(fn) \ #define PROTOBUF_PICK_STRING_FUNCTION(fn) \
(field->options().ctype() == FieldOptions::CORD \ (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord \
? PROTOBUF_PICK_FUNCTION(fn##cS) \ ? PROTOBUF_PICK_FUNCTION(fn##cS) \
: options.is_string_inlined ? PROTOBUF_PICK_FUNCTION(fn##iS) \ : options.is_string_inlined ? PROTOBUF_PICK_FUNCTION(fn##iS) \
: PROTOBUF_PICK_REPEATABLE_FUNCTION(fn)) : PROTOBUF_PICK_REPEATABLE_FUNCTION(fn))
const FieldDescriptor* field = entry.field; const FieldDescriptor* field = entry.field;
@ -248,10 +248,12 @@ bool IsFieldEligibleForFastParsing(
switch (field->type()) { switch (field->type()) {
// Some bytes fields can be handled on fast path. // Some bytes fields can be handled on fast path.
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES: case FieldDescriptor::TYPE_BYTES: {
if (field->options().ctype() == FieldOptions::STRING) { auto ctype = field->cpp_string_type();
if (ctype == FieldDescriptor::CppStringType::kString ||
ctype == FieldDescriptor::CppStringType::kView) {
// strings are fine... // strings are fine...
} else if (field->options().ctype() == FieldOptions::CORD) { } else if (ctype == FieldDescriptor::CppStringType::kCord) {
// Cords are worth putting into the fast table, if they're not repeated // Cords are worth putting into the fast table, if they're not repeated
if (field->is_repeated()) return false; if (field->is_repeated()) return false;
} else { } else {
@ -265,6 +267,7 @@ bool IsFieldEligibleForFastParsing(
aux_idx = entry.inlined_string_idx; aux_idx = entry.inlined_string_idx;
} }
break; break;
}
case FieldDescriptor::TYPE_ENUM: { case FieldDescriptor::TYPE_ENUM: {
uint8_t rmax_value; uint8_t rmax_value;
@ -696,12 +699,12 @@ uint16_t MakeTypeCardForField(
// Fill in extra information about string and bytes field representations. // Fill in extra information about string and bytes field representations.
if (field->type() == FieldDescriptor::TYPE_BYTES || if (field->type() == FieldDescriptor::TYPE_BYTES ||
field->type() == FieldDescriptor::TYPE_STRING) { field->type() == FieldDescriptor::TYPE_STRING) {
switch (internal::cpp::EffectiveStringCType(field)) { switch (field->cpp_string_type()) {
case FieldOptions::CORD: case FieldDescriptor::CppStringType::kCord:
// `Cord` is always used, even for repeated fields. // `Cord` is always used, even for repeated fields.
type_card |= fl::kRepCord; type_card |= fl::kRepCord;
break; break;
case FieldOptions::STRING: case FieldDescriptor::CppStringType::kString:
if (field->is_repeated()) { if (field->is_repeated()) {
// A repeated string field uses RepeatedPtrField<std::string> // A repeated string field uses RepeatedPtrField<std::string>
// (unless it has a ctype option; see above). // (unless it has a ctype option; see above).
@ -711,8 +714,8 @@ uint16_t MakeTypeCardForField(
type_card |= fl::kRepAString; type_card |= fl::kRepAString;
} }
break; break;
default: case FieldDescriptor::CppStringType::kView:
PROTOBUF_ASSUME(false); break;
} }
} }

@ -1664,6 +1664,12 @@ bool TcParser::ChangeOneof(const TcParseTableBase* table,
field.Destroy(); field.Destroy();
break; break;
} }
case field_layout::kRepCord: {
if (msg->GetArena() == nullptr) {
delete RefAt<absl::Cord*>(msg, current_entry->offset);
}
break;
}
case field_layout::kRepSString: case field_layout::kRepSString:
case field_layout::kRepIString: case field_layout::kRepIString:
default: default:

@ -172,13 +172,12 @@ cc_test(
"zero_copy_stream_unittest.cc", "zero_copy_stream_unittest.cc",
], ],
copts = COPTS, copts = COPTS,
data = [
"//src/google/protobuf:testdata",
],
deps = [ deps = [
":gzip_stream", ":gzip_stream",
":io", ":io",
"//:protobuf", "//:protobuf",
"//src/google/protobuf",
"//src/google/protobuf:test_util",
"//src/google/protobuf:test_util2", "//src/google/protobuf:test_util2",
"//src/google/protobuf/testing", "//src/google/protobuf/testing",
"@com_google_absl//absl/container:flat_hash_map", "@com_google_absl//absl/container:flat_hash_map",

@ -57,12 +57,14 @@
#include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/io_win32.h" #include "google/protobuf/io/io_win32.h"
#include "google/protobuf/io/zero_copy_stream_impl.h" #include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/test_util.h"
#include "google/protobuf/test_util2.h" #include "google/protobuf/test_util2.h"
#if HAVE_ZLIB #if HAVE_ZLIB
#include "google/protobuf/io/gzip_stream.h" #include "google/protobuf/io/gzip_stream.h"
#endif #endif
#include "google/protobuf/test_util.h"
// Must be included last. // Must be included last.
#include "google/protobuf/port_def.inc" #include "google/protobuf/port_def.inc"
@ -558,10 +560,9 @@ std::string IoTest::Uncompress(const std::string& data) {
TEST_F(IoTest, CompressionOptions) { TEST_F(IoTest, CompressionOptions) {
// Some ad-hoc testing of compression options. // Some ad-hoc testing of compression options.
std::string golden_filename = protobuf_unittest::TestAllTypes message;
TestUtil::GetTestDataPath("google/protobuf/testdata/golden_message"); TestUtil::SetAllFields(&message);
std::string golden; std::string golden = message.SerializeAsString();
ABSL_CHECK_OK(File::GetContents(golden_filename, &golden, true));
GzipOutputStream::Options options; GzipOutputStream::Options options;
std::string gzip_compressed = Compress(golden, options); std::string gzip_compressed = Compress(golden, options);

@ -250,7 +250,7 @@ TEST_P(JsonTest, TestDefaultValues) {
R"("defaultSfixed64":"-50","defaultFloat":51.5,"defaultDouble":52000,"defaultBool":true,)" R"("defaultSfixed64":"-50","defaultFloat":51.5,"defaultDouble":52000,"defaultBool":true,)"
R"("defaultString":"hello","defaultBytes":"d29ybGQ=","defaultNestedEnum":"BAR",)" R"("defaultString":"hello","defaultBytes":"d29ybGQ=","defaultNestedEnum":"BAR",)"
R"("defaultForeignEnum":"FOREIGN_BAR","defaultImportEnum":"IMPORT_BAR",)" R"("defaultForeignEnum":"FOREIGN_BAR","defaultImportEnum":"IMPORT_BAR",)"
R"("defaultStringPiece":"abc","defaultCord":"123"})")); R"("defaultStringPiece":"abc","defaultCord":"123","optionalBytesCord":""})")) << *ToJson(protobuf_unittest::TestAllTypes(), options);
EXPECT_THAT( EXPECT_THAT(
ToJson(protobuf_unittest::TestExtremeDefaultValues(), options), ToJson(protobuf_unittest::TestExtremeDefaultValues(), options),

@ -956,6 +956,18 @@ TYPED_TEST(LiteTest, AllLite43) {
EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream)); EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
EXPECT_EQ(17, message2.oneof_int32()); EXPECT_EQ(17, message2.oneof_int32());
} }
// Bytes [ctype = CORD]
{
protobuf_unittest::TestOneofParsingLite message2;
message2.set_oneof_bytes_cord("bytes cord");
io::CodedInputStream input_stream(
reinterpret_cast<const ::uint8_t*>(serialized.data()),
serialized.size());
EXPECT_TRUE(message2.MergeFromCodedStream(&input_stream));
EXPECT_EQ(17, message2.oneof_int32());
}
} }
// Verify that we can successfully parse fields of various types within oneof // Verify that we can successfully parse fields of various types within oneof
@ -1042,6 +1054,18 @@ TYPED_TEST(LiteTest, AllLite44) {
} }
} }
// Bytes [ctype = CORD]
{
protobuf_unittest::TestOneofParsingLite original;
original.set_oneof_bytes_cord("bytes cord");
std::string serialized;
EXPECT_TRUE(original.SerializeToString(&serialized));
protobuf_unittest::TestOneofParsingLite parsed;
EXPECT_TRUE(parsed.MergeFromString(serialized));
EXPECT_EQ("bytes cord", std::string(parsed.oneof_bytes_cord()));
EXPECT_TRUE(parsed.MergeFromString(serialized));
}
std::cout << "PASS" << std::endl; std::cout << "PASS" << std::endl;
} }

@ -3895,16 +3895,35 @@ TEST(MapSerializationTest, Deterministic) {
EXPECT_TRUE(util::MessageDifferencer::Equals(u, t)); EXPECT_TRUE(util::MessageDifferencer::Equals(u, t));
} }
static std::string GetGoldenMessageTextProto() {
static std::string* golden_message_textproto = [] {
std::string* textproto = new std::string;
ABSL_CHECK_OK(File::GetContents(
TestUtil::GetTestDataPath("google/protobuf/"
"testdata/map_test_data.txt"),
textproto, true));
return textproto;
}();
return *golden_message_textproto;
}
static std::string GetGoldenMessageBinary() {
static std::string* golden_message_binary = [] {
UNITTEST::TestMaps t;
TextFormat::Parser parser;
parser.ParseFromString(GetGoldenMessageTextProto(), &t);
std::string* result = new std::string;
t.SerializeToString(result);
return result;
}();
return *golden_message_binary;
}
TEST(MapSerializationTest, DeterministicSubmessage) { TEST(MapSerializationTest, DeterministicSubmessage) {
UNITTEST::TestSubmessageMaps p; UNITTEST::TestSubmessageMaps p;
UNITTEST::TestMaps t; UNITTEST::TestMaps t;
const std::string filename = "golden_message_maps"; t.ParseFromString(GetGoldenMessageBinary());
std::string golden;
ABSL_CHECK_OK(
File::GetContents(TestUtil::GetTestDataPath(absl::StrCat(
"google/protobuf/testdata/", filename)),
&golden, true));
t.ParseFromString(golden);
*(p.mutable_m()) = t; *(p.mutable_m()) = t;
std::vector<std::string> v; std::vector<std::string> v;
// Use multiple attempts to increase the chance of a failure if something is // Use multiple attempts to increase the chance of a failure if something is
@ -3942,15 +3961,9 @@ TEST(TextFormatMapTest, DynamicMessage) {
MapReflectionTester tester(message->GetDescriptor()); MapReflectionTester tester(message->GetDescriptor());
tester.SetMapFieldsViaReflection(message.get()); tester.SetMapFieldsViaReflection(message.get());
std::string expected_text;
ABSL_CHECK_OK(
File::GetContents(TestUtil::GetTestDataPath("google/protobuf/"
"testdata/map_test_data.txt"),
&expected_text, true));
std::string actual_text; std::string actual_text;
TextFormat::PrintToString(*message, &actual_text); TextFormat::PrintToString(*message, &actual_text);
EXPECT_EQ(actual_text, expected_text); EXPECT_EQ(actual_text, GetGoldenMessageTextProto());
} }
TEST(TextFormatMapTest, Sorted) { TEST(TextFormatMapTest, Sorted) {
@ -3958,35 +3971,17 @@ TEST(TextFormatMapTest, Sorted) {
MapReflectionTester tester(message.GetDescriptor()); MapReflectionTester tester(message.GetDescriptor());
tester.SetMapFieldsViaReflection(&message); tester.SetMapFieldsViaReflection(&message);
std::string expected_text;
ABSL_CHECK_OK(
File::GetContents(TestUtil::GetTestDataPath("google/protobuf/"
"testdata/map_test_data.txt"),
&expected_text, true));
TextFormat::Printer printer; TextFormat::Printer printer;
std::string actual_text; std::string actual_text;
printer.PrintToString(message, &actual_text); printer.PrintToString(message, &actual_text);
EXPECT_EQ(actual_text, expected_text); EXPECT_EQ(actual_text, GetGoldenMessageTextProto());
// Test again on the reverse order. // Test again on the reverse order.
UNITTEST::TestMap message2; UNITTEST::TestMap message2;
tester.SetMapFieldsViaReflection(&message2); tester.SetMapFieldsViaReflection(&message2);
tester.SwapMapsViaReflection(&message2); tester.SwapMapsViaReflection(&message2);
printer.PrintToString(message2, &actual_text); printer.PrintToString(message2, &actual_text);
EXPECT_EQ(actual_text, expected_text); EXPECT_EQ(actual_text, GetGoldenMessageTextProto());
}
TEST(TextFormatMapTest, ParseCorruptedString) {
std::string serialized_message;
ABSL_CHECK_OK(File::GetContents(
TestUtil::GetTestDataPath(
"google/protobuf/testdata/golden_message_maps"),
&serialized_message, true));
UNITTEST::TestMaps message;
ABSL_CHECK(message.ParseFromString(serialized_message));
TestParseCorruptedString<UNITTEST::TestMaps, true>(message);
TestParseCorruptedString<UNITTEST::TestMaps, false>(message);
} }
// Previously, serializing to text format will disable iterator from generated // Previously, serializing to text format will disable iterator from generated

@ -378,9 +378,11 @@ const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
HANDLE_PRIMITIVE_TYPE(ENUM, int32_t) HANDLE_PRIMITIVE_TYPE(ENUM, int32_t)
#undef HANDLE_PRIMITIVE_TYPE #undef HANDLE_PRIMITIVE_TYPE
case FieldDescriptor::CPPTYPE_STRING: case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) { switch (field->cpp_string_type()) {
default: case FieldDescriptor::CppStringType::kCord:
case FieldOptions::STRING: ABSL_LOG(FATAL) << "Repeated cords are not supported.";
case FieldDescriptor::CppStringType::kView:
case FieldDescriptor::CppStringType::kString:
return GetSingleton<internal::RepeatedPtrFieldStringAccessor>(); return GetSingleton<internal::RepeatedPtrFieldStringAccessor>();
} }
break; break;

@ -28,6 +28,8 @@
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include "google/protobuf/testing/file.h"
#include "google/protobuf/testing/file.h"
#include "google/protobuf/descriptor.pb.h" #include "google/protobuf/descriptor.pb.h"
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include "google/protobuf/testing/googletest.h" #include "google/protobuf/testing/googletest.h"
@ -110,8 +112,12 @@ TEST(MESSAGE_TEST_NAME, SerializeToBrokenOstream) {
} }
TEST(MESSAGE_TEST_NAME, ParseFromFileDescriptor) { TEST(MESSAGE_TEST_NAME, ParseFromFileDescriptor) {
std::string filename = std::string filename = absl::StrCat(TestTempDir(), "/golden_message");
TestUtil::GetTestDataPath("google/protobuf/testdata/golden_message"); UNITTEST::TestAllTypes expected_message;
TestUtil::SetAllFields(&expected_message);
ABSL_CHECK_OK(File::SetContents(
filename, expected_message.SerializeAsString(), true));
int file = open(filename.c_str(), O_RDONLY | O_BINARY); int file = open(filename.c_str(), O_RDONLY | O_BINARY);
ASSERT_GE(file, 0); ASSERT_GE(file, 0);
@ -123,8 +129,12 @@ TEST(MESSAGE_TEST_NAME, ParseFromFileDescriptor) {
} }
TEST(MESSAGE_TEST_NAME, ParsePackedFromFileDescriptor) { TEST(MESSAGE_TEST_NAME, ParsePackedFromFileDescriptor) {
std::string filename = TestUtil::GetTestDataPath( std::string filename = absl::StrCat(TestTempDir(), "/golden_message");
"google/protobuf/testdata/golden_packed_fields_message"); UNITTEST::TestPackedTypes expected_message;
TestUtil::SetPackedFields(&expected_message);
ABSL_CHECK_OK(File::SetContents(
filename, expected_message.SerializeAsString(), true));
int file = open(filename.c_str(), O_RDONLY | O_BINARY); int file = open(filename.c_str(), O_RDONLY | O_BINARY);
ASSERT_GE(file, 0); ASSERT_GE(file, 0);

@ -22,6 +22,7 @@
#include <typeinfo> #include <typeinfo>
#include "absl/base/config.h"
#include "absl/meta/type_traits.h" #include "absl/meta/type_traits.h"
#include "absl/strings/string_view.h" #include "absl/strings/string_view.h"
#include "absl/types/optional.h" #include "absl/types/optional.h"
@ -201,6 +202,22 @@ inline constexpr bool DebugHardenStringValues() {
#endif #endif
} }
#if defined(NDEBUG) && ABSL_HAVE_BUILTIN(__builtin_unreachable)
[[noreturn]] ABSL_ATTRIBUTE_COLD PROTOBUF_ALWAYS_INLINE inline void
Unreachable() {
__builtin_unreachable();
}
#elif ABSL_HAVE_BUILTIN(__builtin_FILE) && ABSL_HAVE_BUILTIN(__builtin_LINE)
[[noreturn]] ABSL_ATTRIBUTE_COLD inline void Unreachable(
const char* file = __builtin_FILE(), int line = __builtin_LINE()) {
protobuf_assumption_failed("Unreachable", file, line);
}
#else
[[noreturn]] ABSL_ATTRIBUTE_COLD inline void Unreachable() {
protobuf_assumption_failed("Unreachable", "", 0);
}
#endif
} // namespace internal } // namespace internal
} // namespace protobuf } // namespace protobuf
} // namespace google } // namespace google

@ -1133,8 +1133,9 @@ static_assert(PROTOBUF_ABSL_MIN(20230125, 3),
namespace google { namespace google {
namespace protobuf { namespace protobuf {
namespace internal { namespace internal {
PROTOBUF_EXPORT void protobuf_assumption_failed(const char *pred, [[noreturn]] PROTOBUF_EXPORT void protobuf_assumption_failed(const char *pred,
const char *file, int line); const char *file,
int line);
} // namespace internal } // namespace internal
} // namespace protobuf } // namespace protobuf
} // namespace google } // namespace google

@ -5,10 +5,13 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // https://developers.google.com/open-source/licenses/bsd
// //
#include "google/protobuf/port.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "absl/base/config.h"
// Must be included last // Must be included last
#include "google/protobuf/port_def.inc" #include "google/protobuf/port_def.inc"
@ -28,6 +31,21 @@ TEST(PortTest, ProtobufAssume) {
#endif #endif
} }
TEST(PortTest, UnreachableTrapsOnDebugMode) {
#ifdef GTEST_HAS_DEATH_TEST
#if defined(NDEBUG)
// In NDEBUG we crash with a UD instruction, so we don't get the "Assumption
// failed" error.
GTEST_SKIP() << "Can't test __builtin_unreachable()";
#elif ABSL_HAVE_BUILTIN(__builtin_FILE)
EXPECT_DEATH(Unreachable(),
"port_test\\.cc:.*Assumption failed: 'Unreachable'");
#else
EXPECT_DEATH(Unreachable(), "Assumption failed: 'Unreachable'");
#endif
#endif
}
} // namespace internal } // namespace internal
} // namespace protobuf } // namespace protobuf
} // namespace google } // namespace google

@ -223,6 +223,8 @@ inline void TestUtil::ReflectionTester::SetAllFieldsViaReflection(
reflection->SetString(message, F("optional_string_piece"), "124"); reflection->SetString(message, F("optional_string_piece"), "124");
reflection->SetString(message, F("optional_cord"), "125"); reflection->SetString(message, F("optional_cord"), "125");
reflection->SetString(message, F("optional_bytes_cord"),
"optional bytes cord");
sub_message = sub_message =
reflection->MutableMessage(message, F("optional_public_import_message")); reflection->MutableMessage(message, F("optional_public_import_message"));
@ -491,6 +493,7 @@ inline void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_TRUE(reflection->HasField(message, F("optional_string_piece"))); EXPECT_TRUE(reflection->HasField(message, F("optional_string_piece")));
EXPECT_TRUE(reflection->HasField(message, F("optional_cord"))); EXPECT_TRUE(reflection->HasField(message, F("optional_cord")));
EXPECT_TRUE(reflection->HasField(message, F("optional_bytes_cord")));
EXPECT_EQ(101, reflection->GetInt32(message, F("optional_int32"))); EXPECT_EQ(101, reflection->GetInt32(message, F("optional_int32")));
EXPECT_EQ(102, reflection->GetInt64(message, F("optional_int64"))); EXPECT_EQ(102, reflection->GetInt64(message, F("optional_int64")));
@ -552,6 +555,14 @@ inline void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection1(
EXPECT_EQ("125", reflection->GetStringReference(message, F("optional_cord"), EXPECT_EQ("125", reflection->GetStringReference(message, F("optional_cord"),
&scratch)); &scratch));
EXPECT_EQ("optional bytes cord",
reflection->GetString(message, F("optional_bytes_cord")));
EXPECT_EQ("optional bytes cord",
reflection->GetStringReference(message, F("optional_bytes_cord"),
&scratch));
EXPECT_EQ("optional bytes cord",
reflection->GetCord(message, F("optional_bytes_cord")));
EXPECT_TRUE(reflection->HasField(message, F("oneof_bytes"))); EXPECT_TRUE(reflection->HasField(message, F("oneof_bytes")));
EXPECT_EQ("604", reflection->GetString(message, F("oneof_bytes"))); EXPECT_EQ("604", reflection->GetString(message, F("oneof_bytes")));
@ -912,6 +923,7 @@ inline void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_FALSE(reflection->HasField(message, F("optional_string_piece"))); EXPECT_FALSE(reflection->HasField(message, F("optional_string_piece")));
EXPECT_FALSE(reflection->HasField(message, F("optional_cord"))); EXPECT_FALSE(reflection->HasField(message, F("optional_cord")));
EXPECT_FALSE(reflection->HasField(message, F("optional_bytes_cord")));
// Optional fields without defaults are set to zero or something like it. // Optional fields without defaults are set to zero or something like it.
EXPECT_EQ(0, reflection->GetInt32(message, F("optional_int32"))); EXPECT_EQ(0, reflection->GetInt32(message, F("optional_int32")));
@ -978,6 +990,11 @@ inline void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_EQ("", reflection->GetStringReference(message, F("optional_cord"), EXPECT_EQ("", reflection->GetStringReference(message, F("optional_cord"),
&scratch)); &scratch));
EXPECT_EQ("", reflection->GetString(message, F("optional_bytes_cord")));
EXPECT_EQ("", reflection->GetStringReference(
message, F("optional_bytes_cord"), &scratch));
EXPECT_EQ("", reflection->GetCord(message, F("optional_bytes_cord")));
// Repeated fields are empty. // Repeated fields are empty.
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int32"))); EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int32")));
EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int64"))); EXPECT_EQ(0, reflection->FieldSize(message, F("repeated_int64")));

@ -137,6 +137,7 @@ inline void TestUtil::SetOptionalFields(UNITTEST::TestAllTypes* message) {
message, message->GetDescriptor()->FindFieldByName("optional_cord"), message, message->GetDescriptor()->FindFieldByName("optional_cord"),
"125"); "125");
#endif // !PROTOBUF_TEST_NO_DESCRIPTORS #endif // !PROTOBUF_TEST_NO_DESCRIPTORS
message->set_optional_bytes_cord("optional bytes cord");
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -352,6 +353,7 @@ inline void TestUtil::ExpectAllFieldsSet(
EXPECT_TRUE(message.has_optional_string_piece()); EXPECT_TRUE(message.has_optional_string_piece());
EXPECT_TRUE(message.has_optional_cord()); EXPECT_TRUE(message.has_optional_cord());
#endif #endif
EXPECT_TRUE(message.has_optional_bytes_cord());
EXPECT_EQ(101, message.optional_int32()); EXPECT_EQ(101, message.optional_int32());
EXPECT_EQ(102, message.optional_int64()); EXPECT_EQ(102, message.optional_int64());
@ -381,6 +383,7 @@ inline void TestUtil::ExpectAllFieldsSet(
EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.optional_foreign_enum()); EXPECT_EQ(UNITTEST::FOREIGN_BAZ, message.optional_foreign_enum());
EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ, message.optional_import_enum()); EXPECT_EQ(UNITTEST_IMPORT::IMPORT_BAZ, message.optional_import_enum());
EXPECT_EQ("optional bytes cord", message.optional_bytes_cord());
// ----------------------------------------------------------------- // -----------------------------------------------------------------
@ -554,6 +557,7 @@ inline void TestUtil::ExpectClear(const UNITTEST::TestAllTypes& message) {
EXPECT_FALSE(message.has_optional_string_piece()); EXPECT_FALSE(message.has_optional_string_piece());
EXPECT_FALSE(message.has_optional_cord()); EXPECT_FALSE(message.has_optional_cord());
EXPECT_FALSE(message.has_optional_bytes_cord());
// Optional fields without defaults are set to zero or something like it. // Optional fields without defaults are set to zero or something like it.
EXPECT_EQ(0, message.optional_int32()); EXPECT_EQ(0, message.optional_int32());
@ -594,6 +598,7 @@ inline void TestUtil::ExpectClear(const UNITTEST::TestAllTypes& message) {
EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.optional_foreign_enum()); EXPECT_EQ(UNITTEST::FOREIGN_FOO, message.optional_foreign_enum());
EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO, message.optional_import_enum()); EXPECT_EQ(UNITTEST_IMPORT::IMPORT_FOO, message.optional_import_enum());
EXPECT_EQ("", message.optional_bytes_cord());
// Repeated fields are empty. // Repeated fields are empty.
EXPECT_EQ(0, message.repeated_int32_size()); EXPECT_EQ(0, message.repeated_int32_size());
@ -975,6 +980,8 @@ inline void TestUtil::SetAllExtensions(UNITTEST::TestAllExtensions* message) {
message->SetExtension(UNITTEST::optional_string_piece_extension, "124"); message->SetExtension(UNITTEST::optional_string_piece_extension, "124");
message->SetExtension(UNITTEST::optional_cord_extension, "125"); message->SetExtension(UNITTEST::optional_cord_extension, "125");
message->SetExtension(UNITTEST::optional_bytes_cord_extension,
"optional bytes cord");
message->MutableExtension(UNITTEST::optional_public_import_message_extension) message->MutableExtension(UNITTEST::optional_public_import_message_extension)
->set_e(126); ->set_e(126);
@ -1204,6 +1211,7 @@ inline void TestUtil::ExpectAllExtensionsSet(
EXPECT_TRUE(message.HasExtension(UNITTEST::optional_string_piece_extension)); EXPECT_TRUE(message.HasExtension(UNITTEST::optional_string_piece_extension));
EXPECT_TRUE(message.HasExtension(UNITTEST::optional_cord_extension)); EXPECT_TRUE(message.HasExtension(UNITTEST::optional_cord_extension));
EXPECT_TRUE(message.HasExtension(UNITTEST::optional_bytes_cord_extension));
EXPECT_EQ(101, message.GetExtension(UNITTEST::optional_int32_extension)); EXPECT_EQ(101, message.GetExtension(UNITTEST::optional_int32_extension));
EXPECT_EQ(102, message.GetExtension(UNITTEST::optional_int64_extension)); EXPECT_EQ(102, message.GetExtension(UNITTEST::optional_int64_extension));
@ -1242,6 +1250,8 @@ inline void TestUtil::ExpectAllExtensionsSet(
EXPECT_EQ("124", EXPECT_EQ("124",
message.GetExtension(UNITTEST::optional_string_piece_extension)); message.GetExtension(UNITTEST::optional_string_piece_extension));
EXPECT_EQ("125", message.GetExtension(UNITTEST::optional_cord_extension)); EXPECT_EQ("125", message.GetExtension(UNITTEST::optional_cord_extension));
EXPECT_EQ("optional bytes cord",
message.GetExtension(UNITTEST::optional_bytes_cord_extension));
EXPECT_EQ( EXPECT_EQ(
126, 126,
message.GetExtension(UNITTEST::optional_public_import_message_extension) message.GetExtension(UNITTEST::optional_public_import_message_extension)
@ -1490,6 +1500,7 @@ inline void TestUtil::ExpectExtensionsClear(
EXPECT_FALSE(message.HasExtension(UNITTEST::optional_string_piece_extension)); EXPECT_FALSE(message.HasExtension(UNITTEST::optional_string_piece_extension));
EXPECT_FALSE(message.HasExtension(UNITTEST::optional_cord_extension)); EXPECT_FALSE(message.HasExtension(UNITTEST::optional_cord_extension));
EXPECT_FALSE(message.HasExtension(UNITTEST::optional_bytes_cord_extension));
// Optional fields without defaults are set to zero or something like it. // Optional fields without defaults are set to zero or something like it.
EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_int32_extension)); EXPECT_EQ(0, message.GetExtension(UNITTEST::optional_int32_extension));
@ -1557,6 +1568,7 @@ inline void TestUtil::ExpectExtensionsClear(
EXPECT_EQ("", EXPECT_EQ("",
message.GetExtension(UNITTEST::optional_string_piece_extension)); message.GetExtension(UNITTEST::optional_string_piece_extension));
EXPECT_EQ("", message.GetExtension(UNITTEST::optional_cord_extension)); EXPECT_EQ("", message.GetExtension(UNITTEST::optional_cord_extension));
EXPECT_EQ("", message.GetExtension(UNITTEST::optional_bytes_cord_extension));
// Repeated fields are empty. // Repeated fields are empty.
EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_int32_extension)); EXPECT_EQ(0, message.ExtensionSize(UNITTEST::repeated_int32_extension));

Binary file not shown.

@ -126,6 +126,7 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO default_import_enum: IMPORT_FOO
default_string_piece: "424" default_string_piece: "424"
default_cord: "425" default_cord: "425"
optional_bytes_cord: "optional bytes cord"
oneof_uint32: 601 oneof_uint32: 601
oneof_nested_message { oneof_nested_message {
bb: 602 bb: 602

@ -129,4 +129,5 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO default_import_enum: IMPORT_FOO
default_string_piece: "424" default_string_piece: "424"
default_cord: "425" default_cord: "425"
optional_bytes_cord: "optional bytes cord"
oneof_bytes: "604" oneof_bytes: "604"

@ -129,6 +129,7 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO default_import_enum: IMPORT_FOO
default_string_piece: "424" default_string_piece: "424"
default_cord: "425" default_cord: "425"
optional_bytes_cord: "optional bytes cord"
oneof_uint32: 601 oneof_uint32: 601
oneof_nested_message < oneof_nested_message <
bb: 602 bb: 602

@ -129,4 +129,5 @@ default_foreign_enum: FOREIGN_FOO
default_import_enum: IMPORT_FOO default_import_enum: IMPORT_FOO
default_string_piece: "424" default_string_piece: "424"
default_cord: "425" default_cord: "425"
optional_bytes_cord: "optional bytes cord"
oneof_bytes: "604" oneof_bytes: "604"

@ -129,6 +129,7 @@
[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO [protobuf_unittest.default_import_enum_extension]: IMPORT_FOO
[protobuf_unittest.default_string_piece_extension]: "424" [protobuf_unittest.default_string_piece_extension]: "424"
[protobuf_unittest.default_cord_extension]: "425" [protobuf_unittest.default_cord_extension]: "425"
[protobuf_unittest.optional_bytes_cord_extension]: "optional bytes cord"
[protobuf_unittest.oneof_uint32_extension]: 601 [protobuf_unittest.oneof_uint32_extension]: 601
[protobuf_unittest.oneof_nested_message_extension] { [protobuf_unittest.oneof_nested_message_extension] {
bb: 602 bb: 602

@ -129,6 +129,7 @@
[protobuf_unittest.default_import_enum_extension]: IMPORT_FOO [protobuf_unittest.default_import_enum_extension]: IMPORT_FOO
[protobuf_unittest.default_string_piece_extension]: "424" [protobuf_unittest.default_string_piece_extension]: "424"
[protobuf_unittest.default_cord_extension]: "425" [protobuf_unittest.default_cord_extension]: "425"
[protobuf_unittest.optional_bytes_cord_extension]: "optional bytes cord"
[protobuf_unittest.oneof_uint32_extension]: 601 [protobuf_unittest.oneof_uint32_extension]: 601
[protobuf_unittest.oneof_nested_message_extension] < [protobuf_unittest.oneof_nested_message_extension] <
bb: 602 bb: 602

@ -84,6 +84,7 @@ message TestAllTypes {
optional string optional_string_piece = 24 [ctype=STRING_PIECE]; optional string optional_string_piece = 24 [ctype=STRING_PIECE];
optional string optional_cord = 25 [ctype=CORD]; optional string optional_cord = 25 [ctype=CORD];
optional bytes optional_bytes_cord = 86 [ctype=CORD];
// Defined in unittest_import_public.proto // Defined in unittest_import_public.proto
optional protobuf_unittest_import.PublicImportMessage optional protobuf_unittest_import.PublicImportMessage
@ -251,6 +252,7 @@ extend TestAllExtensions {
// TODO: ctype=CORD is not supported for extension. Add // TODO: ctype=CORD is not supported for extension. Add
// ctype=CORD option back after it is supported. // ctype=CORD option back after it is supported.
optional string optional_cord_extension = 25; optional string optional_cord_extension = 25;
optional bytes optional_bytes_cord_extension = 86;
optional protobuf_unittest_import.PublicImportMessage optional protobuf_unittest_import.PublicImportMessage
optional_public_import_message_extension = 26; optional_public_import_message_extension = 26;

@ -69,6 +69,7 @@ message TestAllTypesLite {
optional string optional_string_piece = 24 [ctype = STRING_PIECE]; optional string optional_string_piece = 24 [ctype = STRING_PIECE];
optional string optional_cord = 25 [ctype = CORD]; optional string optional_cord = 25 [ctype = CORD];
optional bytes optional_bytes_cord = 86 [ctype = CORD];
// Defined in unittest_import_public.proto // Defined in unittest_import_public.proto
optional protobuf_unittest_import.PublicImportMessageLite optional protobuf_unittest_import.PublicImportMessageLite
@ -223,7 +224,7 @@ extend TestAllExtensionsLite {
// TODO: ctype=CORD is not supported for extension. Add // TODO: ctype=CORD is not supported for extension. Add
// ctype=CORD option back after it is supported. // ctype=CORD option back after it is supported.
optional string optional_cord_extension_lite = 25; optional string optional_cord_extension_lite = 25;
optional bytes optional_bytes_cord_extension_lite = 86;
optional protobuf_unittest_import.PublicImportMessageLite optional protobuf_unittest_import.PublicImportMessageLite
optional_public_import_message_extension_lite = 26; optional_public_import_message_extension_lite = 26;

@ -67,6 +67,7 @@ message TestAllTypes {
string optional_string_piece = 24 [ctype=STRING_PIECE]; string optional_string_piece = 24 [ctype=STRING_PIECE];
string optional_cord = 25 [ctype=CORD]; string optional_cord = 25 [ctype=CORD];
bytes optional_bytes_cord = 86 [ctype=CORD];
// Defined in unittest_import_public.proto // Defined in unittest_import_public.proto
protobuf_unittest_import.PublicImportMessage protobuf_unittest_import.PublicImportMessage

@ -202,7 +202,7 @@ TEST(FieldMaskUtilTest, TestGetFieldMaskForAllFields) {
EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("bb", mask));
mask = FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>(); mask = FieldMaskUtil::GetFieldMaskForAllFields<TestAllTypes>();
EXPECT_EQ(79, mask.paths_size()); EXPECT_EQ(80, mask.paths_size());
EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int32", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int32", mask));
EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int64", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_int64", mask));
EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint32", mask)); EXPECT_TRUE(FieldMaskUtil::IsPathInFieldMask("optional_uint32", mask));

@ -560,7 +560,7 @@ bool WireFormat::ParseAndMergeField(
} }
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
if (internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
absl::Cord value; absl::Cord value;
if (!WireFormatLite::ReadBytes(input, &value)) return false; if (!WireFormatLite::ReadBytes(input, &value)) return false;
message_reflection->SetString(message, field, value); message_reflection->SetString(message, field, value);
@ -964,7 +964,7 @@ const char* WireFormat::_InternalParseAndMergeField(
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
int size = ReadSize(&ptr); int size = ReadSize(&ptr);
if (ptr == nullptr) return nullptr; if (ptr == nullptr) return nullptr;
if (internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
absl::Cord value; absl::Cord value;
ptr = ctx->ReadCord(ptr, size, &value); ptr = ctx->ReadCord(ptr, size, &value);
if (ptr == nullptr) return nullptr; if (ptr == nullptr) return nullptr;
@ -1423,7 +1423,7 @@ uint8_t* WireFormat::InternalSerializeField(const FieldDescriptor* field,
} }
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
if (internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
absl::Cord value = message_reflection->GetCord(message, field); absl::Cord value = message_reflection->GetCord(message, field);
target = stream->WriteString(field->number(), value, target); target = stream->WriteString(field->number(), value, target);
break; break;
@ -1724,7 +1724,7 @@ size_t WireFormat::FieldDataOnlyByteSize(const FieldDescriptor* field,
// instead of copying. // instead of copying.
case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES: { case FieldDescriptor::TYPE_BYTES: {
if (internal::cpp::EffectiveStringCType(field) == FieldOptions::CORD) { if (field->cpp_string_type() == FieldDescriptor::CppStringType::kCord) {
for (size_t j = 0; j < count; j++) { for (size_t j = 0; j < count; j++) {
absl::Cord value = message_reflection->GetCord(message, field); absl::Cord value = message_reflection->GetCord(message, field);
data_size += WireFormatLite::StringSize(value); data_size += WireFormatLite::StringSize(value);

Loading…
Cancel
Save