diff -Nru protobuf-3.12.4/debian/changelog protobuf-3.12.4/debian/changelog --- protobuf-3.12.4/debian/changelog 2021-10-09 20:57:00.000000000 +0000 +++ protobuf-3.12.4/debian/changelog 2023-07-11 08:38:04.000000000 +0000 @@ -1,10 +1,72 @@ -protobuf (3.12.4-1~18.04.sav0) bionic; urgency=medium +protobuf (3.12.4-1ubuntu7.18.04.1sav0) bionic; urgency=medium * Backport to Bionic + * Revert "Don't build elpa stuff on i386" (for pre-Focal): + - d/control: Drop XSBC-Original-Maintainer field causing dh_elpa_test fail * d/{control,rules}: Restore all python2 packaging bits * debian/control: Set debhelper-compat (= 11) BD - -- Rob Savoury Sat, 09 Oct 2021 13:57:00 -0700 + -- Rob Savoury Tue, 11 Jul 2023 18:38:04 +1000 + +protobuf (3.12.4-1ubuntu7.22.04.1) jammy-security; urgency=medium + + * SECURITY UPDATE: DoS in protobuf-java parser + - debian/patches/CVE-2021-22569.patch: Improve performance of parsing + unknown fields in Java + - CVE-2021-22569 + * SECURITY UPDATE: Null pointer dereference issue + - debian/patches/CVE-2021-22570.patch: fix null pointer dereference + - CVE-2021-22570 + * SECURITY UPDATE: Dos vulnerability in cpp and python parser + - debian/patches/CVE-2022-1941.patch: fix parsing vulnerability for the + MessageSet type + - CVE-2022-1941 + + -- Nishit Majithia Thu, 09 Mar 2023 15:05:50 +0530 + +protobuf (3.12.4-1ubuntu7) jammy; urgency=medium + + * No-change rebuild with Python 3.10 only + + -- Graham Inggs Thu, 17 Mar 2022 19:36:00 +0000 + +protobuf (3.12.4-1ubuntu6) jammy; urgency=medium + + * No-change upload due to ruby3.0 transition, remove ruby2.7 support. + + -- Lucas Kanashiro Fri, 03 Dec 2021 13:13:08 -0300 + +protobuf (3.12.4-1ubuntu5) jammy; urgency=medium + + * debian/patches/0001-Fix-Python-3.10-C-tests-9128.patch: Cherry-pick + patch from upstream to fix build failure with python 3.10. + + -- Steve Langasek Wed, 17 Nov 2021 04:43:34 +0000 + +protobuf (3.12.4-1ubuntu4) jammy; urgency=medium + + * No-change rebuild to add python3.10. + + -- Matthias Klose Sat, 16 Oct 2021 06:57:25 +0000 + +protobuf (3.12.4-1ubuntu3) impish; urgency=medium + + * No-change rebuild to build with gcc-11 (LP: #1939413) + + -- Gunnar Hjalmarsson Thu, 12 Aug 2021 12:38:56 +0200 + +protobuf (3.12.4-1ubuntu2) hirsute; urgency=medium + + * No-change rebuild to build with lto. + + -- Matthias Klose Mon, 29 Mar 2021 08:24:14 +0200 + +protobuf (3.12.4-1ubuntu1) hirsute; urgency=low + + * Merge from Debian unstable. Remaining changes: + - Don't build elpa stuff on i386 + + -- Gianfranco Costamagna Tue, 26 Jan 2021 16:42:40 +0100 protobuf (3.12.4-1) unstable; urgency=medium diff -Nru protobuf-3.12.4/debian/control protobuf-3.12.4/debian/control --- protobuf-3.12.4/debian/control 2021-10-09 20:57:00.000000000 +0000 +++ protobuf-3.12.4/debian/control 2023-07-11 08:38:04.000000000 +0000 @@ -1,7 +1,8 @@ Source: protobuf Section: devel Priority: optional -Maintainer: Laszlo Boszormenyi (GCS) +Maintainer: Ubuntu Developers +#XSBC-Original-Maintainer: Laszlo Boszormenyi (GCS) Build-Depends: # Debian build system debhelper-compat (= 11) diff -Nru protobuf-3.12.4/debian/patches/0001-Fix-Python-3.10-C-tests-9128.patch protobuf-3.12.4/debian/patches/0001-Fix-Python-3.10-C-tests-9128.patch --- protobuf-3.12.4/debian/patches/0001-Fix-Python-3.10-C-tests-9128.patch 1970-01-01 00:00:00.000000000 +0000 +++ protobuf-3.12.4/debian/patches/0001-Fix-Python-3.10-C-tests-9128.patch 2021-11-17 04:43:34.000000000 +0000 @@ -0,0 +1,328 @@ +From 63f952b987bd848ac278c714c81c47250214adc7 Mon Sep 17 00:00:00 2001 +From: Adam Cozzette +Date: Wed, 20 Oct 2021 14:51:07 -0700 +Subject: [PATCH] Fix Python 3.10 C++ tests (#9128) + +The first change is to make sure we always define PY_SSIZE_T_CLEAN +before including Python.h. Starting from Python 3.10 this is required. +Otherwise we get errors like this: + +SystemError: PY_SSIZE_T_CLEAN macro must be defined for '#' formats + +The second change is to update reflection_test.py to account for the +fact that with Python 3.10, we get a TypeError even with the C++ +implementation when trying to assign a float to a bool field. I'm not +sure why this changed with Python 3.10, but it seems like a good thing +since this is the desired behavior anyway. +--- + python/google/protobuf/internal/api_implementation.cc | 1 + + python/google/protobuf/internal/reflection_test.py | 4 +++- + python/google/protobuf/proto_api.h | 1 + + python/google/protobuf/pyext/descriptor.cc | 1 + + python/google/protobuf/pyext/descriptor.h | 1 + + python/google/protobuf/pyext/descriptor_containers.cc | 1 + + python/google/protobuf/pyext/descriptor_containers.h | 1 + + python/google/protobuf/pyext/descriptor_database.h | 1 + + python/google/protobuf/pyext/descriptor_pool.cc | 1 + + python/google/protobuf/pyext/descriptor_pool.h | 1 + + python/google/protobuf/pyext/extension_dict.h | 1 + + python/google/protobuf/pyext/field.h | 1 + + python/google/protobuf/pyext/map_container.h | 1 + + python/google/protobuf/pyext/message.h | 1 + + python/google/protobuf/pyext/message_factory.cc | 1 + + python/google/protobuf/pyext/message_factory.h | 1 + + python/google/protobuf/pyext/message_module.cc | 1 + + python/google/protobuf/pyext/repeated_composite_container.h | 1 + + python/google/protobuf/pyext/repeated_scalar_container.h | 1 + + python/google/protobuf/pyext/scoped_pyobject_ptr.h | 1 + + python/google/protobuf/pyext/unknown_fields.cc | 1 + + python/google/protobuf/pyext/unknown_fields.h | 1 + + python/google/protobuf/python_protobuf.h | 1 + + 23 files changed, 25 insertions(+), 1 deletion(-) + +Index: protobuf-3.12.4/python/google/protobuf/internal/api_implementation.cc +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/internal/api_implementation.cc ++++ protobuf-3.12.4/python/google/protobuf/internal/api_implementation.cc +@@ -28,6 +28,7 @@ + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ++#define PY_SSIZE_T_CLEAN + #include + + namespace google { +Index: protobuf-3.12.4/python/google/protobuf/internal/reflection_test.py +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/internal/reflection_test.py ++++ protobuf-3.12.4/python/google/protobuf/internal/reflection_test.py +@@ -40,6 +40,7 @@ + import operator + import six + import struct ++import sys + import warnings + + try: +@@ -387,7 +388,8 @@ + self.assertRaises(TypeError, setattr, proto, 'optional_float', 'foo') + self.assertRaises(TypeError, setattr, proto, 'optional_double', 'foo') + # TODO(jieluo): Fix type checking difference for python and c extension +- if api_implementation.Type() == 'python': ++ if (api_implementation.Type() == 'python' or ++ (sys.version_info.major, sys.version_info.minor) >= (3, 10)): + self.assertRaises(TypeError, setattr, proto, 'optional_bool', 1.1) + else: + proto.optional_bool = 1.1 +Index: protobuf-3.12.4/python/google/protobuf/proto_api.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/proto_api.h ++++ protobuf-3.12.4/python/google/protobuf/proto_api.h +@@ -45,6 +45,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_PROTO_API_H__ + #define GOOGLE_PROTOBUF_PYTHON_PROTO_API_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/descriptor.cc +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/descriptor.cc ++++ protobuf-3.12.4/python/google/protobuf/pyext/descriptor.cc +@@ -30,6 +30,7 @@ + + // Author: petar@google.com (Petar Petrov) + ++#define PY_SSIZE_T_CLEAN + #include + #include + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/descriptor.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/descriptor.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/descriptor.h +@@ -33,6 +33,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/descriptor_containers.cc +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/descriptor_containers.cc ++++ protobuf-3.12.4/python/google/protobuf/pyext/descriptor_containers.cc +@@ -49,6 +49,7 @@ + // because the Python API is based on C, and does not play well with C++ + // inheritance. + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/descriptor_containers.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/descriptor_containers.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/descriptor_containers.h +@@ -34,6 +34,7 @@ + // Mappings and Sequences of descriptors. + // They implement containers like fields_by_name, EnumDescriptor.values... + // See descriptor_containers.cc for more description. ++#define PY_SSIZE_T_CLEAN + #include + + namespace google { +Index: protobuf-3.12.4/python/google/protobuf/pyext/descriptor_database.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/descriptor_database.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/descriptor_database.h +@@ -31,6 +31,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_DATABASE_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/descriptor_pool.cc +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/descriptor_pool.cc ++++ protobuf-3.12.4/python/google/protobuf/pyext/descriptor_pool.cc +@@ -32,6 +32,7 @@ + + #include + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/descriptor_pool.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/descriptor_pool.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/descriptor_pool.h +@@ -31,6 +31,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_DESCRIPTOR_POOL_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/extension_dict.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/extension_dict.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/extension_dict.h +@@ -34,6 +34,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_EXTENSION_DICT_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/field.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/field.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/field.h +@@ -31,6 +31,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_FIELD_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_FIELD_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + namespace google { +Index: protobuf-3.12.4/python/google/protobuf/pyext/map_container.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/map_container.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/map_container.h +@@ -31,6 +31,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_MAP_CONTAINER_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/message.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/message.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/message.h +@@ -34,6 +34,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/message_factory.cc +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/message_factory.cc ++++ protobuf-3.12.4/python/google/protobuf/pyext/message_factory.cc +@@ -30,6 +30,7 @@ + + #include + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/message_factory.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/message_factory.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/message_factory.h +@@ -31,6 +31,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_FACTORY_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_MESSAGE_FACTORY_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/message_module.cc +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/message_module.cc ++++ protobuf-3.12.4/python/google/protobuf/pyext/message_module.cc +@@ -28,6 +28,7 @@ + // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/repeated_composite_container.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/repeated_composite_container.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/repeated_composite_container.h +@@ -34,6 +34,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_COMPOSITE_CONTAINER_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/repeated_scalar_container.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/repeated_scalar_container.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/repeated_scalar_container.h +@@ -34,6 +34,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_REPEATED_SCALAR_CONTAINER_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/scoped_pyobject_ptr.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/scoped_pyobject_ptr.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/scoped_pyobject_ptr.h +@@ -35,6 +35,7 @@ + + #include + ++#define PY_SSIZE_T_CLEAN + #include + namespace google { + namespace protobuf { +Index: protobuf-3.12.4/python/google/protobuf/pyext/unknown_fields.cc +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/unknown_fields.cc ++++ protobuf-3.12.4/python/google/protobuf/pyext/unknown_fields.cc +@@ -30,6 +30,7 @@ + + #include + ++#define PY_SSIZE_T_CLEAN + #include + #include + #include +Index: protobuf-3.12.4/python/google/protobuf/pyext/unknown_fields.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/pyext/unknown_fields.h ++++ protobuf-3.12.4/python/google/protobuf/pyext/unknown_fields.h +@@ -31,6 +31,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_CPP_UNKNOWN_FIELDS_H__ + #define GOOGLE_PROTOBUF_PYTHON_CPP_UNKNOWN_FIELDS_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + #include +Index: protobuf-3.12.4/python/google/protobuf/python_protobuf.h +=================================================================== +--- protobuf-3.12.4.orig/python/google/protobuf/python_protobuf.h ++++ protobuf-3.12.4/python/google/protobuf/python_protobuf.h +@@ -36,6 +36,7 @@ + #ifndef GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__ + #define GOOGLE_PROTOBUF_PYTHON_PYTHON_PROTOBUF_H__ + ++#define PY_SSIZE_T_CLEAN + #include + + namespace google { diff -Nru protobuf-3.12.4/debian/patches/CVE-2021-22569.patch protobuf-3.12.4/debian/patches/CVE-2021-22569.patch --- protobuf-3.12.4/debian/patches/CVE-2021-22569.patch 1970-01-01 00:00:00.000000000 +0000 +++ protobuf-3.12.4/debian/patches/CVE-2021-22569.patch 2023-03-06 06:50:20.000000000 +0000 @@ -0,0 +1,964 @@ +[Ubuntu note: backport, remove test cases since changes are too intrusive in +test files] + +From 5ea2bdf6d7483d64a6b02fcf00ee51fbfb80e847 Mon Sep 17 00:00:00 2001 +From: Adam Cozzette +Date: Wed, 5 Jan 2022 02:01:40 +0000 +Subject: [PATCH] Improve performance of parsing unknown fields in Java + +Credit should go to @elharo for most of these Java changes--I am just +cherry-picking them from our internal codebase. The one thing I did +change was to give the UTF-8 validation tests their own Bazel test +target. This makes it possible to give the other tests a shorter +timeout, which is important for UnknownFieldSetPerformanceTest in +particular. +--- + Makefile.am | 1 + + java/core/BUILD | 24 +- + .../com/google/protobuf/UnknownFieldSet.java | 427 +++++++++--------- + .../UnknownFieldSetPerformanceTest.java | 78 ++++ + .../google/protobuf/UnknownFieldSetTest.java | 182 +++++++- + java/lite/pom.xml | 1 + + 6 files changed, 499 insertions(+), 214 deletions(-) + create mode 100644 java/core/src/test/java/com/google/protobuf/UnknownFieldSetPerformanceTest.java + +--- protobuf-3.12.4.orig/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java ++++ protobuf-3.12.4/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java +@@ -43,13 +43,13 @@ import java.util.Map; + import java.util.TreeMap; + + /** +- * {@code UnknownFieldSet} is used to keep track of fields which were seen when parsing a protocol ++ * {@code UnknownFieldSet} keeps track of fields which were seen when parsing a protocol + * message but whose field numbers or types are unrecognized. This most frequently occurs when new + * fields are added to a message type and then messages containing those fields are read by old + * software that was compiled before the new types were added. + * + *

Every {@link Message} contains an {@code UnknownFieldSet} (and every {@link Message.Builder} +- * contains an {@link Builder}). ++ * contains a {@link Builder}). + * + *

