diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a8f9ba70cf96..ea004a6b6496e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,7 +86,7 @@ if (protobuf_BUILD_SHARED_LIBS) endif () # Version metadata -set(protobuf_VERSION_STRING "6.31.0") +set(protobuf_VERSION_STRING "6.31.1") set(protobuf_DESCRIPTION "Protocol Buffers") set(protobuf_CONTACT "protobuf@googlegroups.com") diff --git a/MODULE.bazel b/MODULE.bazel index 44fcddd9e3d77..b1e4a5440a5f3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -3,7 +3,7 @@ module( name = "protobuf", - version = "31.0", # Automatically updated on release + version = "31.1", # Automatically updated on release compatibility_level = 1, repo_name = "com_google_protobuf", ) diff --git a/Protobuf.podspec b/Protobuf.podspec index b19cecccbc987..55c973c739644 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '4.31.0' + s.version = '4.31.1' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/protocolbuffers/protobuf' s.license = 'BSD-3-Clause' diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index b79d65f8d5607..2ea6254af3806 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Codestin Search App Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.31.0 + 3.31.1 Google Inc. protobuf-packages https://github.com/protocolbuffers/protobuf/blob/main/LICENSE diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index c654139f3aaac..1bf9812f67fc6 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -5,7 +5,7 @@ C# runtime library for Protocol Buffers - Google's data interchange format. Copyright 2015, Google Inc. Google Protocol Buffers - 3.31.0 + 3.31.1 10.0 Google Inc. netstandard1.1;netstandard2.0;net45;net50 diff --git a/editions/generated_files_test.cc b/editions/generated_files_test.cc index debe06424c4fa..cf9ff80f1a50a 100644 --- a/editions/generated_files_test.cc +++ b/editions/generated_files_test.cc @@ -12,6 +12,7 @@ #include "editions/golden/test_messages_proto2_editions.pb.h" #include "editions/golden/test_messages_proto3_editions.pb.h" #include "editions/proto/test_editions_default_features.pb.h" +#include "google/protobuf/internal_feature_helper.h" #include "google/protobuf/test_textproto.h" // These tests provide some basic minimal coverage that protos work as expected. diff --git a/java/bom/pom.xml b/java/bom/pom.xml index de1e2aed5cda3..ca5fe44af1f19 100644 --- a/java/bom/pom.xml +++ b/java/bom/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-bom - 4.31.0 + 4.31.1 pom Protocol Buffers [BOM] diff --git a/java/core/src/main/java/com/google/protobuf/RuntimeVersion.java b/java/core/src/main/java/com/google/protobuf/RuntimeVersion.java index 14d1d0764a61c..9695f847cd4ff 100644 --- a/java/core/src/main/java/com/google/protobuf/RuntimeVersion.java +++ b/java/core/src/main/java/com/google/protobuf/RuntimeVersion.java @@ -28,7 +28,7 @@ public enum RuntimeDomain { public static final RuntimeDomain OSS_DOMAIN = RuntimeDomain.PUBLIC; public static final int OSS_MAJOR = 4; public static final int OSS_MINOR = 31; - public static final int OSS_PATCH = 0; + public static final int OSS_PATCH = 1; public static final String OSS_SUFFIX = ""; public static final RuntimeDomain DOMAIN = OSS_DOMAIN; diff --git a/java/kotlin/pom.xml b/java/kotlin/pom.xml index 471a07a5ea968..82dd453578378 100644 --- a/java/kotlin/pom.xml +++ b/java/kotlin/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 4.31.0 + 4.31.1 protobuf-kotlin diff --git a/java/pom.xml b/java/pom.xml index b03a684578dd7..53f198297383c 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -4,7 +4,7 @@ com.google.protobuf protobuf-parent - 4.31.0 + 4.31.1 pom Protocol Buffers [Parent] diff --git a/java/protoc/pom.xml b/java/protoc/pom.xml index 9544a18d3301e..d645e928c9c28 100644 --- a/java/protoc/pom.xml +++ b/java/protoc/pom.xml @@ -8,7 +8,7 @@ com.google.protobuf protoc - 4.31.0 + 4.31.1 pom Protobuf Compiler diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h index d52d31a705e3f..e8eb30388b02c 100644 --- a/php/ext/google/protobuf/protobuf.h +++ b/php/ext/google/protobuf/protobuf.h @@ -32,7 +32,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_setter, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() -#define PHP_PROTOBUF_VERSION "4.31.0" +#define PHP_PROTOBUF_VERSION "4.31.1" // ptr -> PHP object cache. This is a weak map that caches lazily-created // wrapper objects around upb types: diff --git a/protobuf_version.bzl b/protobuf_version.bzl index 1b62969998183..68bad21034830 100644 --- a/protobuf_version.bzl +++ b/protobuf_version.bzl @@ -1,7 +1,7 @@ """ Contains version numbers to be used in other bzl files """ -PROTOC_VERSION = "31.0" -PROTOBUF_JAVA_VERSION = "4.31.0" -PROTOBUF_PYTHON_VERSION = "6.31.0" -PROTOBUF_PHP_VERSION = "4.31.0" -PROTOBUF_RUBY_VERSION = "4.31.0" -PROTOBUF_RUST_VERSION = "4.31.0" +PROTOC_VERSION = "31.1" +PROTOBUF_JAVA_VERSION = "4.31.1" +PROTOBUF_PYTHON_VERSION = "6.31.1" +PROTOBUF_PHP_VERSION = "4.31.1" +PROTOBUF_RUBY_VERSION = "4.31.1" +PROTOBUF_RUST_VERSION = "4.31.1" diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index 38a0c6dbd50a0..d41e5bf38500b 100755 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -7,4 +7,4 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '6.31.0' +__version__ = '6.31.1' diff --git a/python/google/protobuf/internal/decoder.py b/python/google/protobuf/internal/decoder.py index e2a3de17089ab..dbf848bf31083 100755 --- a/python/google/protobuf/internal/decoder.py +++ b/python/google/protobuf/internal/decoder.py @@ -703,7 +703,13 @@ def DecodeRepeatedField( if value is None: value = field_dict.setdefault(key, new_default(message)) # Read sub-message. + current_depth += 1 + if current_depth > _recursion_limit: + raise _DecodeError( + 'Error parsing message: too many levels of nesting.' + ) pos = value.add()._InternalParse(buffer, pos, end, current_depth) + current_depth -= 1 # Read end tag. new_pos = pos+end_tag_len if buffer[pos:new_pos] != end_tag_bytes or new_pos > end: @@ -722,7 +728,11 @@ def DecodeField(buffer, pos, end, message, field_dict, current_depth=0): if value is None: value = field_dict.setdefault(key, new_default(message)) # Read sub-message. + current_depth += 1 + if current_depth > _recursion_limit: + raise _DecodeError('Error parsing message: too many levels of nesting.') pos = value._InternalParse(buffer, pos, end, current_depth) + current_depth -= 1 # Read end tag. new_pos = pos+end_tag_len if buffer[pos:new_pos] != end_tag_bytes or new_pos > end: @@ -755,6 +765,11 @@ def DecodeRepeatedField( if new_pos > end: raise _DecodeError('Truncated message.') # Read sub-message. + current_depth += 1 + if current_depth > _recursion_limit: + raise _DecodeError( + 'Error parsing message: too many levels of nesting.' + ) if ( value.add()._InternalParse(buffer, pos, new_pos, current_depth) != new_pos @@ -762,6 +777,7 @@ def DecodeRepeatedField( # The only reason _InternalParse would return early is if it # encountered an end-group tag. raise _DecodeError('Unexpected end-group tag.') + current_depth -= 1 # Predict that the next tag is another copy of the same repeated field. pos = new_pos + tag_len if buffer[new_pos:pos] != tag_bytes or new_pos == end: @@ -781,10 +797,14 @@ def DecodeField(buffer, pos, end, message, field_dict, current_depth=0): if new_pos > end: raise _DecodeError('Truncated message.') # Read sub-message. + current_depth += 1 + if current_depth > _recursion_limit: + raise _DecodeError('Error parsing message: too many levels of nesting.') if value._InternalParse(buffer, pos, new_pos, current_depth) != new_pos: # The only reason _InternalParse would return early is if it encountered # an end-group tag. raise _DecodeError('Unexpected end-group tag.') + current_depth -= 1 return new_pos return DecodeField @@ -980,6 +1000,13 @@ def _DecodeFixed32(buffer, pos): new_pos = pos + 4 return (struct.unpack('= _recursion_limit: + raise _DecodeError('Error parsing message: too many levels of nesting.') data, pos = _DecodeUnknownFieldSet(buffer, pos, end_pos, current_depth) + current_depth -= 1 # Check end tag. if buffer[pos - len(end_tag_bytes) : pos] != end_tag_bytes: raise _DecodeError('Missing group end tag.') diff --git a/python/google/protobuf/internal/decoder_test.py b/python/google/protobuf/internal/decoder_test.py index aa683ad140966..d2bc81b46171b 100644 --- a/python/google/protobuf/internal/decoder_test.py +++ b/python/google/protobuf/internal/decoder_test.py @@ -84,6 +84,19 @@ def test_decode_unknown_group_field_nested(self): self.assertEqual(parsed[0].data[0].data[0].field_number, 3) self.assertEqual(parsed[0].data[0].data[0].data, 4) + def test_decode_unknown_group_field_too_many_levels(self): + data = memoryview(b'\023' * 5_000_000) + self.assertRaisesRegex( + message.DecodeError, + 'Error parsing message', + decoder._DecodeUnknownField, + data, + 1, + len(data), + 1, + wire_format.WIRETYPE_START_GROUP, + ) + def test_decode_unknown_mismatched_end_group(self): self.assertRaisesRegex( message.DecodeError, diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index 1441a49b8584d..ea0c707009a14 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -36,6 +36,7 @@ from google.protobuf.internal import more_extensions_pb2 from google.protobuf.internal import more_messages_pb2 from google.protobuf.internal import packed_field_test_pb2 +from google.protobuf.internal import self_recursive_pb2 from google.protobuf.internal import test_proto3_optional_pb2 from google.protobuf.internal import test_util from google.protobuf.internal import testing_refleaks @@ -1431,6 +1432,52 @@ def testMessageClassName(self, message_module): ) +@testing_refleaks.TestCase +class TestRecursiveGroup(unittest.TestCase): + + def _MakeRecursiveGroupMessage(self, n): + msg = self_recursive_pb2.SelfRecursive() + sub = msg + for _ in range(n): + sub = sub.sub_group + sub.i = 1 + return msg.SerializeToString() + + def testRecursiveGroups(self): + recurse_msg = self_recursive_pb2.SelfRecursive() + data = self._MakeRecursiveGroupMessage(100) + recurse_msg.ParseFromString(data) + self.assertTrue(recurse_msg.HasField('sub_group')) + + def testRecursiveGroupsException(self): + if api_implementation.Type() != 'python': + api_implementation._c_module.SetAllowOversizeProtos(False) + recurse_msg = self_recursive_pb2.SelfRecursive() + data = self._MakeRecursiveGroupMessage(300) + with self.assertRaises(message.DecodeError) as context: + recurse_msg.ParseFromString(data) + self.assertIn('Error parsing message', str(context.exception)) + if api_implementation.Type() == 'python': + self.assertIn('too many levels of nesting', str(context.exception)) + + def testRecursiveGroupsUnknownFields(self): + if api_implementation.Type() != 'python': + api_implementation._c_module.SetAllowOversizeProtos(False) + test_msg = unittest_pb2.TestAllTypes() + data = self._MakeRecursiveGroupMessage(300) # unknown to test_msg + with self.assertRaises(message.DecodeError) as context: + test_msg.ParseFromString(data) + self.assertIn( + 'Error parsing message', + str(context.exception), + ) + if api_implementation.Type() == 'python': + self.assertIn('too many levels of nesting', str(context.exception)) + decoder.SetRecursionLimit(310) + test_msg.ParseFromString(data) + decoder.SetRecursionLimit(decoder.DEFAULT_RECURSION_LIMIT) + + # Class to test proto2-only features (required, extensions, etc.) @testing_refleaks.TestCase class Proto2Test(unittest.TestCase): @@ -2859,8 +2906,6 @@ def testUnpackedFields(self): self.assertEqual(golden_data, message.SerializeToString()) -@unittest.skipIf(api_implementation.Type() == 'python', - 'explicit tests of the C++ implementation') @testing_refleaks.TestCase class OversizeProtosTest(unittest.TestCase): @@ -2877,16 +2922,23 @@ def testSucceedOkSizedProto(self): msg.ParseFromString(self.GenerateNestedProto(100)) def testAssertOversizeProto(self): - api_implementation._c_module.SetAllowOversizeProtos(False) + if api_implementation.Type() != 'python': + api_implementation._c_module.SetAllowOversizeProtos(False) msg = unittest_pb2.TestRecursiveMessage() with self.assertRaises(message.DecodeError) as context: msg.ParseFromString(self.GenerateNestedProto(101)) self.assertIn('Error parsing message', str(context.exception)) def testSucceedOversizeProto(self): - api_implementation._c_module.SetAllowOversizeProtos(True) + + if api_implementation.Type() == 'python': + decoder.SetRecursionLimit(310) + else: + api_implementation._c_module.SetAllowOversizeProtos(True) + msg = unittest_pb2.TestRecursiveMessage() msg.ParseFromString(self.GenerateNestedProto(101)) + decoder.SetRecursionLimit(decoder.DEFAULT_RECURSION_LIMIT) if __name__ == '__main__': diff --git a/python/google/protobuf/internal/self_recursive.proto b/python/google/protobuf/internal/self_recursive.proto index 20bc2b4d3eb80..d2a7f004bf947 100644 --- a/python/google/protobuf/internal/self_recursive.proto +++ b/python/google/protobuf/internal/self_recursive.proto @@ -12,6 +12,7 @@ package google.protobuf.python.internal; message SelfRecursive { SelfRecursive sub = 1; int32 i = 2; + SelfRecursive sub_group = 3 [features.message_encoding = DELIMITED]; } message IndirectRecursive { diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc index 94a1121e30264..a714ca00edc05 100644 --- a/python/google/protobuf/pyext/descriptor.cc +++ b/python/google/protobuf/pyext/descriptor.cc @@ -23,6 +23,7 @@ #include "absl/strings/string_view.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/dynamic_message.h" +#include "google/protobuf/internal_feature_helper.h" #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/pyext/descriptor_containers.h" #include "google/protobuf/pyext/descriptor_pool.h" diff --git a/python/google/protobuf/runtime_version.py b/python/google/protobuf/runtime_version.py index 5b923f3baa109..7d69773d99e90 100644 --- a/python/google/protobuf/runtime_version.py +++ b/python/google/protobuf/runtime_version.py @@ -29,7 +29,7 @@ class Domain(Enum): OSS_DOMAIN = Domain.PUBLIC OSS_MAJOR = 6 OSS_MINOR = 31 -OSS_PATCH = 0 +OSS_PATCH = 1 OSS_SUFFIX = '' DOMAIN = OSS_DOMAIN diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index d2b91fc11f53c..7a3021017adde 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "4.31.0" + s.version = "4.31.1" git_tag = "v#{s.version.to_s.sub('.rc.', '-rc')}" # Converts X.Y.Z.rc.N to vX.Y.Z-rcN, used for the git tag s.licenses = ["BSD-3-Clause"] s.summary = "Protocol Buffers" diff --git a/ruby/pom.xml b/ruby/pom.xml index b620e6a9c89d0..3f592641f9aa1 100644 --- a/ruby/pom.xml +++ b/ruby/pom.xml @@ -9,7 +9,7 @@ com.google.protobuf.jruby protobuf-jruby - 4.31.0 + 4.31.1 Protocol Buffer JRuby native extension Protocol Buffers are a way of encoding structured data in an efficient yet @@ -76,7 +76,7 @@ com.google.protobuf protobuf-java-util - 4.31.0 + 4.31.1 org.jruby diff --git a/src/file_lists.cmake b/src/file_lists.cmake index c6c6fcf20cd51..e798ad90330bb 100644 --- a/src/file_lists.cmake +++ b/src/file_lists.cmake @@ -46,6 +46,7 @@ set(libprotobuf_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_feature_helper.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32.cc @@ -137,6 +138,7 @@ set(libprotobuf_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/has_bits.h ${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.h ${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_feature_helper.h ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_visibility.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.h @@ -851,6 +853,7 @@ set(protoc-gen-upb_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_feature_helper.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32.cc @@ -930,6 +933,7 @@ set(protoc-gen-upb_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/has_bits.h ${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.h ${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_feature_helper.h ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_visibility.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.h @@ -1020,6 +1024,7 @@ set(protoc-gen-upbdefs_srcs ${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_util.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_feature_helper.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/io/io_win32.cc @@ -1100,6 +1105,7 @@ set(protoc-gen-upbdefs_hdrs ${protobuf_SOURCE_DIR}/src/google/protobuf/has_bits.h ${protobuf_SOURCE_DIR}/src/google/protobuf/implicit_weak_message.h ${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field.h + ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_feature_helper.h ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_visibility.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/coded_stream.h ${protobuf_SOURCE_DIR}/src/google/protobuf/io/gzip_stream.h @@ -1419,6 +1425,7 @@ set(protobuf_test_files ${protobuf_SOURCE_DIR}/src/google/protobuf/generated_message_tctable_lite_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/has_bits_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/inlined_string_field_unittest.cc + ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_feature_helper_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/internal_message_util_unittest.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map_field_test.cc ${protobuf_SOURCE_DIR}/src/google/protobuf/map_test.cc diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel index a5a47147fe691..6273bebd6c7a6 100644 --- a/src/google/protobuf/BUILD.bazel +++ b/src/google/protobuf/BUILD.bazel @@ -718,6 +718,7 @@ PROTOBUF_HEADERS = [ "descriptor_visitor.h", "dynamic_message.h", "feature_resolver.h", + "internal_feature_helper.h", "field_access_listener.h", "generated_enum_reflection.h", "generated_message_bases.h", @@ -754,6 +755,7 @@ cc_library( "generated_message_reflection.cc", "generated_message_tctable_full.cc", "generated_message_tctable_gen.cc", + "internal_feature_helper.cc", "map_field.cc", "message.cc", "reflection_mode.cc", @@ -1704,6 +1706,37 @@ cc_test( ], ) +cc_test( + name = "internal_feature_helper_test", + srcs = [ + "internal_feature_helper_test.cc", + ], + copts = COPTS, + deps = [ + ":cc_test_protos", + ":port", + ":protobuf", + ":protobuf_lite", + ":test_textproto", + ":test_util", + "//src/google/protobuf/compiler:importer", + "//src/google/protobuf/io", + "//src/google/protobuf/io:tokenizer", + "//src/google/protobuf/testing", + "//src/google/protobuf/testing:file", + "@abseil-cpp//absl/log:absl_check", + "@abseil-cpp//absl/log:absl_log", + "@abseil-cpp//absl/log:die_if_null", + "@abseil-cpp//absl/memory", + "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:statusor", + "@abseil-cpp//absl/strings", + "@abseil-cpp//absl/strings:str_format", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + cc_test( name = "generated_message_reflection_unittest", srcs = ["generated_message_reflection_unittest.cc"], diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc index b0d9a5f1d2fe6..d5ffa04a12c74 100644 --- a/src/google/protobuf/any.pb.cc +++ b/src/google/protobuf/any.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/any.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/any.pb.h" diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index cda85dd611510..4110bf7b2f45f 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/any.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fany_2eproto_2epb_2eh #define google_2fprotobuf_2fany_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc index c3f2957c95a45..38f45571d6f79 100644 --- a/src/google/protobuf/api.pb.cc +++ b/src/google/protobuf/api.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/api.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/api.pb.h" diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index 811678bf7cfc5..02a895e8234d8 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/api.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fapi_2eproto_2epb_2eh #define google_2fprotobuf_2fapi_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h index 683a4276eb76e..552dc3dcc28f0 100644 --- a/src/google/protobuf/compiler/code_generator.h +++ b/src/google/protobuf/compiler/code_generator.h @@ -25,6 +25,7 @@ #include "google/protobuf/compiler/code_generator_lite.h" // IWYU pragma: export #include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/internal_feature_helper.h" // Must be included last. #include "google/protobuf/port_def.inc" @@ -142,6 +143,20 @@ class PROTOC_EXPORT CodeGenerator { return ::google::protobuf::internal::InternalFeatureHelper::GetFeatures(desc); } + // Returns the resolved FeatureSet for the language extension. It is + // guaranteed that the result is fully aware of the language feature set + // defaults, either the defaults set to the descriptor pool, or, if not set, + // the defaults embedded in the language FeatureSet extension. + template + static auto GetResolvedSourceFeatureExtension( + const DescriptorT& desc, + const google::protobuf::internal::ExtensionIdentifier< + FeatureSet, TypeTraitsT, field_type, is_packed>& extension) { + return ::google::protobuf::internal::InternalFeatureHelper:: + GetResolvedFeatureExtension(desc, extension); + } + // Retrieves the unresolved source features for a given descriptor. These // should be used to validate the original .proto file. These represent the // original proto files from generated code, but should be stripped of diff --git a/src/google/protobuf/compiler/code_generator_unittest.cc b/src/google/protobuf/compiler/code_generator_unittest.cc index 6167498a17193..4e55f7b528968 100644 --- a/src/google/protobuf/compiler/code_generator_unittest.cc +++ b/src/google/protobuf/compiler/code_generator_unittest.cc @@ -67,6 +67,7 @@ class TestGenerator : public CodeGenerator { } // Expose the protected methods for testing. + using CodeGenerator::GetResolvedSourceFeatureExtension; using CodeGenerator::GetResolvedSourceFeatures; using CodeGenerator::GetUnresolvedSourceFeatures; @@ -246,6 +247,143 @@ TEST_F(CodeGeneratorTest, GetResolvedSourceFeaturesInherited) { EXPECT_EQ(ext.source_feature2(), pb::EnumFeature::VALUE3); } +TEST_F(CodeGeneratorTest, GetResolvedSourceFeatureExtension) { + TestGenerator generator; + generator.set_feature_extensions({GetExtensionReflection(pb::test)}); + ASSERT_OK(pool_.SetFeatureSetDefaults(*generator.BuildFeatureSetDefaults())); + + ASSERT_THAT(BuildFile(DescriptorProto::descriptor()->file()), NotNull()); + ASSERT_THAT(BuildFile(pb::TestMessage::descriptor()->file()), NotNull()); + auto file = BuildFile(R"schema( + edition = "2023"; + package proto2_unittest; + + import "google/protobuf/unittest_features.proto"; + + option features.(pb.test).file_feature = VALUE6; + option features.(pb.test).source_feature = VALUE5; + )schema"); + ASSERT_THAT(file, NotNull()); + const pb::TestFeatures& ext1 = + TestGenerator::GetResolvedSourceFeatureExtension(*file, pb::test); + const pb::TestFeatures& ext2 = + TestGenerator::GetResolvedSourceFeatures(*file).GetExtension(pb::test); + + // Since the pool provides the feature set defaults, there should be no + // difference between the two results. + EXPECT_EQ(ext1.enum_feature(), pb::EnumFeature::VALUE1); + EXPECT_EQ(ext1.field_feature(), pb::EnumFeature::VALUE1); + EXPECT_EQ(ext1.file_feature(), pb::EnumFeature::VALUE6); + EXPECT_EQ(ext1.source_feature(), pb::EnumFeature::VALUE5); + EXPECT_EQ(ext2.enum_feature(), ext1.enum_feature()); + EXPECT_EQ(ext2.field_feature(), ext1.field_feature()); + EXPECT_EQ(ext2.file_feature(), ext1.file_feature()); + EXPECT_EQ(ext2.source_feature(), ext1.source_feature()); +} + +TEST_F(CodeGeneratorTest, GetResolvedSourceFeatureExtensionEditedDefaults) { + FeatureSetDefaults defaults = ParseTextOrDie(R"pb( + minimum_edition: EDITION_PROTO2 + maximum_edition: EDITION_2024 + defaults { + edition: EDITION_LEGACY + overridable_features {} + fixed_features { + field_presence: EXPLICIT + enum_type: CLOSED + repeated_field_encoding: EXPANDED + utf8_validation: NONE + message_encoding: LENGTH_PREFIXED + json_format: LEGACY_BEST_EFFORT + enforce_naming_style: STYLE_LEGACY + default_symbol_visibility: EXPORT_ALL + } + } + defaults { + edition: EDITION_2023 + overridable_features { + field_presence: EXPLICIT + enum_type: OPEN + repeated_field_encoding: PACKED + utf8_validation: VERIFY + message_encoding: LENGTH_PREFIXED + json_format: ALLOW + [pb.test] { + file_feature: VALUE3 + field_feature: VALUE15 + enum_feature: VALUE14 + source_feature: VALUE1 + } + } + fixed_features { + enforce_naming_style: STYLE_LEGACY + default_symbol_visibility: EXPORT_ALL + } + } + )pb"); + ASSERT_OK(pool_.SetFeatureSetDefaults(defaults)); + + ASSERT_THAT(BuildFile(DescriptorProto::descriptor()->file()), NotNull()); + ASSERT_THAT(BuildFile(pb::TestMessage::descriptor()->file()), NotNull()); + auto file = BuildFile(R"schema( + edition = "2023"; + package proto2_unittest; + + import "google/protobuf/unittest_features.proto"; + + option features.(pb.test).file_feature = VALUE6; + option features.(pb.test).source_feature = VALUE5; + )schema"); + ASSERT_THAT(file, NotNull()); + const pb::TestFeatures& ext = + TestGenerator::GetResolvedSourceFeatureExtension(*file, pb::test); + + // Since the pool provides the modified feature set defaults, the result + // should be the one reflecting the pool's defaults. + EXPECT_EQ(ext.enum_feature(), pb::EnumFeature::VALUE14); + EXPECT_EQ(ext.field_feature(), pb::EnumFeature::VALUE15); + EXPECT_EQ(ext.file_feature(), pb::EnumFeature::VALUE6); + EXPECT_EQ(ext.source_feature(), pb::EnumFeature::VALUE5); +} + +TEST_F(CodeGeneratorTest, + GetResolvedSourceFeatureExtensionDefaultsFromFeatureSetExtension) { + // Make sure feature set defaults are empty in the pool. + TestGenerator generator; + generator.set_feature_extensions({}); + ASSERT_OK(pool_.SetFeatureSetDefaults(*generator.BuildFeatureSetDefaults())); + + ASSERT_THAT(BuildFile(DescriptorProto::descriptor()->file()), NotNull()); + ASSERT_THAT(BuildFile(pb::TestMessage::descriptor()->file()), NotNull()); + auto file = BuildFile(R"schema( + edition = "2023"; + package proto2_unittest; + + import "google/protobuf/unittest_features.proto"; + + option features.(pb.test).file_feature = VALUE6; + option features.(pb.test).source_feature = VALUE5; + )schema"); + ASSERT_THAT(file, NotNull()); + + const pb::TestFeatures& ext1 = + TestGenerator::GetResolvedSourceFeatureExtension(*file, pb::test); + const pb::TestFeatures& ext2 = + TestGenerator::GetResolvedSourceFeatures(*file).GetExtension(pb::test); + + // No defaults were added to the pool, but they should be still present in the + // result. On the other hand, features that are explicitly set should be also + // present. + EXPECT_EQ(ext1.enum_feature(), pb::EnumFeature::VALUE1); + EXPECT_EQ(ext1.field_feature(), pb::EnumFeature::VALUE1); + EXPECT_EQ(ext1.file_feature(), pb::EnumFeature::VALUE6); + EXPECT_EQ(ext1.source_feature(), pb::EnumFeature::VALUE5); + EXPECT_EQ(ext2.enum_feature(), pb::EnumFeature::TEST_ENUM_FEATURE_UNKNOWN); + EXPECT_EQ(ext2.field_feature(), pb::EnumFeature::TEST_ENUM_FEATURE_UNKNOWN); + EXPECT_EQ(ext2.file_feature(), pb::EnumFeature::VALUE6); + EXPECT_EQ(ext2.source_feature(), pb::EnumFeature::VALUE5); +} + // TODO: Use the gtest versions once that's available in OSS. MATCHER_P(HasError, msg_matcher, "") { return arg.status().code() == absl::StatusCode::kFailedPrecondition && diff --git a/src/google/protobuf/compiler/cpp/BUILD.bazel b/src/google/protobuf/compiler/cpp/BUILD.bazel index 81b2502de3c21..37a47de81ae2c 100644 --- a/src/google/protobuf/compiler/cpp/BUILD.bazel +++ b/src/google/protobuf/compiler/cpp/BUILD.bazel @@ -147,6 +147,7 @@ cc_library( "@abseil-cpp//absl/log:die_if_null", "@abseil-cpp//absl/memory", "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", "@abseil-cpp//absl/synchronization", diff --git a/src/google/protobuf/compiler/cpp/extension.cc b/src/google/protobuf/compiler/cpp/extension.cc index 3dd9410b8fabd..178548e44abd0 100644 --- a/src/google/protobuf/compiler/cpp/extension.cc +++ b/src/google/protobuf/compiler/cpp/extension.cc @@ -15,12 +15,17 @@ #include #include "absl/log/absl_check.h" +#include "absl/status/statusor.h" +#include "absl/strings/escaping.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_replace.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/feature_resolver.h" #include "google/protobuf/io/printer.h" namespace google { @@ -96,30 +101,67 @@ bool ExtensionGenerator::IsScoped() const { return descriptor_->extension_scope() != nullptr; } +namespace { +bool ShouldGenerateFeatureSetDefaultData(absl::string_view extension) { + return extension == "pb.java" || extension == "pb.test"; +} +} // namespace + void ExtensionGenerator::GenerateDeclaration(io::Printer* p) const { auto var = p->WithVars(variables_); auto annotate = p->WithAnnotations({{"name", descriptor_}}); - p->Emit({{"constant_qualifier", - // If this is a class member, it needs to be declared - // `static constexpr`. - // Otherwise, it will be - // `inline constexpr`. - IsScoped() ? "static" : ""}, - {"id_qualifier", - // If this is a class member, it needs to be declared "static". - // Otherwise, it needs to be "extern". In the latter case, it - // also needs the DLL export/import specifier. - IsScoped() ? "static" - : options_.dllexport_decl.empty() - ? "extern" - : absl::StrCat(options_.dllexport_decl, " extern")}}, - R"cc( - inline $constant_qualifier $constexpr int $constant_name$ = - $number$; - $id_qualifier$ $pbi$::ExtensionIdentifier< - $extendee$, $pbi$::$type_traits$, $field_type$, $packed$> - $name$; - )cc"); + p->Emit( + {{"constant_qualifier", + // If this is a class member, it needs to be declared + // `static constexpr`. + // Otherwise, it will be + // `inline constexpr`. + IsScoped() ? "static" : ""}, + {"id_qualifier", + // If this is a class member, it needs to be declared "static". + // Otherwise, it needs to be "extern". In the latter case, it + // also needs the DLL export/import specifier. + IsScoped() ? "static" + : options_.dllexport_decl.empty() + ? "extern" + : absl::StrCat(options_.dllexport_decl, " extern")}, + {"feature_set_defaults", + [&] { + if (!ShouldGenerateFeatureSetDefaultData(descriptor_->full_name())) { + return; + } + if (descriptor_->message_type() == nullptr) return; + absl::string_view extendee = + descriptor_->containing_type()->full_name(); + if (extendee != "google.protobuf.FeatureSet") return; + + std::vector extensions = {descriptor_}; + absl::StatusOr defaults = + FeatureResolver::CompileDefaults( + descriptor_->containing_type(), extensions, + ProtocMinimumEdition(), ProtocMaximumEdition()); + ABSL_CHECK_OK(defaults); + p->Emit( + {{"defaults", absl::Base64Escape(defaults->SerializeAsString())}, + {"extension_type", ClassName(descriptor_->message_type(), true)}, + {"function_name", "GetFeatureSetDefaultsData"}}, + R"cc( + namespace internal { + template <> + inline ::absl::string_view $function_name$<$extension_type$>() { + static constexpr char kDefaults[] = "$defaults$"; + return kDefaults; + } + } // namespace internal + )cc"); + }}}, + R"cc( + inline $constant_qualifier $constexpr int $constant_name$ = $number$; + $id_qualifier$ $pbi$::ExtensionIdentifier< + $extendee$, $pbi$::$type_traits$, $field_type$, $packed$> + $name$; + $feature_set_defaults$; + )cc"); } void ExtensionGenerator::GenerateDefinition(io::Printer* p) { diff --git a/src/google/protobuf/compiler/java/BUILD.bazel b/src/google/protobuf/compiler/java/BUILD.bazel index 458a9ef37b0a4..58c4ba48da543 100644 --- a/src/google/protobuf/compiler/java/BUILD.bazel +++ b/src/google/protobuf/compiler/java/BUILD.bazel @@ -85,6 +85,7 @@ cc_library( "generator.h", "internal_helpers.h", ], + copts = COPTS, strip_include_prefix = "/src", visibility = [ "//src/google/protobuf/compiler/java:__subpackages__", diff --git a/src/google/protobuf/compiler/java/generator.h b/src/google/protobuf/compiler/java/generator.h index 4abf7ce32228b..17202d47e916d 100644 --- a/src/google/protobuf/compiler/java/generator.h +++ b/src/google/protobuf/compiler/java/generator.h @@ -60,6 +60,7 @@ class PROTOC_EXPORT JavaGenerator : public CodeGenerator { } using CodeGenerator::GetEdition; + using CodeGenerator::GetResolvedSourceFeatureExtension; using CodeGenerator::GetResolvedSourceFeatures; using CodeGenerator::GetUnresolvedSourceFeatures; diff --git a/src/google/protobuf/compiler/java/helpers.cc b/src/google/protobuf/compiler/java/helpers.cc index 19b191a670ce2..448c2141344e0 100644 --- a/src/google/protobuf/compiler/java/helpers.cc +++ b/src/google/protobuf/compiler/java/helpers.cc @@ -929,15 +929,12 @@ namespace { // generated class should be nested in the generated proto file Java class. template inline bool NestInFileClass(const Descriptor& descriptor) { - auto nest_in_file_class = JavaGenerator::GetResolvedSourceFeatures(descriptor) - .GetExtension(pb::java) - .nest_in_file_class(); + auto nest_in_file_class = + JavaGenerator::GetResolvedSourceFeatureExtension(descriptor, pb::java) + .nest_in_file_class(); ABSL_CHECK( nest_in_file_class != - pb::JavaFeatures::NestInFileClassFeature::NEST_IN_FILE_CLASS_UNKNOWN) - << "Unknown value for nest_in_file_class feature. Try populating the " - "Java feature set defaults in your generator plugin or custom " - "descriptor pool."; + pb::JavaFeatures::NestInFileClassFeature::NEST_IN_FILE_CLASS_UNKNOWN); if (nest_in_file_class == pb::JavaFeatures::NestInFileClassFeature::LEGACY) { return !descriptor.file()->options().java_multiple_files(); diff --git a/src/google/protobuf/compiler/java/java_features.pb.cc b/src/google/protobuf/compiler/java/java_features.pb.cc index 9a72149b16080..e8155844e6cd1 100644 --- a/src/google/protobuf/compiler/java/java_features.pb.cc +++ b/src/google/protobuf/compiler/java/java_features.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/compiler/java/java_features.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/compiler/java/java_features.pb.h" diff --git a/src/google/protobuf/compiler/java/java_features.pb.h b/src/google/protobuf/compiler/java/java_features.pb.h index 72dbafd45e196..467af1ca62080 100644 --- a/src/google/protobuf/compiler/java/java_features.pb.h +++ b/src/google/protobuf/compiler/java/java_features.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/compiler/java/java_features.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fcompiler_2fjava_2fjava_5ffeatures_2eproto_2epb_2eh #define google_2fprotobuf_2fcompiler_2fjava_2fjava_5ffeatures_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" @@ -591,11 +591,17 @@ PROTOC_EXPORT extern const ::google::protobuf::internal::ClassDataFull JavaFeatu -inline constexpr int kJavaFieldNumber = - 1001; +inline constexpr int kJavaFieldNumber = 1001; PROTOC_EXPORT extern ::google::protobuf::internal::ExtensionIdentifier< ::google::protobuf::FeatureSet, ::google::protobuf::internal::MessageTypeTraits< ::pb::JavaFeatures >, 11, false> java; +namespace internal { +template <> +inline ::absl::string_view GetFeatureSetDefaultsData<::pb::JavaFeatures>() { + static constexpr char kDefaults[] = "CicYhAciA8o+ACodCAEQAhgCIAMoATACOAJAAco+CggBEAEYACABKAMKJxjnByIDyj4AKh0IAhABGAEgAigBMAE4AkAByj4KCAAQARgAIAEoAwonGOgHIhMIARABGAEgAigBMAHKPgQIABABKg04AkAByj4GGAAgASgDIOYHKOgH"; + return kDefaults; +} +} // namespace internal // =================================================================== diff --git a/src/google/protobuf/compiler/java/name_resolver.cc b/src/google/protobuf/compiler/java/name_resolver.cc index 6002a21645942..418f26f87deaf 100644 --- a/src/google/protobuf/compiler/java/name_resolver.cc +++ b/src/google/protobuf/compiler/java/name_resolver.cc @@ -38,11 +38,7 @@ namespace { const char* kOuterClassNameSuffix = "OuterClass"; inline bool UseOldFileClassNameDefault(const FileDescriptor* file) { - // TODO b/373884685 - Clean up this check once when we have a way to query - // Java features in the C++ runtime. - if (JavaGenerator::GetEdition(*file) < EDITION_2024) return true; - return JavaGenerator::GetResolvedSourceFeatures(*file) - .GetExtension(pb::java) + return JavaGenerator::GetResolvedSourceFeatureExtension(*file, pb::java) .use_old_outer_classname_default(); } diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index 116f46c9fc55c..dcb42cbdeb890 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/compiler/plugin.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/compiler/plugin.pb.h" diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 65326a7f3fba2..2b623100110ee 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/compiler/plugin.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fcompiler_2fplugin_2eproto_2epb_2eh #define google_2fprotobuf_2fcompiler_2fplugin_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/compiler/python/pyi_generator.cc b/src/google/protobuf/compiler/python/pyi_generator.cc index d687259cf9c73..31e1fb8545485 100644 --- a/src/google/protobuf/compiler/python/pyi_generator.cc +++ b/src/google/protobuf/compiler/python/pyi_generator.cc @@ -73,6 +73,7 @@ struct ImportModules { bool has_union = false; // typing.Union bool has_callable = false; // typing.Callable bool has_well_known_type = false; + bool has_datetime = false; }; // Checks whether a descriptor name matches a well-known type. @@ -112,8 +113,15 @@ void CheckImportModules(const Descriptor* descriptor, if (field->is_map()) { import_modules->has_mapping = true; const FieldDescriptor* value_des = field->message_type()->field(1); - if (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || - value_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + if (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + import_modules->has_union = true; + const absl::string_view name = value_des->message_type()->full_name(); + if (name == "google.protobuf.Duration" || + name == "google.protobuf.Timestamp") { + import_modules->has_datetime = true; + } + } + if (value_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { import_modules->has_union = true; } } else { @@ -123,6 +131,11 @@ void CheckImportModules(const Descriptor* descriptor, if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { import_modules->has_union = true; import_modules->has_mapping = true; + const absl::string_view name = field->message_type()->full_name(); + if (name == "google.protobuf.Duration" || + name == "google.protobuf.Timestamp") { + import_modules->has_datetime = true; + } } if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { import_modules->has_union = true; @@ -170,21 +183,6 @@ void PyiGenerator::PrintImportForDescriptor( } void PyiGenerator::PrintImports() const { - // Prints imported dependent _pb2 files. - absl::flat_hash_set seen_aliases; - bool has_importlib = false; - for (int i = 0; i < file_->dependency_count(); ++i) { - const FileDescriptor* dep = file_->dependency(i); - if (strip_nonfunctional_codegen_ && IsKnownFeatureProto(dep->name())) { - continue; - } - PrintImportForDescriptor(*dep, &seen_aliases, &has_importlib); - for (int j = 0; j < dep->public_dependency_count(); ++j) { - PrintImportForDescriptor(*dep->public_dependency(j), &seen_aliases, - &has_importlib); - } - } - // Checks what modules should be imported. ImportModules import_modules; if (file_->message_type_count() > 0) { @@ -201,6 +199,24 @@ void PyiGenerator::PrintImports() const { for (int i = 0; i < file_->message_type_count(); i++) { CheckImportModules(file_->message_type(i), &import_modules); } + if (import_modules.has_datetime) { + printer_->Print("import datetime\n\n"); + } + + // Prints imported dependent _pb2 files. + absl::flat_hash_set seen_aliases; + bool has_importlib = false; + for (int i = 0; i < file_->dependency_count(); ++i) { + const FileDescriptor* dep = file_->dependency(i); + if (strip_nonfunctional_codegen_ && IsKnownFeatureProto(dep->name())) { + continue; + } + PrintImportForDescriptor(*dep, &seen_aliases, &has_importlib); + for (int j = 0; j < dep->public_dependency_count(); ++j) { + PrintImportForDescriptor(*dep->public_dependency(j), &seen_aliases, + &has_importlib); + } + } // Prints modules (e.g. _containers, _messages, typing) that are // required in the proto file. diff --git a/src/google/protobuf/compiler/versions.h b/src/google/protobuf/compiler/versions.h index 17f52e3a6885d..8d821c3ba34a7 100644 --- a/src/google/protobuf/compiler/versions.h +++ b/src/google/protobuf/compiler/versions.h @@ -53,10 +53,10 @@ // // Please avoid changing them manually, as they should be updated automatically // by Protobuf release process. -#define PROTOBUF_CPP_VERSION_STRING "6.31.0" -#define PROTOBUF_JAVA_VERSION_STRING "4.31.0" -#define PROTOBUF_PYTHON_VERSION_STRING "6.31.0" -#define PROTOBUF_RUST_VERSION_STRING "4.31.0" +#define PROTOBUF_CPP_VERSION_STRING "6.31.1" +#define PROTOBUF_JAVA_VERSION_STRING "4.31.1" +#define PROTOBUF_PYTHON_VERSION_STRING "6.31.1" +#define PROTOBUF_RUST_VERSION_STRING "4.31.1" namespace google { diff --git a/src/google/protobuf/cpp_features.pb.cc b/src/google/protobuf/cpp_features.pb.cc index b3a24523c06fe..0b85061c361bc 100644 --- a/src/google/protobuf/cpp_features.pb.cc +++ b/src/google/protobuf/cpp_features.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/cpp_features.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/cpp_features.pb.h" diff --git a/src/google/protobuf/cpp_features.pb.h b/src/google/protobuf/cpp_features.pb.h index ecc5050b11553..6920a52aaa0b9 100644 --- a/src/google/protobuf/cpp_features.pb.h +++ b/src/google/protobuf/cpp_features.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/cpp_features.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fcpp_5ffeatures_2eproto_2epb_2eh #define google_2fprotobuf_2fcpp_5ffeatures_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" @@ -354,8 +354,7 @@ PROTOBUF_EXPORT extern const ::google::protobuf::internal::ClassDataFull CppFeat -inline constexpr int kCppFieldNumber = - 1000; +inline constexpr int kCppFieldNumber = 1000; PROTOBUF_EXPORT extern ::google::protobuf::internal::ExtensionIdentifier< ::google::protobuf::FeatureSet, ::google::protobuf::internal::MessageTypeTraits< ::pb::CppFeatures >, 11, false> cpp; diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 7456d3c3d6653..f97d2065a3247 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -78,6 +78,7 @@ #include "google/protobuf/dynamic_message.h" #include "google/protobuf/feature_resolver.h" #include "google/protobuf/generated_message_util.h" +#include "google/protobuf/internal_feature_helper.h" #include "google/protobuf/io/strtod.h" #include "google/protobuf/io/tokenizer.h" #include "google/protobuf/message.h" @@ -10711,9 +10712,6 @@ namespace internal { absl::string_view ShortEditionName(Edition edition) { return absl::StripPrefix(Edition_Name(edition), "EDITION_"); } -Edition InternalFeatureHelper::GetEdition(const FileDescriptor& desc) { - return desc.edition(); -} } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index f0d1ba647f492..af6222a5fb6c7 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -148,6 +148,10 @@ namespace io { class Printer; } // namespace io +namespace internal { +class InternalFeatureHelper; +} // namespace internal + // NB, all indices are zero-based. struct SourceLocation { int start_line; @@ -320,41 +324,6 @@ class PROTOBUF_EXPORT SymbolBase { template class PROTOBUF_EXPORT SymbolBaseN : public SymbolBase {}; -// This class is for internal use only and provides access to the resolved -// runtime FeatureSets of any descriptor. These features are not designed -// to be stable, and depending directly on them (vs the public descriptor APIs) -// is not safe. -class PROTOBUF_EXPORT InternalFeatureHelper { - public: - template - static const FeatureSet& GetFeatures(const DescriptorT& desc) { - return desc.features(); - } - - private: - friend class ::google::protobuf::compiler::CodeGenerator; - friend class ::google::protobuf::compiler::CommandLineInterface; - - // Provides a restricted view exclusively to code generators to query their - // own unresolved features. Unresolved features are virtually meaningless to - // everyone else. Code generators will need them to validate their own - // features, and runtimes may need them internally to be able to properly - // represent the original proto files from generated code. - template - static typename TypeTraitsT::ConstType GetUnresolvedFeatures( - const DescriptorT& descriptor, - const google::protobuf::internal::ExtensionIdentifier< - FeatureSet, TypeTraitsT, field_type, is_packed>& extension) { - return descriptor.proto_features_->GetExtension(extension); - } - - // Provides a restricted view exclusively to code generators to query the - // edition of files being processed. While most people should never write - // edition-dependent code, generators frequently will need to. - static Edition GetEdition(const FileDescriptor& desc); -}; - PROTOBUF_EXPORT absl::string_view ShortEditionName(Edition edition); bool IsEnumFullySequential(const EnumDescriptor* enum_desc); diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index d3dc31823fc00..637fb2d9b3a2e 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/descriptor.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/descriptor.pb.h" diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 760c8035ea032..eca29b66f9db2 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/descriptor.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fdescriptor_2eproto_2epb_2eh #define google_2fprotobuf_2fdescriptor_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 626b6f999dae5..1b744ca46e587 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -62,6 +62,7 @@ #include "google/protobuf/descriptor_legacy.h" #include "google/protobuf/dynamic_message.h" #include "google/protobuf/feature_resolver.h" +#include "google/protobuf/internal_feature_helper.h" #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/tokenizer.h" #include "google/protobuf/io/zero_copy_stream_impl_lite.h" diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc index 7aff062120411..0082e2454d9fe 100644 --- a/src/google/protobuf/duration.pb.cc +++ b/src/google/protobuf/duration.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/duration.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/duration.pb.h" diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h index 3f93f863ba983..28e6cb0a3c088 100644 --- a/src/google/protobuf/duration.pb.h +++ b/src/google/protobuf/duration.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/duration.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fduration_2eproto_2epb_2eh #define google_2fprotobuf_2fduration_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc index ace50306ab6a4..92ba7143e5b3b 100644 --- a/src/google/protobuf/empty.pb.cc +++ b/src/google/protobuf/empty.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/empty.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/empty.pb.h" diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h index 8427b07b670c2..454e9b7b36b12 100644 --- a/src/google/protobuf/empty.pb.h +++ b/src/google/protobuf/empty.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/empty.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fempty_2eproto_2epb_2eh #define google_2fprotobuf_2fempty_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index fafd21e9fe3c1..37c2da3deb185 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -33,6 +33,7 @@ #include "absl/base/prefetch.h" #include "absl/container/btree_map.h" #include "absl/log/absl_check.h" +#include "absl/strings/string_view.h" #include "google/protobuf/generated_enum_util.h" #include "google/protobuf/internal_visibility.h" #include "google/protobuf/port.h" @@ -76,6 +77,13 @@ void InitializeLazyExtensionSet(); } // namespace google namespace pb { class CppFeatures; +namespace internal { +// Forward-declares the function for FeatureSet extensions to make it visible +// to the internal feature helper. It should hold and return serialized +// FeatureSetDefaults data. +template +inline ::absl::string_view GetFeatureSetDefaultsData(); +} // namespace internal } // namespace pb namespace google { diff --git a/src/google/protobuf/feature_resolver.cc b/src/google/protobuf/feature_resolver.cc index 731ccb9822840..f5b8abae08d4f 100644 --- a/src/google/protobuf/feature_resolver.cc +++ b/src/google/protobuf/feature_resolver.cc @@ -526,21 +526,10 @@ absl::StatusOr FeatureResolver::Create( prev_edition = edition_default.edition(); } - // Select the matching edition defaults. - auto comparator = [](const auto& a, const auto& b) { - return a.edition() < b.edition(); - }; - FeatureSetDefaults::FeatureSetEditionDefault search; - search.set_edition(edition); - auto first_nonmatch = - absl::c_upper_bound(compiled_defaults.defaults(), search, comparator); - if (first_nonmatch == compiled_defaults.defaults().begin()) { - return Error("No valid default found for edition ", edition); - } - - FeatureSet features = std::prev(first_nonmatch)->fixed_features(); - features.MergeFrom(std::prev(first_nonmatch)->overridable_features()); - return FeatureResolver(std::move(features)); + auto features = + internal::GetEditionFeatureSetDefaults(edition, compiled_defaults); + RETURN_IF_ERROR(features.status()); + return FeatureResolver(std::move(features.value())); } absl::StatusOr FeatureResolver::MergeFeatures( @@ -581,6 +570,25 @@ FeatureResolver::ValidationResults FeatureResolver::ValidateFeatureLifetimes( return results; } +namespace internal { +absl::StatusOr GetEditionFeatureSetDefaults( + Edition edition, const FeatureSetDefaults& defaults) { + // Select the matching edition defaults. + auto comparator = [](const auto& a, const auto& b) { + return a.edition() < b.edition(); + }; + FeatureSetDefaults::FeatureSetEditionDefault search; + search.set_edition(edition); + auto first_nonmatch = + absl::c_upper_bound(defaults.defaults(), search, comparator); + if (first_nonmatch == defaults.defaults().begin()) { + return Error("No valid default found for edition ", edition); + } + FeatureSet features = std::prev(first_nonmatch)->fixed_features(); + features.MergeFrom(std::prev(first_nonmatch)->overridable_features()); + return features; +} +} // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/feature_resolver.h b/src/google/protobuf/feature_resolver.h index 543cf9850037d..d66c156e2f66d 100644 --- a/src/google/protobuf/feature_resolver.h +++ b/src/google/protobuf/feature_resolver.h @@ -80,9 +80,15 @@ class PROTOBUF_EXPORT FeatureResolver { FeatureSet defaults_; }; +namespace internal { +// Gets the default feature set for a given edition. +absl::StatusOr PROTOBUF_EXPORT GetEditionFeatureSetDefaults( + Edition edition, const FeatureSetDefaults& defaults); +} // namespace internal } // namespace protobuf } // namespace google +#include "google/protobuf/port_undef.inc" + #endif // GOOGLE_PROTOBUF_FEATURE_RESOLVER_H__ -#include "google/protobuf/port_undef.inc" diff --git a/src/google/protobuf/feature_resolver_test.cc b/src/google/protobuf/feature_resolver_test.cc index eb27662f8b6e7..341b69ae72825 100644 --- a/src/google/protobuf/feature_resolver_test.cc +++ b/src/google/protobuf/feature_resolver_test.cc @@ -562,6 +562,46 @@ TEST(FeatureResolverTest, MergeFeaturesDistantFuture) { HasSubstr("maximum supported edition 99997_TEST_ONLY")))); } +TEST(FeatureResolverTest, GetEditionFeatureSetDefaults) { + absl::StatusOr defaults = + FeatureResolver::CompileDefaults(FeatureSet::descriptor(), + {GetExtension(pb::test)}, EDITION_LEGACY, + EDITION_99997_TEST_ONLY); + + absl::StatusOr edition_2023_feature = + internal::GetEditionFeatureSetDefaults(EDITION_2023, *defaults); + absl::StatusOr edition_proto3_feature = + internal::GetEditionFeatureSetDefaults(EDITION_PROTO3, *defaults); + absl::StatusOr edition_proto2_feature = + internal::GetEditionFeatureSetDefaults(EDITION_LEGACY, *defaults); + absl::StatusOr edition_test_feature = + internal::GetEditionFeatureSetDefaults(EDITION_99998_TEST_ONLY, + *defaults); + EXPECT_OK(edition_2023_feature); + EXPECT_EQ(edition_2023_feature->GetExtension(pb::test).file_feature(), + pb::VALUE3); + EXPECT_OK(edition_proto3_feature); + EXPECT_EQ(edition_proto3_feature->GetExtension(pb::test).file_feature(), + pb::VALUE2); + EXPECT_OK(edition_proto2_feature); + EXPECT_EQ(edition_proto2_feature->GetExtension(pb::test).file_feature(), + pb::VALUE1); + EXPECT_OK(edition_test_feature); + EXPECT_EQ(edition_test_feature->GetExtension(pb::test).file_feature(), + pb::VALUE4); +} + +TEST(FeatureResolverTest, GetEditionFeatureSetDefaultsNotFound) { + absl::StatusOr defaults = + FeatureResolver::CompileDefaults(FeatureSet::descriptor(), + {GetExtension(pb::test)}, EDITION_2023, + EDITION_2023); + + absl::StatusOr edition_2023_feature = + internal::GetEditionFeatureSetDefaults(EDITION_1_TEST_ONLY, *defaults); + EXPECT_THAT(edition_2023_feature, HasError(HasSubstr("No valid default"))); +} + TEST(FeatureResolverLifetimesTest, Valid) { FeatureSet features = ParseTextOrDie(R"pb( [pb.test] { file_feature: VALUE1 } diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc index 4da0421cdd8d3..944d06c1e1c24 100644 --- a/src/google/protobuf/field_mask.pb.cc +++ b/src/google/protobuf/field_mask.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/field_mask.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/field_mask.pb.h" diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h index 2e334c65679f6..902c31bd66ec3 100644 --- a/src/google/protobuf/field_mask.pb.h +++ b/src/google/protobuf/field_mask.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/field_mask.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2ffield_5fmask_2eproto_2epb_2eh #define google_2fprotobuf_2ffield_5fmask_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/internal_feature_helper.cc b/src/google/protobuf/internal_feature_helper.cc new file mode 100644 index 0000000000000..a0a1c99cbbf91 --- /dev/null +++ b/src/google/protobuf/internal_feature_helper.cc @@ -0,0 +1,28 @@ +#include "google/protobuf/internal_feature_helper.h" + +#include + +#include "absl/log/absl_check.h" +#include "absl/strings/escaping.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/extension_set.h" +#include "google/protobuf/feature_resolver.h" + +namespace google { +namespace protobuf { +namespace internal { +FeatureSet InternalFeatureHelper::ParseAndGetEditionResolvedFeatureSet( + absl::string_view data, Edition edition) { + FeatureSetDefaults defaults; + std::string unescaped_data; + absl::Base64Unescape(data, &unescaped_data); + ABSL_CHECK(defaults.ParseFromString(unescaped_data)); + auto edition_feature_set = GetEditionFeatureSetDefaults(edition, defaults); + ABSL_CHECK_OK(edition_feature_set); + return *edition_feature_set; +} +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/internal_feature_helper.h b/src/google/protobuf/internal_feature_helper.h new file mode 100644 index 0000000000000..f183778424842 --- /dev/null +++ b/src/google/protobuf/internal_feature_helper.h @@ -0,0 +1,109 @@ +#ifndef GOOGLE_PROTOBUF_INTERNAL_FEATURE_HELPER_H__ +#define GOOGLE_PROTOBUF_INTERNAL_FEATURE_HELPER_H__ + +#include + +#include "absl/strings/string_view.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/extension_set.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace internal { +class InternalFeatureHelperTest; +// This class is for internal use only and provides access to the resolved +// runtime FeatureSets of any descriptor. These features are not designed +// to be stable, and depending directly on them (vs the public descriptor APIs) +// is not safe. +class PROTOBUF_EXPORT InternalFeatureHelper { + public: + template + static const FeatureSet& GetFeatures(const DescriptorT& desc) { + return desc.features(); + } + + private: + friend class ::google::protobuf::compiler::CodeGenerator; + friend class ::google::protobuf::compiler::CommandLineInterface; + friend class ::google::protobuf::internal::InternalFeatureHelperTest; + + static const DescriptorPool& GetDescriptorPool(const FileDescriptor& file) { + return *file.pool(); + } + + template + static const DescriptorPool& GetDescriptorPool(const DescriptorT& desc) { + return GetDescriptorPool(*desc.file()); + } + + // Provides a restricted view exclusively to code generators to query their + // own unresolved features. Unresolved features are virtually meaningless to + // everyone else. Code generators will need them to validate their own + // features, and runtimes may need them internally to be able to properly + // represent the original proto files from generated code. + template + static typename TypeTraitsT::ConstType GetUnresolvedFeatures( + const DescriptorT& descriptor, + const google::protobuf::internal::ExtensionIdentifier< + FeatureSet, TypeTraitsT, field_type, is_packed>& extension) { + return descriptor.proto_features_->GetExtension(extension); + } + + // Provides a restricted view exclusively to code generators to query the + // edition of files being processed. While most people should never write + // edition-dependent code, generators frequently will need to. + static Edition GetEdition(const FileDescriptor& desc) { + return desc.edition(); + } + + template + static Edition GetEdition(const DescriptorT& desc) { + return GetEdition(*desc.file()); + } + + // Parses the serialized FeatureSetDefaults and returns the resolved + // FeatureSet for a given edition. + static FeatureSet ParseAndGetEditionResolvedFeatureSet(absl::string_view data, + Edition edition); + + // Gets the resolved FeatureSet extension for a given descriptor. + // + // If the descriptor's pool has already provided the resolved feature default + // for the edition and the language FeatureSet extension, then the default + // will be returned directly. Otherwise, the function will parse the + // serialized FeatureSetDefaults data provided by the language FeatureSet + // extension, and merge it with the original FeatureSet extension so that the + // resolved feature set defaults will always be present. + template + static auto GetResolvedFeatureExtension( + const DescriptorT& descriptor, + const google::protobuf::internal::ExtensionIdentifier< + FeatureSet, MessageTypeTraits, field_type, is_packed>& + extension) { + auto lang_features = GetFeatures(descriptor).GetExtension(extension); + if (GetDescriptorPool(descriptor).ResolvesFeaturesFor(extension)) { + return lang_features; + } + + auto lang_features_ret = + ParseAndGetEditionResolvedFeatureSet( + ::pb::internal::GetFeatureSetDefaultsData(), + GetEdition(descriptor)) + .GetExtension(extension); + lang_features_ret.MergeFrom(lang_features); + return lang_features_ret; + } +}; +} // namespace internal +} // namespace protobuf +} // namespace google + +#include "google/protobuf/port_undef.inc" + +#endif // GOOGLE_PROTOBUF_INTERNAL_FEATURE_HELPER_H__ diff --git a/src/google/protobuf/internal_feature_helper_test.cc b/src/google/protobuf/internal_feature_helper_test.cc new file mode 100644 index 0000000000000..5394e61749240 --- /dev/null +++ b/src/google/protobuf/internal_feature_helper_test.cc @@ -0,0 +1,210 @@ +#include "google/protobuf/internal_feature_helper.h" + +#include + +#include "google/protobuf/descriptor.pb.h" +#include +#include +#include "absl/log/absl_check.h" +#include "absl/log/absl_log.h" +#include "absl/strings/str_format.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/compiler/parser.h" +#include "google/protobuf/descriptor.h" +#include "google/protobuf/descriptor.pb.h" +#include "google/protobuf/extension_set.h" +#include "google/protobuf/feature_resolver.h" +#include "google/protobuf/io/tokenizer.h" +#include "google/protobuf/io/zero_copy_stream_impl_lite.h" +#include "google/protobuf/test_textproto.h" +#include "google/protobuf/unittest_features.pb.h" + +// Must be included last. +#include "google/protobuf/port_def.inc" + +namespace google { +namespace protobuf { +namespace internal { +namespace { +#define ASSERT_OK(x) ASSERT_TRUE(x.ok()) << x.message(); + +using ::testing::NotNull; + +class SimpleErrorCollector : public io::ErrorCollector { + public: + void RecordError(int line, int column, absl::string_view message) override { + ABSL_LOG(ERROR) << absl::StrFormat("%d:%d:%s", line, column, message); + } +}; +} // namespace + +class InternalFeatureHelperTest : public ::testing::Test { + protected: + template + static auto GetResolvedSourceFeatureExtension( + const DescriptorT& desc, + const google::protobuf::internal::ExtensionIdentifier< + FeatureSet, TypeTraitsT, field_type, is_packed>& extension) { + return ::google::protobuf::internal::InternalFeatureHelper:: + GetResolvedFeatureExtension(desc, extension); + } + + const FileDescriptor* BuildFile(absl::string_view schema) { + io::ArrayInputStream input_stream(schema.data(), + static_cast(schema.size())); + SimpleErrorCollector error_collector; + io::Tokenizer tokenizer(&input_stream, &error_collector); + compiler::Parser parser; + parser.RecordErrorsTo(&error_collector); + FileDescriptorProto proto; + ABSL_CHECK(parser.Parse(&tokenizer, &proto)) << schema; + proto.set_name("test.proto"); + return pool_.BuildFile(proto); + } + + const FileDescriptor* BuildFile(const FileDescriptor* file) { + FileDescriptorProto proto; + file->CopyTo(&proto); + return pool_.BuildFile(proto); + } + FeatureSetDefaults GetFeatureSetDefaults() { + auto defaults = FeatureResolver::CompileDefaults( + FeatureSet::descriptor(), {GetExtensionReflection(pb::test)}, + EDITION_PROTO2, EDITION_2024); + ABSL_CHECK_OK(defaults); + return *defaults; + } + + DescriptorPool pool_; +}; + +namespace { +TEST_F(InternalFeatureHelperTest, GetResolvedSourceFeatureExtension) { + ASSERT_OK(pool_.SetFeatureSetDefaults(GetFeatureSetDefaults())); + + ASSERT_THAT(BuildFile(DescriptorProto::descriptor()->file()), NotNull()); + ASSERT_THAT(BuildFile(pb::TestMessage::descriptor()->file()), NotNull()); + auto file = BuildFile(R"schema( + edition = "2023"; + package proto2_unittest; + + import "google/protobuf/unittest_features.proto"; + + option features.(pb.test).file_feature = VALUE6; + option features.(pb.test).source_feature = VALUE5; + )schema"); + ASSERT_THAT(file, NotNull()); + const pb::TestFeatures& ext1 = + GetResolvedSourceFeatureExtension(*file, pb::test); + const pb::TestFeatures& ext2 = + InternalFeatureHelper::GetFeatures(*file).GetExtension(pb::test); + EXPECT_EQ(ext1.enum_feature(), pb::EnumFeature::VALUE1); + EXPECT_EQ(ext1.field_feature(), pb::EnumFeature::VALUE1); + EXPECT_EQ(ext1.file_feature(), pb::EnumFeature::VALUE6); + EXPECT_EQ(ext1.source_feature(), pb::EnumFeature::VALUE5); + EXPECT_EQ(ext2.enum_feature(), ext1.enum_feature()); + EXPECT_EQ(ext2.field_feature(), ext1.field_feature()); + EXPECT_EQ(ext2.file_feature(), ext1.file_feature()); + EXPECT_EQ(ext2.source_feature(), ext1.source_feature()); +} + +TEST_F(InternalFeatureHelperTest, + GetResolvedSourceFeatureExtensionEditedDefaults) { + FeatureSetDefaults defaults = ParseTextOrDie(R"pb( + minimum_edition: EDITION_PROTO2 + maximum_edition: EDITION_2024 + defaults { + edition: EDITION_LEGACY + overridable_features {} + fixed_features { + field_presence: EXPLICIT + enum_type: CLOSED + repeated_field_encoding: EXPANDED + utf8_validation: NONE + message_encoding: LENGTH_PREFIXED + json_format: LEGACY_BEST_EFFORT + enforce_naming_style: STYLE_LEGACY + default_symbol_visibility: EXPORT_ALL + } + } + defaults { + edition: EDITION_2023 + overridable_features { + field_presence: EXPLICIT + enum_type: OPEN + repeated_field_encoding: PACKED + utf8_validation: VERIFY + message_encoding: LENGTH_PREFIXED + json_format: ALLOW + [pb.test] { + file_feature: VALUE3 + field_feature: VALUE15 + enum_feature: VALUE14 + source_feature: VALUE1 + } + } + fixed_features { + enforce_naming_style: STYLE_LEGACY + default_symbol_visibility: EXPORT_ALL + } + } + )pb"); + ASSERT_OK(pool_.SetFeatureSetDefaults(defaults)); + + ASSERT_THAT(BuildFile(DescriptorProto::descriptor()->file()), NotNull()); + ASSERT_THAT(BuildFile(pb::TestMessage::descriptor()->file()), NotNull()); + auto file = BuildFile(R"schema( + edition = "2023"; + package proto2_unittest; + + import "google/protobuf/unittest_features.proto"; + + option features.(pb.test).file_feature = VALUE6; + option features.(pb.test).source_feature = VALUE5; + )schema"); + ASSERT_THAT(file, NotNull()); + const pb::TestFeatures& ext = + GetResolvedSourceFeatureExtension(*file, pb::test); + + EXPECT_EQ(ext.enum_feature(), pb::EnumFeature::VALUE14); + EXPECT_EQ(ext.field_feature(), pb::EnumFeature::VALUE15); + EXPECT_EQ(ext.file_feature(), pb::EnumFeature::VALUE6); + EXPECT_EQ(ext.source_feature(), pb::EnumFeature::VALUE5); +} + +TEST_F(InternalFeatureHelperTest, + GetResolvedSourceFeatureExtensionDefaultsFromFeatureSetExtension) { + ASSERT_THAT(BuildFile(DescriptorProto::descriptor()->file()), NotNull()); + ASSERT_THAT(BuildFile(pb::TestMessage::descriptor()->file()), NotNull()); + auto file = BuildFile(R"schema( + edition = "2023"; + package proto2_unittest; + + import "google/protobuf/unittest_features.proto"; + + option features.(pb.test).file_feature = VALUE6; + option features.(pb.test).source_feature = VALUE5; + )schema"); + ASSERT_THAT(file, NotNull()); + + const pb::TestFeatures& ext1 = + GetResolvedSourceFeatureExtension(*file, pb::test); + const pb::TestFeatures& ext2 = + InternalFeatureHelper::GetFeatures(*file).GetExtension(pb::test); + + EXPECT_EQ(ext1.enum_feature(), pb::EnumFeature::VALUE1); + EXPECT_EQ(ext1.field_feature(), pb::EnumFeature::VALUE1); + EXPECT_EQ(ext1.file_feature(), pb::EnumFeature::VALUE6); + EXPECT_EQ(ext1.source_feature(), pb::EnumFeature::VALUE5); + EXPECT_EQ(ext2.enum_feature(), pb::EnumFeature::TEST_ENUM_FEATURE_UNKNOWN); + EXPECT_EQ(ext2.field_feature(), pb::EnumFeature::TEST_ENUM_FEATURE_UNKNOWN); + EXPECT_EQ(ext2.file_feature(), pb::EnumFeature::VALUE6); + EXPECT_EQ(ext2.source_feature(), pb::EnumFeature::VALUE5); +} + +#include "google/protobuf/port_undef.inc" +} // namespace +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/runtime_version.h b/src/google/protobuf/runtime_version.h index 8f135c2b57cef..2fa48639c209f 100644 --- a/src/google/protobuf/runtime_version.h +++ b/src/google/protobuf/runtime_version.h @@ -18,7 +18,7 @@ #endif // PROTOBUF_OSS_VERSION_SUFFIX // The OSS versions are not stripped to avoid merging conflicts. -#define PROTOBUF_OSS_VERSION 6031000 +#define PROTOBUF_OSS_VERSION 6031001 #define PROTOBUF_OSS_VERSION_SUFFIX "" #define PROTOBUF_VERSION PROTOBUF_OSS_VERSION diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc index 8e17fc63dfa22..c70e192f7e11c 100644 --- a/src/google/protobuf/source_context.pb.cc +++ b/src/google/protobuf/source_context.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/source_context.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/source_context.pb.h" diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h index 45155510a401b..779d31bf840f0 100644 --- a/src/google/protobuf/source_context.pb.h +++ b/src/google/protobuf/source_context.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/source_context.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fsource_5fcontext_2eproto_2epb_2eh #define google_2fprotobuf_2fsource_5fcontext_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc index 0b9f8e71ed5a5..be01b5af93d02 100644 --- a/src/google/protobuf/struct.pb.cc +++ b/src/google/protobuf/struct.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/struct.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/struct.pb.h" diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index 640c8d8ead631..cef8c7cfd674b 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/struct.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fstruct_2eproto_2epb_2eh #define google_2fprotobuf_2fstruct_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index bcbc6c952efb6..54e08473ba1a0 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -44,7 +44,7 @@ namespace internal { // The current version, represented as a single integer to make comparison // easier: major * 10^6 + minor * 10^3 + micro -#define GOOGLE_PROTOBUF_VERSION 6031000 +#define GOOGLE_PROTOBUF_VERSION 6031001 // A suffix string for alpha, beta or rc releases. Empty for stable releases. #define GOOGLE_PROTOBUF_VERSION_SUFFIX "" diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc index 0f7979cddefe1..ae7b7285d75df 100644 --- a/src/google/protobuf/timestamp.pb.cc +++ b/src/google/protobuf/timestamp.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/timestamp.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/timestamp.pb.h" diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h index 316e94c8ed40e..6ac7bd8f0bb7e 100644 --- a/src/google/protobuf/timestamp.pb.h +++ b/src/google/protobuf/timestamp.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/timestamp.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2ftimestamp_2eproto_2epb_2eh #define google_2fprotobuf_2ftimestamp_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc index 263d54e2f2dfb..b2bf40149170a 100644 --- a/src/google/protobuf/type.pb.cc +++ b/src/google/protobuf/type.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/type.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/type.pb.h" diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index 748adb7f07804..2b5f1a1c758ae 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/type.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2ftype_2eproto_2epb_2eh #define google_2fprotobuf_2ftype_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index 55983e09df9f6..7a7a230214fef 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/wrappers.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #include "google/protobuf/wrappers.pb.h" diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index dfd6685e70e77..de948eeef2d9a 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -1,7 +1,7 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! // NO CHECKED-IN PROTOBUF GENCODE // source: google/protobuf/wrappers.proto -// Protobuf C++ Version: 6.31.0 +// Protobuf C++ Version: 6.31.1 #ifndef google_2fprotobuf_2fwrappers_2eproto_2epb_2eh #define google_2fprotobuf_2fwrappers_2eproto_2epb_2eh @@ -12,7 +12,7 @@ #include #include "google/protobuf/runtime_version.h" -#if PROTOBUF_VERSION != 6031000 +#if PROTOBUF_VERSION != 6031001 #error "Protobuf C++ gencode is built with an incompatible version of" #error "Protobuf C++ headers/runtime. See" #error "https://protobuf.dev/support/cross-version-runtime-guarantee/#cpp" diff --git a/version.json b/version.json index c3425ad327559..5e5dd0f5e06db 100644 --- a/version.json +++ b/version.json @@ -1,18 +1,18 @@ { "31.x": { - "protoc_version": "31.0", + "protoc_version": "31.1", "lts": false, - "date": "2025-05-14", + "date": "2025-05-28", "languages": { - "cpp": "6.31.0", - "csharp": "3.31.0", - "java": "4.31.0", - "javascript": "3.31.0", - "objectivec": "4.31.0", - "php": "4.31.0", - "python": "6.31.0", - "ruby": "4.31.0", - "rust": "4.31.0" + "cpp": "6.31.1", + "csharp": "3.31.1", + "java": "4.31.1", + "javascript": "3.31.1", + "objectivec": "4.31.1", + "php": "4.31.1", + "python": "6.31.1", + "ruby": "4.31.1", + "rust": "4.31.1" } } } \ No newline at end of file