Most users will never need to use this class. + * +@@ -57,9 +57,13 @@ import java.util.TreeMap; + */ + public final class UnknownFieldSet implements MessageLite { + +- private UnknownFieldSet() { +- fields = null; +- fieldsDescending = null; ++ private final TreeMap fields; ++ ++ /** ++ * Construct an {@code UnknownFieldSet} around the given map. ++ */ ++ UnknownFieldSet(TreeMap fields) { ++ this.fields = fields; + } + + /** Create a new {@link Builder}. */ +@@ -68,7 +72,7 @@ public final class UnknownFieldSet imple + } + + /** Create a new {@link Builder} and initialize it to be a copy of {@code copyFrom}. */ +- public static Builder newBuilder(final UnknownFieldSet copyFrom) { ++ public static Builder newBuilder(UnknownFieldSet copyFrom) { + return newBuilder().mergeFrom(copyFrom); + } + +@@ -83,25 +87,11 @@ public final class UnknownFieldSet imple + } + + private static final UnknownFieldSet defaultInstance = +- new UnknownFieldSet( +- Collections.emptyMap(), Collections.emptyMap()); +- +- /** +- * Construct an {@code UnknownFieldSet} around the given map. The map is expected to be immutable. +- */ +- UnknownFieldSet(final Map fields, final Map fieldsDescending) { +- this.fields = fields; +- this.fieldsDescending = fieldsDescending; +- } +- +- private final Map fields; +- +- /** A copy of {@link #fields} who's iterator order is reversed. */ +- private final Map fieldsDescending; ++ new UnknownFieldSet(new TreeMap()); + + + @Override +- public boolean equals(final Object other) { ++ public boolean equals(Object other) { + if (this == other) { + return true; + } +@@ -110,29 +100,33 @@ public final class UnknownFieldSet imple + + @Override + public int hashCode() { ++ if (fields.isEmpty()) { // avoid allocation of iterator. ++ // This optimization may not be helpful but it is needed for the allocation tests to pass. ++ return 0; ++ } + return fields.hashCode(); + } + + /** Get a map of fields in the set by number. */ + public Map asMap() { +- return fields; ++ return (Map) fields.clone(); + } + + /** Check if the given field number is present in the set. */ +- public boolean hasField(final int number) { ++ public boolean hasField(int number) { + return fields.containsKey(number); + } + + /** Get a field by number. Returns an empty field if not present. Never returns {@code null}. */ +- public Field getField(final int number) { +- final Field result = fields.get(number); ++ public Field getField(int number) { ++ Field result = fields.get(number); + return (result == null) ? Field.getDefaultInstance() : result; + } + + /** Serializes the set and writes it to {@code output}. */ + @Override +- public void writeTo(final CodedOutputStream output) throws IOException { +- for (final Map.Entry entry : fields.entrySet()) { ++ public void writeTo(CodedOutputStream output) throws IOException { ++ for (Map.Entry entry : fields.entrySet()) { + Field field = entry.getValue(); + field.writeTo(entry.getKey(), output); + } +@@ -154,10 +148,10 @@ public final class UnknownFieldSet imple + @Override + public ByteString toByteString() { + try { +- final ByteString.CodedBuilder out = ByteString.newCodedBuilder(getSerializedSize()); ++ ByteString.CodedBuilder out = ByteString.newCodedBuilder(getSerializedSize()); + writeTo(out.getCodedOutput()); + return out.build(); +- } catch (final IOException e) { ++ } catch (IOException e) { + throw new RuntimeException( + "Serializing to a ByteString threw an IOException (should never happen).", e); + } +@@ -170,12 +164,12 @@ public final class UnknownFieldSet imple + @Override + public byte[] toByteArray() { + try { +- final byte[] result = new byte[getSerializedSize()]; +- final CodedOutputStream output = CodedOutputStream.newInstance(result); ++ byte[] result = new byte[getSerializedSize()]; ++ CodedOutputStream output = CodedOutputStream.newInstance(result); + writeTo(output); + output.checkNoSpaceLeft(); + return result; +- } catch (final IOException e) { ++ } catch (IOException e) { + throw new RuntimeException( + "Serializing to a byte array threw an IOException (should never happen).", e); + } +@@ -186,16 +180,16 @@ public final class UnknownFieldSet imple + * {@link #writeTo(CodedOutputStream)}. + */ + @Override +- public void writeTo(final OutputStream output) throws IOException { +- final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); ++ public void writeTo(OutputStream output) throws IOException { ++ CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); + writeTo(codedOutput); + codedOutput.flush(); + } + + @Override + public void writeDelimitedTo(OutputStream output) throws IOException { +- final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); +- codedOutput.writeRawVarint32(getSerializedSize()); ++ CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); ++ codedOutput.writeUInt32NoTag(getSerializedSize()); + writeTo(codedOutput); + codedOutput.flush(); + } +@@ -204,15 +198,17 @@ public final class UnknownFieldSet imple + @Override + public int getSerializedSize() { + int result = 0; +- for (final Map.Entry entry : fields.entrySet()) { +- result += entry.getValue().getSerializedSize(entry.getKey()); ++ if (!fields.isEmpty()) { ++ for (Map.Entry entry : fields.entrySet()) { ++ result += entry.getValue().getSerializedSize(entry.getKey()); ++ } + } + return result; + } + + /** Serializes the set and writes it to {@code output} using {@code MessageSet} wire format. */ +- public void writeAsMessageSetTo(final CodedOutputStream output) throws IOException { +- for (final Map.Entry entry : fields.entrySet()) { ++ public void writeAsMessageSetTo(CodedOutputStream output) throws IOException { ++ for (Map.Entry entry : fields.entrySet()) { + entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), output); + } + } +@@ -221,7 +217,7 @@ public final class UnknownFieldSet imple + void writeTo(Writer writer) throws IOException { + if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { + // Write fields in descending order. +- for (Map.Entry entry : fieldsDescending.entrySet()) { ++ for (Map.Entry entry : fields.descendingMap().entrySet()) { + entry.getValue().writeTo(entry.getKey(), writer); + } + } else { +@@ -233,15 +229,15 @@ public final class UnknownFieldSet imple + } + + /** Serializes the set and writes it to {@code writer} using {@code MessageSet} wire format. */ +- void writeAsMessageSetTo(final Writer writer) throws IOException { ++ void writeAsMessageSetTo(Writer writer) throws IOException { + if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { + // Write fields in descending order. +- for (final Map.Entry entry : fieldsDescending.entrySet()) { ++ for (Map.Entry entry : fields.descendingMap().entrySet()) { + entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), writer); + } + } else { + // Write fields in ascending order. +- for (final Map.Entry entry : fields.entrySet()) { ++ for (Map.Entry entry : fields.entrySet()) { + entry.getValue().writeAsMessageSetExtensionTo(entry.getKey(), writer); + } + } +@@ -250,7 +246,7 @@ public final class UnknownFieldSet imple + /** Get the number of bytes required to encode this set using {@code MessageSet} wire format. */ + public int getSerializedSizeAsMessageSet() { + int result = 0; +- for (final Map.Entry entry : fields.entrySet()) { ++ for (Map.Entry entry : fields.entrySet()) { + result += entry.getValue().getSerializedSizeAsMessageSetExtension(entry.getKey()); + } + return result; +@@ -264,23 +260,23 @@ public final class UnknownFieldSet imple + } + + /** Parse an {@code UnknownFieldSet} from the given input stream. */ +- public static UnknownFieldSet parseFrom(final CodedInputStream input) throws IOException { ++ public static UnknownFieldSet parseFrom(CodedInputStream input) throws IOException { + return newBuilder().mergeFrom(input).build(); + } + + /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */ +- public static UnknownFieldSet parseFrom(final ByteString data) ++ public static UnknownFieldSet parseFrom(ByteString data) + throws InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).build(); + } + + /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */ +- public static UnknownFieldSet parseFrom(final byte[] data) throws InvalidProtocolBufferException { ++ public static UnknownFieldSet parseFrom(byte[] data) throws InvalidProtocolBufferException { + return newBuilder().mergeFrom(data).build(); + } + + /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */ +- public static UnknownFieldSet parseFrom(final InputStream input) throws IOException { ++ public static UnknownFieldSet parseFrom(InputStream input) throws IOException { + return newBuilder().mergeFrom(input).build(); + } + +@@ -309,64 +305,43 @@ public final class UnknownFieldSet imple + // This constructor should never be called directly (except from 'create'). + private Builder() {} + +- private Map fields; +- +- // Optimization: We keep around a builder for the last field that was +- // modified so that we can efficiently add to it multiple times in a +- // row (important when parsing an unknown repeated field). +- private int lastFieldNumber; +- private Field.Builder lastField; ++ private TreeMap fieldBuilders = new TreeMap<>(); + + private static Builder create() { +- Builder builder = new Builder(); +- builder.reinitialize(); +- return builder; ++ return new Builder(); + } + + /** + * Get a field builder for the given field number which includes any values that already exist. + */ +- private Field.Builder getFieldBuilder(final int number) { +- if (lastField != null) { +- if (number == lastFieldNumber) { +- return lastField; +- } +- // Note: addField() will reset lastField and lastFieldNumber. +- addField(lastFieldNumber, lastField.build()); +- } ++ private Field.Builder getFieldBuilder(int number) { + if (number == 0) { + return null; + } else { +- final Field existing = fields.get(number); +- lastFieldNumber = number; +- lastField = Field.newBuilder(); +- if (existing != null) { +- lastField.mergeFrom(existing); ++ Field.Builder builder = fieldBuilders.get(number); ++ if (builder == null) { ++ builder = Field.newBuilder(); ++ fieldBuilders.put(number, builder); + } +- return lastField; ++ return builder; + } + } + + /** + * Build the {@link UnknownFieldSet} and return it. +- * +- *

Once {@code build()} has been called, the {@code Builder} will no longer be usable. +- * Calling any method after {@code build()} will result in undefined behavior and can cause a +- * {@code NullPointerException} to be thrown. + */ + @Override + public UnknownFieldSet build() { +- getFieldBuilder(0); // Force lastField to be built. +- final UnknownFieldSet result; +- if (fields.isEmpty()) { ++ UnknownFieldSet result; ++ if (fieldBuilders.isEmpty()) { + result = getDefaultInstance(); + } else { +- Map descendingFields = null; +- descendingFields = +- Collections.unmodifiableMap(((TreeMap) fields).descendingMap()); +- result = new UnknownFieldSet(Collections.unmodifiableMap(fields), descendingFields); ++ TreeMap fields = new TreeMap<>(); ++ for (Map.Entry entry : fieldBuilders.entrySet()) { ++ fields.put(entry.getKey(), entry.getValue().build()); ++ } ++ result = new UnknownFieldSet(fields); + } +- fields = null; + return result; + } + +@@ -378,11 +353,13 @@ public final class UnknownFieldSet imple + + @Override + public Builder clone() { +- getFieldBuilder(0); // Force lastField to be built. +- Map descendingFields = null; +- descendingFields = +- Collections.unmodifiableMap(((TreeMap) fields).descendingMap()); +- return UnknownFieldSet.newBuilder().mergeFrom(new UnknownFieldSet(fields, descendingFields)); ++ Builder clone = UnknownFieldSet.newBuilder(); ++ for (Map.Entry entry : fieldBuilders.entrySet()) { ++ Integer key = entry.getKey(); ++ Field.Builder value = entry.getValue(); ++ clone.fieldBuilders.put(key, value.clone()); ++ } ++ return clone; + } + + @Override +@@ -390,31 +367,24 @@ public final class UnknownFieldSet imple + return UnknownFieldSet.getDefaultInstance(); + } + +- private void reinitialize() { +- fields = Collections.emptyMap(); +- lastFieldNumber = 0; +- lastField = null; +- } +- + /** Reset the builder to an empty set. */ + @Override + public Builder clear() { +- reinitialize(); ++ fieldBuilders = new TreeMap<>(); + return this; + } + +- /** Clear fields from the set with a given field number. */ +- public Builder clearField(final int number) { +- if (number == 0) { +- throw new IllegalArgumentException("Zero is not a valid field number."); +- } +- if (lastField != null && lastFieldNumber == number) { +- // Discard this. +- lastField = null; +- lastFieldNumber = 0; ++ /** ++ * Clear fields from the set with a given field number. ++ * ++ * @throws IllegalArgumentException if number is not positive ++ */ ++ public Builder clearField(int number) { ++ if (number <= 0) { ++ throw new IllegalArgumentException(number + " is not a valid field number."); + } +- if (fields.containsKey(number)) { +- fields.remove(number); ++ if (fieldBuilders.containsKey(number)) { ++ fieldBuilders.remove(number); + } + return this; + } +@@ -423,9 +393,9 @@ public final class UnknownFieldSet imple + * Merge the fields from {@code other} into this set. If a field number exists in both sets, + * {@code other}'s values for that field will be appended to the values in this set. + */ +- public Builder mergeFrom(final UnknownFieldSet other) { ++ public Builder mergeFrom(UnknownFieldSet other) { + if (other != getDefaultInstance()) { +- for (final Map.Entry entry : other.fields.entrySet()) { ++ for (Map.Entry entry : other.fields.entrySet()) { + mergeField(entry.getKey(), entry.getValue()); + } + } +@@ -435,10 +405,12 @@ public final class UnknownFieldSet imple + /** + * Add a field to the {@code UnknownFieldSet}. If a field with the same number already exists, + * the two are merged. ++ * ++ * @throws IllegalArgumentException if number is not positive + */ +- public Builder mergeField(final int number, final Field field) { +- if (number == 0) { +- throw new IllegalArgumentException("Zero is not a valid field number."); ++ public Builder mergeField(int number, final Field field) { ++ if (number <= 0) { ++ throw new IllegalArgumentException(number + " is not a valid field number."); + } + if (hasField(number)) { + getFieldBuilder(number).mergeFrom(field); +@@ -454,10 +426,12 @@ public final class UnknownFieldSet imple + /** + * Convenience method for merging a new field containing a single varint value. This is used in + * particular when an unknown enum value is encountered. ++ * ++ * @throws IllegalArgumentException if number is not positive + */ +- public Builder mergeVarintField(final int number, final int value) { +- if (number == 0) { +- throw new IllegalArgumentException("Zero is not a valid field number."); ++ public Builder mergeVarintField(int number, int value) { ++ if (number <= 0) { ++ throw new IllegalArgumentException(number + " is not a valid field number."); + } + getFieldBuilder(number).addVarint(value); + return this; +@@ -467,40 +441,33 @@ public final class UnknownFieldSet imple + * Convenience method for merging a length-delimited field. + * + *

For use by generated code only. ++ * ++ * @throws IllegalArgumentException if number is not positive + */ +- public Builder mergeLengthDelimitedField(final int number, final ByteString value) { +- if (number == 0) { +- throw new IllegalArgumentException("Zero is not a valid field number."); ++ public Builder mergeLengthDelimitedField(int number, ByteString value) { ++ if (number <= 0) { ++ throw new IllegalArgumentException(number + " is not a valid field number."); + } + getFieldBuilder(number).addLengthDelimited(value); + return this; + } + + /** Check if the given field number is present in the set. */ +- public boolean hasField(final int number) { +- if (number == 0) { +- throw new IllegalArgumentException("Zero is not a valid field number."); +- } +- return number == lastFieldNumber || fields.containsKey(number); ++ public boolean hasField(int number) { ++ return fieldBuilders.containsKey(number); + } + + /** + * Add a field to the {@code UnknownFieldSet}. If a field with the same number already exists, + * it is removed. ++ * ++ * @throws IllegalArgumentException if number is not positive + */ +- public Builder addField(final int number, final Field field) { +- if (number == 0) { +- throw new IllegalArgumentException("Zero is not a valid field number."); +- } +- if (lastField != null && lastFieldNumber == number) { +- // Discard this. +- lastField = null; +- lastFieldNumber = 0; ++ public Builder addField(int number, Field field) { ++ if (number <= 0) { ++ throw new IllegalArgumentException(number + " is not a valid field number."); + } +- if (fields.isEmpty()) { +- fields = new TreeMap(); +- } +- fields.put(number, field); ++ fieldBuilders.put(number, Field.newBuilder(field)); + return this; + } + +@@ -509,15 +476,18 @@ public final class UnknownFieldSet imple + * changes may or may not be reflected in this map. + */ + public Map asMap() { +- getFieldBuilder(0); // Force lastField to be built. ++ TreeMap fields = new TreeMap<>(); ++ for (Map.Entry entry : fieldBuilders.entrySet()) { ++ fields.put(entry.getKey(), entry.getValue().build()); ++ } + return Collections.unmodifiableMap(fields); + } + + /** Parse an entire message from {@code input} and merge its fields into this set. */ + @Override +- public Builder mergeFrom(final CodedInputStream input) throws IOException { ++ public Builder mergeFrom(CodedInputStream input) throws IOException { + while (true) { +- final int tag = input.readTag(); ++ int tag = input.readTag(); + if (tag == 0 || !mergeFieldFrom(tag, input)) { + break; + } +@@ -531,8 +501,8 @@ public final class UnknownFieldSet imple + * @param tag The field's tag number, which was already parsed. + * @return {@code false} if the tag is an end group tag. + */ +- public boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException { +- final int number = WireFormat.getTagFieldNumber(tag); ++ public boolean mergeFieldFrom(int tag, CodedInputStream input) throws IOException { ++ int number = WireFormat.getTagFieldNumber(tag); + switch (WireFormat.getTagWireType(tag)) { + case WireFormat.WIRETYPE_VARINT: + getFieldBuilder(number).addVarint(input.readInt64()); +@@ -544,7 +514,7 @@ public final class UnknownFieldSet imple + getFieldBuilder(number).addLengthDelimited(input.readBytes()); + return true; + case WireFormat.WIRETYPE_START_GROUP: +- final Builder subBuilder = newBuilder(); ++ Builder subBuilder = newBuilder(); + input.readGroup(number, subBuilder, ExtensionRegistry.getEmptyRegistry()); + getFieldBuilder(number).addGroup(subBuilder.build()); + return true; +@@ -563,15 +533,15 @@ public final class UnknownFieldSet imple + * is just a small wrapper around {@link #mergeFrom(CodedInputStream)}. + */ + @Override +- public Builder mergeFrom(final ByteString data) throws InvalidProtocolBufferException { ++ public Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException { + try { +- final CodedInputStream input = data.newCodedInput(); ++ CodedInputStream input = data.newCodedInput(); + mergeFrom(input); + input.checkLastTagWas(0); + return this; +- } catch (final InvalidProtocolBufferException e) { ++ } catch (InvalidProtocolBufferException e) { + throw e; +- } catch (final IOException e) { ++ } catch (IOException e) { + throw new RuntimeException( + "Reading from a ByteString threw an IOException (should never happen).", e); + } +@@ -582,15 +552,15 @@ public final class UnknownFieldSet imple + * is just a small wrapper around {@link #mergeFrom(CodedInputStream)}. + */ + @Override +- public Builder mergeFrom(final byte[] data) throws InvalidProtocolBufferException { ++ public Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException { + try { +- final CodedInputStream input = CodedInputStream.newInstance(data); ++ CodedInputStream input = CodedInputStream.newInstance(data); + mergeFrom(input); + input.checkLastTagWas(0); + return this; +- } catch (final InvalidProtocolBufferException e) { ++ } catch (InvalidProtocolBufferException e) { + throw e; +- } catch (final IOException e) { ++ } catch (IOException e) { + throw new RuntimeException( + "Reading from a byte array threw an IOException (should never happen).", e); + } +@@ -601,8 +571,8 @@ public final class UnknownFieldSet imple + * This is just a small wrapper around {@link #mergeFrom(CodedInputStream)}. + */ + @Override +- public Builder mergeFrom(final InputStream input) throws IOException { +- final CodedInputStream codedInput = CodedInputStream.newInstance(input); ++ public Builder mergeFrom(InputStream input) throws IOException { ++ CodedInputStream codedInput = CodedInputStream.newInstance(input); + mergeFrom(codedInput); + codedInput.checkLastTagWas(0); + return this; +@@ -610,12 +580,12 @@ public final class UnknownFieldSet imple + + @Override + public boolean mergeDelimitedFrom(InputStream input) throws IOException { +- final int firstByte = input.read(); ++ int firstByte = input.read(); + if (firstByte == -1) { + return false; + } +- final int size = CodedInputStream.readRawVarint32(firstByte, input); +- final InputStream limitedInput = new LimitedInputStream(input, size); ++ int size = CodedInputStream.readRawVarint32(firstByte, input); ++ InputStream limitedInput = new LimitedInputStream(input, size); + mergeFrom(limitedInput); + return true; + } +@@ -644,7 +614,7 @@ public final class UnknownFieldSet imple + @Override + public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException { + try { +- final CodedInputStream input = CodedInputStream.newInstance(data, off, len); ++ CodedInputStream input = CodedInputStream.newInstance(data, off, len); + mergeFrom(input); + input.checkLastTagWas(0); + return this; +@@ -718,7 +688,7 @@ public final class UnknownFieldSet imple + } + + /** Construct a new {@link Builder} and initialize it to a copy of {@code copyFrom}. */ +- public static Builder newBuilder(final Field copyFrom) { ++ public static Builder newBuilder(Field copyFrom) { + return newBuilder().mergeFrom(copyFrom); + } + +@@ -758,7 +728,7 @@ public final class UnknownFieldSet imple + } + + @Override +- public boolean equals(final Object other) { ++ public boolean equals(Object other) { + if (this == other) { + return true; + } +@@ -785,7 +755,7 @@ public final class UnknownFieldSet imple + public ByteString toByteString(int fieldNumber) { + try { + // TODO(lukes): consider caching serialized size in a volatile long +- final ByteString.CodedBuilder out = ++ ByteString.CodedBuilder out = + ByteString.newCodedBuilder(getSerializedSize(fieldNumber)); + writeTo(fieldNumber, out.getCodedOutput()); + return out.build(); +@@ -796,40 +766,40 @@ public final class UnknownFieldSet imple + } + + /** Serializes the field, including field number, and writes it to {@code output}. */ +- public void writeTo(final int fieldNumber, final CodedOutputStream output) throws IOException { +- for (final long value : varint) { ++ public void writeTo(int fieldNumber, CodedOutputStream output) throws IOException { ++ for (long value : varint) { + output.writeUInt64(fieldNumber, value); + } +- for (final int value : fixed32) { ++ for (int value : fixed32) { + output.writeFixed32(fieldNumber, value); + } +- for (final long value : fixed64) { ++ for (long value : fixed64) { + output.writeFixed64(fieldNumber, value); + } +- for (final ByteString value : lengthDelimited) { ++ for (ByteString value : lengthDelimited) { + output.writeBytes(fieldNumber, value); + } +- for (final UnknownFieldSet value : group) { ++ for (UnknownFieldSet value : group) { + output.writeGroup(fieldNumber, value); + } + } + + /** Get the number of bytes required to encode this field, including field number. */ +- public int getSerializedSize(final int fieldNumber) { ++ public int getSerializedSize(int fieldNumber) { + int result = 0; +- for (final long value : varint) { ++ for (long value : varint) { + result += CodedOutputStream.computeUInt64Size(fieldNumber, value); + } +- for (final int value : fixed32) { ++ for (int value : fixed32) { + result += CodedOutputStream.computeFixed32Size(fieldNumber, value); + } +- for (final long value : fixed64) { ++ for (long value : fixed64) { + result += CodedOutputStream.computeFixed64Size(fieldNumber, value); + } +- for (final ByteString value : lengthDelimited) { ++ for (ByteString value : lengthDelimited) { + result += CodedOutputStream.computeBytesSize(fieldNumber, value); + } +- for (final UnknownFieldSet value : group) { ++ for (UnknownFieldSet value : group) { + result += CodedOutputStream.computeGroupSize(fieldNumber, value); + } + return result; +@@ -839,15 +809,15 @@ public final class UnknownFieldSet imple + * Serializes the field, including field number, and writes it to {@code output}, using {@code + * MessageSet} wire format. + */ +- public void writeAsMessageSetExtensionTo(final int fieldNumber, final CodedOutputStream output) ++ public void writeAsMessageSetExtensionTo(int fieldNumber, CodedOutputStream output) + throws IOException { +- for (final ByteString value : lengthDelimited) { ++ for (ByteString value : lengthDelimited) { + output.writeRawMessageSetExtension(fieldNumber, value); + } + } + + /** Serializes the field, including field number, and writes it to {@code writer}. */ +- void writeTo(final int fieldNumber, final Writer writer) throws IOException { ++ void writeTo(int fieldNumber, Writer writer) throws IOException { + writer.writeInt64List(fieldNumber, varint, false); + writer.writeFixed32List(fieldNumber, fixed32, false); + writer.writeFixed64List(fieldNumber, fixed64, false); +@@ -872,7 +842,7 @@ public final class UnknownFieldSet imple + * Serializes the field, including field number, and writes it to {@code writer}, using {@code + * MessageSet} wire format. + */ +- private void writeAsMessageSetExtensionTo(final int fieldNumber, final Writer writer) ++ private void writeAsMessageSetExtensionTo(int fieldNumber, Writer writer) + throws IOException { + if (writer.fieldOrder() == Writer.FieldOrder.DESCENDING) { + // Write in descending field order. +@@ -882,7 +852,7 @@ public final class UnknownFieldSet imple + } + } else { + // Write in ascending field order. +- for (final ByteString value : lengthDelimited) { ++ for (ByteString value : lengthDelimited) { + writer.writeMessageSetItem(fieldNumber, value); + } + } +@@ -892,9 +862,9 @@ public final class UnknownFieldSet imple + * Get the number of bytes required to encode this field, including field number, using {@code + * MessageSet} wire format. + */ +- public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) { ++ public int getSerializedSizeAsMessageSetExtension(int fieldNumber) { + int result = 0; +- for (final ByteString value : lengthDelimited) { ++ for (ByteString value : lengthDelimited) { + result += CodedOutputStream.computeRawMessageSetExtensionSize(fieldNumber, value); + } + return result; +@@ -912,52 +882,85 @@ public final class UnknownFieldSet imple + *

Use {@link Field#newBuilder()} to construct a {@code Builder}. + */ + public static final class Builder { +- // This constructor should never be called directly (except from 'create'). +- private Builder() {} ++ // This constructor should only be called directly from 'create' and 'clone'. ++ private Builder() { ++ result = new Field(); ++ } + + private static Builder create() { + Builder builder = new Builder(); +- builder.result = new Field(); + return builder; + } + + private Field result; + ++ @Override ++ public Builder clone() { ++ Field copy = new Field(); ++ if (result.varint == null) { ++ copy.varint = null; ++ } else { ++ copy.varint = new ArrayList<>(result.varint); ++ } ++ if (result.fixed32 == null) { ++ copy.fixed32 = null; ++ } else { ++ copy.fixed32 = new ArrayList<>(result.fixed32); ++ } ++ if (result.fixed64 == null) { ++ copy.fixed64 = null; ++ } else { ++ copy.fixed64 = new ArrayList<>(result.fixed64); ++ } ++ if (result.lengthDelimited == null) { ++ copy.lengthDelimited = null; ++ } else { ++ copy.lengthDelimited = new ArrayList<>(result.lengthDelimited); ++ } ++ if (result.group == null) { ++ copy.group = null; ++ } else { ++ copy.group = new ArrayList<>(result.group); ++ } ++ ++ Builder clone = new Builder(); ++ clone.result = copy; ++ return clone; ++ } ++ + /** +- * Build the field. After {@code build()} has been called, the {@code Builder} is no longer +- * usable. Calling any other method will result in undefined behavior and can cause a {@code +- * NullPointerException} to be thrown. ++ * Build the field. + */ + public Field build() { ++ Field built = new Field(); + if (result.varint == null) { +- result.varint = Collections.emptyList(); ++ built.varint = Collections.emptyList(); + } else { +- result.varint = Collections.unmodifiableList(result.varint); ++ built.varint = Collections.unmodifiableList(new ArrayList<>(result.varint)); + } + if (result.fixed32 == null) { +- result.fixed32 = Collections.emptyList(); ++ built.fixed32 = Collections.emptyList(); + } else { +- result.fixed32 = Collections.unmodifiableList(result.fixed32); ++ built.fixed32 = Collections.unmodifiableList(new ArrayList<>(result.fixed32)); + } + if (result.fixed64 == null) { +- result.fixed64 = Collections.emptyList(); ++ built.fixed64 = Collections.emptyList(); + } else { +- result.fixed64 = Collections.unmodifiableList(result.fixed64); ++ built.fixed64 = Collections.unmodifiableList(new ArrayList<>(result.fixed64)); + } + if (result.lengthDelimited == null) { +- result.lengthDelimited = Collections.emptyList(); ++ built.lengthDelimited = Collections.emptyList(); + } else { +- result.lengthDelimited = Collections.unmodifiableList(result.lengthDelimited); ++ built.lengthDelimited = Collections.unmodifiableList( ++ new ArrayList<>(result.lengthDelimited)); + } + if (result.group == null) { +- result.group = Collections.emptyList(); ++ built.group = Collections.emptyList(); + } else { +- result.group = Collections.unmodifiableList(result.group); ++ built.group = Collections.unmodifiableList(new ArrayList<>(result.group)); + } + +- final Field returnMe = result; +- result = null; +- return returnMe; ++ return built; + } + + /** Discard the field's contents. */ +@@ -970,7 +973,7 @@ public final class UnknownFieldSet imple + * Merge the values in {@code other} into this field. For each list of values, {@code other}'s + * values are append to the ones in this field. + */ +- public Builder mergeFrom(final Field other) { ++ public Builder mergeFrom(Field other) { + if (!other.varint.isEmpty()) { + if (result.varint == null) { + result.varint = new ArrayList(); +@@ -985,19 +988,19 @@ public final class UnknownFieldSet imple + } + if (!other.fixed64.isEmpty()) { + if (result.fixed64 == null) { +- result.fixed64 = new ArrayList(); ++ result.fixed64 = new ArrayList<>(); + } + result.fixed64.addAll(other.fixed64); + } + if (!other.lengthDelimited.isEmpty()) { + if (result.lengthDelimited == null) { +- result.lengthDelimited = new ArrayList(); ++ result.lengthDelimited = new ArrayList<>(); + } + result.lengthDelimited.addAll(other.lengthDelimited); + } + if (!other.group.isEmpty()) { + if (result.group == null) { +- result.group = new ArrayList(); ++ result.group = new ArrayList<>(); + } + result.group.addAll(other.group); + } +@@ -1005,45 +1008,45 @@ public final class UnknownFieldSet imple + } + + /** Add a varint value. */ +- public Builder addVarint(final long value) { ++ public Builder addVarint(long value) { + if (result.varint == null) { +- result.varint = new ArrayList(); ++ result.varint = new ArrayList<>(); + } + result.varint.add(value); + return this; + } + + /** Add a fixed32 value. */ +- public Builder addFixed32(final int value) { ++ public Builder addFixed32(int value) { + if (result.fixed32 == null) { +- result.fixed32 = new ArrayList(); ++ result.fixed32 = new ArrayList<>(); + } + result.fixed32.add(value); + return this; + } + + /** Add a fixed64 value. */ +- public Builder addFixed64(final long value) { ++ public Builder addFixed64(long value) { + if (result.fixed64 == null) { +- result.fixed64 = new ArrayList(); ++ result.fixed64 = new ArrayList<>(); + } + result.fixed64.add(value); + return this; + } + + /** Add a length-delimited value. */ +- public Builder addLengthDelimited(final ByteString value) { ++ public Builder addLengthDelimited(ByteString value) { + if (result.lengthDelimited == null) { +- result.lengthDelimited = new ArrayList(); ++ result.lengthDelimited = new ArrayList<>(); + } + result.lengthDelimited.add(value); + return this; + } + + /** Add an embedded group. */ +- public Builder addGroup(final UnknownFieldSet value) { ++ public Builder addGroup(UnknownFieldSet value) { + if (result.group == null) { +- result.group = new ArrayList(); ++ result.group = new ArrayList<>(); + } + result.group.add(value); + return this; +--- protobuf-3.12.4.orig/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java ++++ protobuf-3.12.4/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java +@@ -58,7 +58,7 @@ public class UnknownFieldSetTest extends + unknownFields = emptyMessage.getUnknownFields(); + } + +- UnknownFieldSet.Field getField(String name) { ++ private UnknownFieldSet.Field getField(String name) { + Descriptors.FieldDescriptor field = descriptor.findFieldByName(name); + assertNotNull(field); + return unknownFields.getField(field.getNumber()); diff -Nru protobuf-3.12.4/debian/patches/CVE-2021-22570.patch protobuf-3.12.4/debian/patches/CVE-2021-22570.patch --- protobuf-3.12.4/debian/patches/CVE-2021-22570.patch 1970-01-01 00:00:00.000000000 +0000 +++ protobuf-3.12.4/debian/patches/CVE-2021-22570.patch 2023-03-06 12:13:20.000000000 +0000 @@ -0,0 +1,43 @@ +From a00125024e9231d76746bd394fef8876f5cc15e2 Mon Sep 17 00:00:00 2001 +From: Deanna Garcia +Date: Fri, 22 Jan 2021 00:24:30 +0000 +Subject: [PATCH] Sync from Piper @353127564 +--- protobuf-3.12.4.orig/src/google/protobuf/descriptor.cc ++++ protobuf-3.12.4/src/google/protobuf/descriptor.cc +@@ -4034,6 +4034,11 @@ bool DescriptorBuilder::AddSymbol(const + // Use its file as the parent instead. + if (parent == nullptr) parent = file_; + ++ if (full_name.find('\0') != std::string::npos) { ++ AddError(full_name, proto, DescriptorPool::ErrorCollector::NAME, ++ "\"" + full_name + "\" contains null character."); ++ return false; ++ } + if (tables_->AddSymbol(full_name, symbol)) { + if (!file_tables_->AddAliasUnderParent(parent, name, symbol)) { + // This is only possible if there was already an error adding something of +@@ -4073,6 +4078,11 @@ bool DescriptorBuilder::AddSymbol(const + void DescriptorBuilder::AddPackage(const std::string& name, + const Message& proto, + const FileDescriptor* file) { ++ if (name.find('\0') != std::string::npos) { ++ AddError(name, proto, DescriptorPool::ErrorCollector::NAME, ++ "\"" + name + "\" contains null character."); ++ return; ++ } + if (tables_->AddSymbol(name, Symbol(file))) { + // Success. Also add parent package, if any. + std::string::size_type dot_pos = name.find_last_of('.'); +@@ -4386,6 +4396,12 @@ FileDescriptor* DescriptorBuilder::Build + } + result->pool_ = pool_; + ++ if (result->name().find('\0') != std::string::npos) { ++ AddError(result->name(), proto, DescriptorPool::ErrorCollector::NAME, ++ "\"" + result->name() + "\" contains null character."); ++ return NULL; ++ } ++ + // Add to tables. + if (!tables_->AddFile(result)) { + AddError(proto.name(), proto, DescriptorPool::ErrorCollector::OTHER, diff -Nru protobuf-3.12.4/debian/patches/CVE-2022-1941.patch protobuf-3.12.4/debian/patches/CVE-2022-1941.patch --- protobuf-3.12.4/debian/patches/CVE-2022-1941.patch 1970-01-01 00:00:00.000000000 +0000 +++ protobuf-3.12.4/debian/patches/CVE-2022-1941.patch 2023-03-06 12:24:45.000000000 +0000 @@ -0,0 +1,137 @@ +[Canonical note: File wire_format_unittest.inc doesnt exist in 3.11.2, thats +why removed the patch replated to unittest.inc. File wire_format.cc also +doesnt contain the vulnerable code, so skiiping the part.] + +From b4c395aaedfacb32e2414d361fa85968c0991b34 Mon Sep 17 00:00:00 2001 +From: Deanna Garcia +Date: Tue, 13 Sep 2022 16:35:58 +0000 +Subject: [PATCH] Apply patch + +--- + src/google/protobuf/extension_set_inl.h | 27 +++-- + src/google/protobuf/wire_format.cc | 26 +++-- + src/google/protobuf/wire_format_lite.h | 27 +++-- + src/google/protobuf/wire_format_unittest.inc | 104 +++++++++++++++++-- + 4 files changed, 149 insertions(+), 35 deletions(-) + +--- protobuf-3.12.4.orig/src/google/protobuf/extension_set_inl.h ++++ protobuf-3.12.4/src/google/protobuf/extension_set_inl.h +@@ -206,15 +206,20 @@ const char* ExtensionSet::ParseMessageSe + const char* ptr, const Msg* containing_type, + internal::InternalMetadata* metadata, internal::ParseContext* ctx) { + std::string payload; +- uint32 type_id = 0; ++ uint32 type_id; ++ enum class State { kNoTag, kHasType, kHasPayload, kDone }; ++ State state = State::kNoTag; + while (!ctx->Done(&ptr)) { + uint32 tag = static_cast(*ptr++); + if (tag == WireFormatLite::kMessageSetTypeIdTag) { + uint64 tmp; + ptr = ParseBigVarint(ptr, &tmp); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); +- type_id = tmp; +- if (!payload.empty()) { ++ if (state == State::kNoTag) { ++ type_id = tmp; ++ state = State::kHasType; ++ } else if (state == State::kHasPayload) { ++ type_id = tmp; + ExtensionInfo extension; + bool was_packed_on_wire; + if (!FindExtension(2, type_id, containing_type, ctx, &extension, +@@ -240,19 +245,24 @@ const char* ExtensionSet::ParseMessageSe + GOOGLE_PROTOBUF_PARSER_ASSERT(value->_InternalParse(p, &tmp_ctx) && + tmp_ctx.EndedAtLimit()); + } +- type_id = 0; ++ state = State::kDone; + } + } else if (tag == WireFormatLite::kMessageSetMessageTag) { +- if (type_id != 0) { ++ if (state == State::kHasType) { + ptr = ParseFieldMaybeLazily(static_cast(type_id) * 8 + 2, ptr, + containing_type, metadata, ctx); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr != nullptr); +- type_id = 0; ++ state = State::kDone; + } else { ++ std::string tmp; + int32 size = ReadSize(&ptr); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); +- ptr = ctx->ReadString(ptr, size, &payload); ++ ptr = ctx->ReadString(ptr, size, &tmp); + GOOGLE_PROTOBUF_PARSER_ASSERT(ptr); ++ if (state == State::kNoTag) { ++ payload = std::move(tmp); ++ state = State::kHasPayload; ++ } + } + } else { + ptr = ReadTag(ptr - 1, &tag); +--- protobuf-3.12.4.orig/src/google/protobuf/wire_format_lite.h ++++ protobuf-3.12.4/src/google/protobuf/wire_format_lite.h +@@ -1798,6 +1798,9 @@ bool ParseMessageSetItemImpl(io::CodedIn + // we can parse it later. + std::string message_data; + ++ enum class State { kNoTag, kHasType, kHasPayload, kDone }; ++ State state = State::kNoTag; ++ + while (true) { + const uint32 tag = input->ReadTagNoLastTag(); + if (tag == 0) return false; +@@ -1806,26 +1809,34 @@ bool ParseMessageSetItemImpl(io::CodedIn + case WireFormatLite::kMessageSetTypeIdTag: { + uint32 type_id; + if (!input->ReadVarint32(&type_id)) return false; +- last_type_id = type_id; +- +- if (!message_data.empty()) { ++ if (state == State::kNoTag) { ++ last_type_id = type_id; ++ state = State::kHasType; ++ } else if (state == State::kHasPayload) { + // We saw some message data before the type_id. Have to parse it + // now. + io::CodedInputStream sub_input( + reinterpret_cast(message_data.data()), + static_cast(message_data.size())); + sub_input.SetRecursionLimit(input->RecursionBudget()); +- if (!ms.ParseField(last_type_id, &sub_input)) { ++ if (!ms.ParseField(type_id, &sub_input)) { + return false; + } + message_data.clear(); ++ state = State::kDone; + } + + break; + } + + case WireFormatLite::kMessageSetMessageTag: { +- if (last_type_id == 0) { ++ if (state == State::kHasType) { ++ // Already saw type_id, so we can parse this directly. ++ if (!ms.ParseField(last_type_id, input)) { ++ return false; ++ } ++ state = State::kDone; ++ } else if (state == State::kNoTag) { + // We haven't seen a type_id yet. Append this data to message_data. + uint32 length; + if (!input->ReadVarint32(&length)) return false; +@@ -1836,11 +1847,9 @@ bool ParseMessageSetItemImpl(io::CodedIn + auto ptr = reinterpret_cast(&message_data[0]); + ptr = io::CodedOutputStream::WriteVarint32ToArray(length, ptr); + if (!input->ReadRaw(ptr, length)) return false; ++ state = State::kHasPayload; + } else { +- // Already saw type_id, so we can parse this directly. +- if (!ms.ParseField(last_type_id, input)) { +- return false; +- } ++ if (!ms.SkipField(tag, input)) return false; + } + + break; diff -Nru protobuf-3.12.4/debian/patches/series protobuf-3.12.4/debian/patches/series --- protobuf-3.12.4/debian/patches/series 2020-05-09 18:45:17.000000000 +0000 +++ protobuf-3.12.4/debian/patches/series 2023-03-09 09:35:50.000000000 +0000 @@ -9,3 +9,7 @@ 32bit.patch python3ify_examples.patch no_errorprone.patch +0001-Fix-Python-3.10-C-tests-9128.patch +CVE-2021-22569.patch +CVE-2021-22570.patch +CVE-2022-1941.patch diff -Nru protobuf-3.12.4/debian/rules protobuf-3.12.4/debian/rules --- protobuf-3.12.4/debian/rules 2021-10-09 20:57:00.000000000 +0000 +++ protobuf-3.12.4/debian/rules 2023-07-11 08:11:34.000000000 +0000 @@ -57,7 +57,7 @@ # Generate the manpage xmlto man debian/protoc.xml - # Python and Python3 build. + # Python and Python3 build cp -rv python python3 set -e; cd python && for pv in $(shell pyversions -vr); do \ $(PYTHON_CROSS_VARS) python$$pv setup.py build --cpp_implementation; \ @@ -102,7 +102,7 @@ endif ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - # Python test. + # Python test set -e; \ export LD_LIBRARY_PATH=$(CURDIR)/src/.libs; \ cd python && for PYTHON in $(shell pyversions -r); do \ @@ -122,7 +122,7 @@ override_dh_auto_clean-arch: dh_auto_clean --arch - # Python clean. + # Python clean set -e; \ cd python && for python in $(shell pyversions -r); do \ $$python setup.py clean --all; \ @@ -141,7 +141,7 @@ override_dh_auto_install-arch: dh_auto_install --arch - # Python install. + # Python install set -e; \ cd python && for pv in $(shell pyversions -vr); do \ $(PYTHON_CROSS_VARS) python$$pv setup.py install --cpp_implementation \ diff -Nru protobuf-3.12.4/debian/tests/control protobuf-3.12.4/debian/tests/control --- protobuf-3.12.4/debian/tests/control 2020-08-05 00:34:01.000000000 +0000 +++ protobuf-3.12.4/debian/tests/control 2021-01-17 03:13:24.000000000 +0000 @@ -1,3 +1,3 @@ Tests: simple -Depends: @, make, python, python3, pkg-config, zlib1g-dev, build-essential, default-jdk +Depends: @, make, python3, pkg-config, zlib1g-dev, build-essential, default-jdk Restrictions: allow-stderr