Merge release branch 22.x into main
diff --git a/.github/actions/bazel/action.yml b/.github/actions/bazel/action.yml
index 141527d..5fd3e9a 100644
--- a/.github/actions/bazel/action.yml
+++ b/.github/actions/bazel/action.yml
@@ -93,6 +93,29 @@
shell: bash
run: bazelisk version
+ # Bazel has multiple Xcode calls with hardcoded timeouts. Many of these
+ # end up timing out on our github runners, causing flakes on every mac
+ # build that invoked Bazel. To work around this, we manually inoke these
+ # calls before running Bazel to make sure they end up in Xcode's cache for
+ # quicker runs later. All of these calls are obtained from xcrun calls in
+ # https://github.com/bazelbuild/bazel/blob/e8a69f5d5acaeb6af760631490ecbf73e8a04eeb/tools/cpp/osx_cc_configure.bzl.
+ # See https://github.com/bazelbuild/bazel/issues/17437 for more details.
+ # TODO(b/269503614) Remove this once Bazel provides an official solution.
+ - name: Warm up Xcode
+ if: ${{ runner.os == 'macOS' }}
+ shell: bash
+ run: |
+ mkdir -p mac_bazel_workaround
+ bazelisk ${{ steps.bazel.outputs.bazel-startup-flags }} build @bazel_tools//tools/osx:xcode_locator.m $BAZEL_FLAGS
+ XCODE_LOCATOR_FLAGS="--sdk macosx clang -mmacosx-version-min=10.9 -fobjc-arc -framework CoreServices -framework Foundation"
+ SINGLE_ARCH_COMPILE_FLAGS="--sdk macosx clang -mmacosx-version-min=10.9 -std=c++11 -lc++ -O3"
+ COMPILE_FLAGS="$SINGLE_ARCH_COMPILE_FLAGS -arch arm64 -arch x86_64 -Wl,-no_adhoc_codesign -Wl,-no_uuid -O3"
+ time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $XCODE_LOCATOR_FLAGS -o mac_bazel_workaround/xcode-locator-bin $(bazel info output_base)/external/bazel_tools/tools/osx/xcode_locator.m
+ time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $SINGLE_ARCH_COMPILE_FLAGS -o mac_bazel_workaround/libtool_check_unique $(bazel info output_base)/external/bazel_tools/tools/objc/libtool_check_unique.cc
+ time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $COMPILE_FLAGS -o mac_bazel_workaround/libtool_check_unique $(bazel info output_base)/external/bazel_tools/tools/objc/libtool_check_unique.cc
+ time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $SINGLE_ARCH_COMPILE_FLAGS -o mac_bazel_workaround/wrapped_clang $(bazel info output_base)/external/bazel_tools/tools/osx/crosstool/wrapped_clang.cc
+ time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $COMPILE_FLAGS -o mac_bazel_workaround/wrapped_clang $(bazel info output_base)/external/bazel_tools/tools/osx/crosstool/wrapped_clang.cc
+
- name: Run Bash
if: ${{ inputs.bash }}
run: ${{ inputs.bash }}
diff --git a/.github/actions/internal/bazel-setup/action.yml b/.github/actions/internal/bazel-setup/action.yml
index 20e7241..0ef5d5a 100644
--- a/.github/actions/internal/bazel-setup/action.yml
+++ b/.github/actions/internal/bazel-setup/action.yml
@@ -42,7 +42,9 @@
- name: Initialize MacOS-specific Bazel flags
if: runner.os == 'macOS'
shell: bash
- run: echo "BAZEL_FLAGS=$BAZEL_FLAGS --xcode_version_config=//.github:host_xcodes" >> $GITHUB_ENV
+ run: |
+ echo "BAZEL_FLAGS=$BAZEL_FLAGS --xcode_version_config=//.github:host_xcodes" >> $GITHUB_ENV
+ echo "DEVELOPER_DIR=${{ env.DEVELOPER_DIR || '/Applications/Xcode_14.1.app/Contents/Developer' }}" >> $GITHUB_ENV
- name: Configure Bazel caching
# Skip bazel cache for local act runs due to issue with credential files
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index e17f174..26b4a32 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -2,7 +2,16 @@
# https://github.com/codespell-project/actions-codespell
# https://github.com/codespell-project/codespell
name: codespell
-on: [push, pull_request]
+on:
+ push:
+ branches:
+ - main
+ - '[0-9]+.x'
+ pull_request:
+ branches:
+ - main
+ - '[0-9]+.x'
+
permissions:
contents: read # to fetch code (actions/checkout)
jobs:
diff --git a/.github/workflows/test_runner.yml b/.github/workflows/test_runner.yml
index a99d090..9fa37f1 100644
--- a/.github/workflows/test_runner.yml
+++ b/.github/workflows/test_runner.yml
@@ -41,7 +41,7 @@
branches:
- main
- '[0-9]+.x'
- # The 21.x branch still uses Kokoro
+ # The 21.x branch still use Kokoro
- '!21.x'
# For testing purposes so we can stage this on the `gha` branch.
- gha
diff --git a/README.md b/README.md
index 3bfeb0f..c84ab2b 100644
--- a/README.md
+++ b/README.md
@@ -3,14 +3,12 @@
Copyright 2008 Google Inc.
-[Protocol Buffers documentation](https://developers.google.com/protocol-buffers/)
-
Overview
--------
Protocol Buffers (a.k.a., protobuf) are Google's language-neutral,
platform-neutral, extensible mechanism for serializing structured data. You
-can find [protobuf's documentation on the Google Developers site](https://developers.google.com/protocol-buffers/).
+can learn more about it in [protobuf's documentation](https://protobuf.dev).
This README file contains protobuf installation instructions. To install
protobuf, you need to install the protocol compiler (used to compile .proto
@@ -64,7 +62,7 @@
-----------
The best way to learn how to use protobuf is to follow the [tutorials in our
-developer guide](https://developers.google.com/protocol-buffers/docs/tutorials).
+developer guide](https://protobuf.dev/getting-started).
If you want to learn from code examples, take a look at the examples in the
[examples](examples) directory.
@@ -72,11 +70,16 @@
Documentation
-------------
-The complete documentation is available via the [Protocol Buffers documentation](https://developers.google.com/protocol-buffers/).
+The complete documentation is available at the [Protocol Buffers doc site](https://protobuf.dev).
+
+Support Policy
+--------------
+
+Read about our [version support policy](https://protobuf.dev/version-support/)
+to stay current on support timeframes for the language libraries.
Developer Community
-------------------
To be alerted to upcoming changes in Protocol Buffers and connect with protobuf developers and users,
[join the Google Group](https://groups.google.com/g/protobuf).
-
diff --git a/csharp/BUILD.bazel b/csharp/BUILD.bazel
index 23fbe41..2af7d06 100644
--- a/csharp/BUILD.bazel
+++ b/csharp/BUILD.bazel
@@ -65,9 +65,11 @@
srcs = [
":srcs",
"src/Google.Protobuf.sln",
+ "//conformance:conformance_csharp_proto",
"//csharp/src/Google.Protobuf.Conformance:srcs",
],
cmd = """
+ cp $(rootpath //conformance:conformance_csharp_proto) `dirname $(location src/Google.Protobuf.sln)`/Google.Protobuf.Conformance/
pushd `dirname $(location src/Google.Protobuf.sln)`/..
dotnet restore src/Google.Protobuf.sln
dotnet build -c Release src/Google.Protobuf.sln
diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh
index cd682c2..17b1640 100755
--- a/csharp/generate_protos.sh
+++ b/csharp/generate_protos.sh
@@ -79,3 +79,8 @@
$PROTOC -Iexamples -Isrc --csharp_out=csharp/src/AddressBook \
--csharp_opt=file_extension=.pb.cs \
examples/addressbook.proto
+
+# Conformance tests
+$PROTOC -I. --csharp_out=csharp/src/Google.Protobuf.Conformance \
+ --csharp_opt=file_extension=.pb.cs \
+ conformance/conformance.proto
diff --git a/csharp/src/Google.Protobuf.Conformance/BUILD.bazel b/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
index 12ad0f7..0b5e2c8 100644
--- a/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
+++ b/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
@@ -1,3 +1,4 @@
+load("//:protobuf.bzl", "internal_csharp_proto_library")
load("//build_defs:internal_shell.bzl", "inline_sh_binary")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
@@ -37,7 +38,6 @@
filegroup(
name = "srcs",
srcs = [
- "Conformance.cs",
"Program.cs",
"Google.Protobuf.Conformance.csproj",
],
@@ -88,7 +88,6 @@
srcs = [
"BUILD.bazel",
"Google.Protobuf.Conformance.csproj",
- "Conformance.cs",
"Program.cs",
],
strip_prefix = strip_prefix.from_root(""),
diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
similarity index 93%
rename from csharp/src/Google.Protobuf.Conformance/Conformance.cs
rename to csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
index 77fd9c9..664a17b 100644
--- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs
+++ b/csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
@@ -1,6 +1,6 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: conformance.proto
+// source: conformance/conformance.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021, 8981
#region Designer generated code
@@ -11,11 +11,11 @@
using scg = global::System.Collections.Generic;
namespace Conformance {
- /// <summary>Holder for reflection information generated from conformance.proto</summary>
+ /// <summary>Holder for reflection information generated from conformance/conformance.proto</summary>
public static partial class ConformanceReflection {
#region Descriptor
- /// <summary>File descriptor for conformance.proto</summary>
+ /// <summary>File descriptor for conformance/conformance.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
@@ -24,34 +24,35 @@
static ConformanceReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UiHQoKRmFpbHVyZVNl",
- "dBIPCgdmYWlsdXJlGAEgAygJIuMCChJDb25mb3JtYW5jZVJlcXVlc3QSGgoQ",
- "cHJvdG9idWZfcGF5bG9hZBgBIAEoDEgAEhYKDGpzb25fcGF5bG9hZBgCIAEo",
- "CUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9hZBgI",
- "IAEoCUgAEjgKF3JlcXVlc3RlZF9vdXRwdXRfZm9ybWF0GAMgASgOMhcuY29u",
- "Zm9ybWFuY2UuV2lyZUZvcm1hdBIUCgxtZXNzYWdlX3R5cGUYBCABKAkSMAoN",
- "dGVzdF9jYXRlZ29yeRgFIAEoDjIZLmNvbmZvcm1hbmNlLlRlc3RDYXRlZ29y",
- "eRI+ChVqc3BiX2VuY29kaW5nX29wdGlvbnMYBiABKAsyHy5jb25mb3JtYW5j",
- "ZS5Kc3BiRW5jb2RpbmdDb25maWcSHAoUcHJpbnRfdW5rbm93bl9maWVsZHMY",
- "CSABKAhCCQoHcGF5bG9hZCLhAQoTQ29uZm9ybWFuY2VSZXNwb25zZRIVCgtw",
- "YXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6ZV9lcnJvchgGIAEoCUgA",
- "EhcKDXJ1bnRpbWVfZXJyb3IYAiABKAlIABIaChBwcm90b2J1Zl9wYXlsb2Fk",
- "GAMgASgMSAASFgoManNvbl9wYXlsb2FkGAQgASgJSAASEQoHc2tpcHBlZBgF",
- "IAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9h",
- "ZBgIIAEoCUgAQggKBnJlc3VsdCI3ChJKc3BiRW5jb2RpbmdDb25maWcSIQoZ",
- "dXNlX2pzcGJfYXJyYXlfYW55X2Zvcm1hdBgBIAEoCCpQCgpXaXJlRm9ybWF0",
- "Eg8KC1VOU1BFQ0lGSUVEEAASDAoIUFJPVE9CVUYQARIICgRKU09OEAISCAoE",
- "SlNQQhADEg8KC1RFWFRfRk9STUFUEAQqjwEKDFRlc3RDYXRlZ29yeRIUChBV",
- "TlNQRUNJRklFRF9URVNUEAASDwoLQklOQVJZX1RFU1QQARINCglKU09OX1RF",
- "U1QQAhIkCiBKU09OX0lHTk9SRV9VTktOT1dOX1BBUlNJTkdfVEVTVBADEg0K",
- "CUpTUEJfVEVTVBAEEhQKEFRFWFRfRk9STUFUX1RFU1QQBUIhCh9jb20uZ29v",
- "Z2xlLnByb3RvYnVmLmNvbmZvcm1hbmNlYgZwcm90bzM="));
+ "Ch1jb25mb3JtYW5jZS9jb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2Ui",
+ "HQoKRmFpbHVyZVNldBIPCgdmYWlsdXJlGAEgAygJIuMCChJDb25mb3JtYW5j",
+ "ZVJlcXVlc3QSGgoQcHJvdG9idWZfcGF5bG9hZBgBIAEoDEgAEhYKDGpzb25f",
+ "cGF5bG9hZBgCIAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRl",
+ "eHRfcGF5bG9hZBgIIAEoCUgAEjgKF3JlcXVlc3RlZF9vdXRwdXRfZm9ybWF0",
+ "GAMgASgOMhcuY29uZm9ybWFuY2UuV2lyZUZvcm1hdBIUCgxtZXNzYWdlX3R5",
+ "cGUYBCABKAkSMAoNdGVzdF9jYXRlZ29yeRgFIAEoDjIZLmNvbmZvcm1hbmNl",
+ "LlRlc3RDYXRlZ29yeRI+ChVqc3BiX2VuY29kaW5nX29wdGlvbnMYBiABKAsy",
+ "Hy5jb25mb3JtYW5jZS5Kc3BiRW5jb2RpbmdDb25maWcSHAoUcHJpbnRfdW5r",
+ "bm93bl9maWVsZHMYCSABKAhCCQoHcGF5bG9hZCL6AQoTQ29uZm9ybWFuY2VS",
+ "ZXNwb25zZRIVCgtwYXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6ZV9l",
+ "cnJvchgGIAEoCUgAEhcKDXRpbWVvdXRfZXJyb3IYCSABKAlIABIXCg1ydW50",
+ "aW1lX2Vycm9yGAIgASgJSAASGgoQcHJvdG9idWZfcGF5bG9hZBgDIAEoDEgA",
+ "EhYKDGpzb25fcGF5bG9hZBgEIAEoCUgAEhEKB3NraXBwZWQYBSABKAlIABIW",
+ "Cgxqc3BiX3BheWxvYWQYByABKAlIABIWCgx0ZXh0X3BheWxvYWQYCCABKAlI",
+ "AEIICgZyZXN1bHQiNwoSSnNwYkVuY29kaW5nQ29uZmlnEiEKGXVzZV9qc3Bi",
+ "X2FycmF5X2FueV9mb3JtYXQYASABKAgqUAoKV2lyZUZvcm1hdBIPCgtVTlNQ",
+ "RUNJRklFRBAAEgwKCFBST1RPQlVGEAESCAoESlNPThACEggKBEpTUEIQAxIP",
+ "CgtURVhUX0ZPUk1BVBAEKo8BCgxUZXN0Q2F0ZWdvcnkSFAoQVU5TUEVDSUZJ",
+ "RURfVEVTVBAAEg8KC0JJTkFSWV9URVNUEAESDQoJSlNPTl9URVNUEAISJAog",
+ "SlNPTl9JR05PUkVfVU5LTk9XTl9QQVJTSU5HX1RFU1QQAxINCglKU1BCX1RF",
+ "U1QQBBIUChBURVhUX0ZPUk1BVF9URVNUEAVCLwofY29tLmdvb2dsZS5wcm90",
+ "b2J1Zi5jb25mb3JtYW5jZaICC0NvbmZvcm1hbmNlYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.TestCategory), }, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.FailureSet), global::Conformance.FailureSet.Parser, new[]{ "Failure" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "JspbPayload", "TextPayload", "RequestedOutputFormat", "MessageType", "TestCategory", "JspbEncodingOptions", "PrintUnknownFields" }, new[]{ "Payload" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped", "JspbPayload", "TextPayload" }, new[]{ "Result" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "TimeoutError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped", "JspbPayload", "TextPayload" }, new[]{ "Result" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.JspbEncodingConfig), global::Conformance.JspbEncodingConfig.Parser, new[]{ "UseJspbArrayAnyFormat" }, null, null, null, null)
}));
}
@@ -89,7 +90,8 @@
/// </summary>
[pbr::OriginalName("JSON_IGNORE_UNKNOWN_PARSING_TEST")] JsonIgnoreUnknownParsingTest = 3,
/// <summary>
- /// Test jspb wire format. Only used inside Google. Opensource testees just skip it.
+ /// Test jspb wire format. Only used inside Google. Opensource testees just
+ /// skip it.
/// </summary>
[pbr::OriginalName("JSPB_TEST")] JspbTest = 4,
/// <summary>
@@ -382,7 +384,7 @@
/// <summary>Field number for the "jspb_payload" field.</summary>
public const int JspbPayloadFieldNumber = 7;
/// <summary>
- /// Only used inside google. Opensource testees just skip it.
+ /// Only used inside Google. Opensource testees just skip it.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -443,8 +445,8 @@
private global::Conformance.TestCategory testCategory_ = global::Conformance.TestCategory.UnspecifiedTest;
/// <summary>
/// Each test is given a specific test category. Some category may need
- /// specific support in testee programs. Refer to the definition of TestCategory
- /// for more information.
+ /// specific support in testee programs. Refer to the definition of
+ /// TestCategory for more information.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -892,6 +894,9 @@
case ResultOneofCase.SerializeError:
SerializeError = other.SerializeError;
break;
+ case ResultOneofCase.TimeoutError:
+ TimeoutError = other.TimeoutError;
+ break;
case ResultOneofCase.RuntimeError:
RuntimeError = other.RuntimeError;
break;
@@ -957,6 +962,23 @@
}
}
+ /// <summary>Field number for the "timeout_error" field.</summary>
+ public const int TimeoutErrorFieldNumber = 9;
+ /// <summary>
+ /// This should be set if the test program timed out. The string should
+ /// provide more information about what the child process was doing when it
+ /// was killed.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string TimeoutError {
+ get { return resultCase_ == ResultOneofCase.TimeoutError ? (string) result_ : ""; }
+ set {
+ result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ resultCase_ = ResultOneofCase.TimeoutError;
+ }
+ }
+
/// <summary>Field number for the "runtime_error" field.</summary>
public const int RuntimeErrorFieldNumber = 2;
/// <summary>
@@ -1061,6 +1083,7 @@
None = 0,
ParseError = 1,
SerializeError = 6,
+ TimeoutError = 9,
RuntimeError = 2,
ProtobufPayload = 3,
JsonPayload = 4,
@@ -1099,6 +1122,7 @@
}
if (ParseError != other.ParseError) return false;
if (SerializeError != other.SerializeError) return false;
+ if (TimeoutError != other.TimeoutError) return false;
if (RuntimeError != other.RuntimeError) return false;
if (ProtobufPayload != other.ProtobufPayload) return false;
if (JsonPayload != other.JsonPayload) return false;
@@ -1115,6 +1139,7 @@
int hash = 1;
if (resultCase_ == ResultOneofCase.ParseError) hash ^= ParseError.GetHashCode();
if (resultCase_ == ResultOneofCase.SerializeError) hash ^= SerializeError.GetHashCode();
+ if (resultCase_ == ResultOneofCase.TimeoutError) hash ^= TimeoutError.GetHashCode();
if (resultCase_ == ResultOneofCase.RuntimeError) hash ^= RuntimeError.GetHashCode();
if (resultCase_ == ResultOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
if (resultCase_ == ResultOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
@@ -1172,6 +1197,10 @@
output.WriteRawTag(66);
output.WriteString(TextPayload);
}
+ if (resultCase_ == ResultOneofCase.TimeoutError) {
+ output.WriteRawTag(74);
+ output.WriteString(TimeoutError);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -1214,6 +1243,10 @@
output.WriteRawTag(66);
output.WriteString(TextPayload);
}
+ if (resultCase_ == ResultOneofCase.TimeoutError) {
+ output.WriteRawTag(74);
+ output.WriteString(TimeoutError);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
@@ -1230,6 +1263,9 @@
if (resultCase_ == ResultOneofCase.SerializeError) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(SerializeError);
}
+ if (resultCase_ == ResultOneofCase.TimeoutError) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(TimeoutError);
+ }
if (resultCase_ == ResultOneofCase.RuntimeError) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(RuntimeError);
}
@@ -1267,6 +1303,9 @@
case ResultOneofCase.SerializeError:
SerializeError = other.SerializeError;
break;
+ case ResultOneofCase.TimeoutError:
+ TimeoutError = other.TimeoutError;
+ break;
case ResultOneofCase.RuntimeError:
RuntimeError = other.RuntimeError;
break;
@@ -1334,6 +1373,10 @@
TextPayload = input.ReadString();
break;
}
+ case 74: {
+ TimeoutError = input.ReadString();
+ break;
+ }
}
}
#endif
@@ -1381,6 +1424,10 @@
TextPayload = input.ReadString();
break;
}
+ case 74: {
+ TimeoutError = input.ReadString();
+ break;
+ }
}
}
}
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
index ab9581a..b25011e 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -423,6 +423,26 @@
return makeMutableCopy(list);
}
+ // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+ protected static LongList mutableCopy(LongList list) {
+ return makeMutableCopy(list);
+ }
+
+ // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+ protected static FloatList mutableCopy(FloatList list) {
+ return makeMutableCopy(list);
+ }
+
+ // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+ protected static DoubleList mutableCopy(DoubleList list) {
+ return makeMutableCopy(list);
+ }
+
+ // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+ protected static BooleanList mutableCopy(BooleanList list) {
+ return makeMutableCopy(list);
+ }
+
protected static LongList emptyLongList() {
return LongArrayList.emptyList();
}
@@ -432,11 +452,6 @@
return new LongArrayList();
}
- // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
- protected static LongList mutableCopy(LongList list) {
- return makeMutableCopy(list);
- }
-
protected static FloatList emptyFloatList() {
return FloatArrayList.emptyList();
}
@@ -446,11 +461,6 @@
return new FloatArrayList();
}
- // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
- protected static FloatList mutableCopy(FloatList list) {
- return makeMutableCopy(list);
- }
-
protected static DoubleList emptyDoubleList() {
return DoubleArrayList.emptyList();
}
@@ -460,11 +470,6 @@
return new DoubleArrayList();
}
- // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
- protected static DoubleList mutableCopy(DoubleList list) {
- return makeMutableCopy(list);
- }
-
protected static BooleanList emptyBooleanList() {
return BooleanArrayList.emptyList();
}
@@ -474,11 +479,6 @@
return new BooleanArrayList();
}
- // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
- protected static BooleanList mutableCopy(BooleanList list) {
- return makeMutableCopy(list);
- }
-
@SuppressWarnings("unchecked") // Guaranteed by proto runtime.
protected static <ListT extends ProtobufList<?>> ListT makeMutableCopy(ListT list) {
int size = list.size();
diff --git a/objectivec/BUILD.bazel b/objectivec/BUILD.bazel
index 1c45357..0965de5 100644
--- a/objectivec/BUILD.bazel
+++ b/objectivec/BUILD.bazel
@@ -1,20 +1,66 @@
load("@rules_cc//cc:defs.bzl", "objc_library")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
+load("@upb//cmake:build_defs.bzl", "staleness_test")
load("//conformance:defs.bzl", "conformance_test")
+load(":defs.bzl", "objc_proto_camel_case_name")
+
+# The WKTs have to be checked in to support the CocoaPods and Xcode builds. This
+# generule and test ensure the source are current.
+#
+# Within the ":objectivec" target, the outputs of the genrule are then used to
+# ensure they are always "current". This implementation is basically the same
+# has how the WKTs are handled in src/google/protobuf/BUILD.bazel for the C++
+# version. They share the potential downsides around layer checks and that
+# someone could #include the header with the `wkt/` prefix on the name.
+
+_WELL_KNOWN_TYPES = [
+ "any",
+ "api",
+ "duration",
+ "empty",
+ "field_mask",
+ "source_context",
+ "struct",
+ "timestamp",
+ "type",
+ "wrappers",
+]
+
+_OBJC_WKT_NAMES = [objc_proto_camel_case_name(x) for x in _WELL_KNOWN_TYPES]
+
+_OBJC_EXTS = [
+ ".pbobjc.h",
+ ".pbobjc.m",
+]
+
+genrule(
+ name = "gen_wkt_sources",
+ srcs = ["//src/google/protobuf:well_known_type_protos"],
+ outs = ["wkt/GPB" + wkt + ext for wkt in _OBJC_WKT_NAMES for ext in _OBJC_EXTS],
+ cmd = " && ".join([
+ "$(execpath //:protoc) --objc_out=$(RULEDIR)/wkt --proto_path=src $(SRCS)",
+ ] + [
+ "mv $(RULEDIR)/wkt/google/protobuf/" + wkt + ext + " $(RULEDIR)/wkt/GPB" + wkt + ext
+ for wkt in _OBJC_WKT_NAMES
+ for ext in _OBJC_EXTS
+ ]),
+ exec_tools = ["//:protoc"],
+)
+
+staleness_test(
+ name = "well_known_types_staleness_test",
+ outs = ["GPB" + wkt + ext for wkt in _OBJC_WKT_NAMES for ext in _OBJC_EXTS],
+ generated_pattern = "wkt/%s",
+ tags = ["manual"],
+)
+
+################################################################################
+# Objective-C Runtime Library
+################################################################################
objc_library(
name = "objectivec",
hdrs = [
- "GPBAny.pbobjc.h",
- "GPBApi.pbobjc.h",
- "GPBDuration.pbobjc.h",
- "GPBEmpty.pbobjc.h",
- "GPBFieldMask.pbobjc.h",
- "GPBSourceContext.pbobjc.h",
- "GPBStruct.pbobjc.h",
- "GPBTimestamp.pbobjc.h",
- "GPBType.pbobjc.h",
- "GPBWrappers.pbobjc.h",
"GPBArray.h",
"GPBBootstrap.h",
"GPBCodedInputStream.h",
@@ -55,39 +101,30 @@
"GPBUnknownFieldSet_PackagePrivate.h",
"GPBUnknownField_PackagePrivate.h",
"GPBUtilities_PackagePrivate.h",
- ],
+ ] + ["wkt/GPB" + wkt + ".pbobjc.h" for wkt in _OBJC_WKT_NAMES],
copts = [
"-Wno-vla",
],
includes = [
".",
+ "wkt",
],
non_arc_srcs = [
- "GPBAny.pbobjc.m",
- "GPBApi.pbobjc.m",
"GPBArray.m",
"GPBCodedInputStream.m",
"GPBCodedOutputStream.m",
"GPBDescriptor.m",
"GPBDictionary.m",
- "GPBDuration.pbobjc.m",
- "GPBEmpty.pbobjc.m",
"GPBExtensionInternals.m",
"GPBExtensionRegistry.m",
- "GPBFieldMask.pbobjc.m",
"GPBMessage.m",
"GPBRootObject.m",
- "GPBSourceContext.pbobjc.m",
- "GPBStruct.pbobjc.m",
- "GPBTimestamp.pbobjc.m",
- "GPBType.pbobjc.m",
"GPBUnknownField.m",
"GPBUnknownFieldSet.m",
"GPBUtilities.m",
"GPBWellKnownTypes.m",
"GPBWireFormat.m",
- "GPBWrappers.pbobjc.m",
- ],
+ ] + ["wkt/GPB" + wkt + ".pbobjc.m" for wkt in _OBJC_WKT_NAMES],
target_compatible_with = select({
"@platforms//os:macos": [],
"@platforms//os:ios": [],
@@ -105,8 +142,8 @@
conformance_test(
name = "conformance_test",
failure_list = "//conformance:failure_list_objc.txt",
- testee = "//conformance:conformance_objc",
target_compatible_with = ["@platforms//os:macos"],
+ testee = "//conformance:conformance_objc",
)
# -------------------------------------------------------------------
@@ -121,6 +158,34 @@
],
)
+# -------------------------------------------------------------------
+# Validation of pddm expansion.
+
+py_binary(
+ name = "pddm",
+ srcs = ["DevTools/pddm.py"],
+)
+
+py_test(
+ name = "pddm_tests",
+ size = "small",
+ srcs = [
+ "DevTools/pddm.py",
+ "DevTools/pddm_tests.py",
+ ],
+)
+
+sh_test(
+ name = "sources_pddm_expansion_test",
+ size = "small",
+ srcs = ["DevTools/sources_pddm_expansion_test.sh"],
+ data = [":pddm"] + glob([
+ "**/*.h",
+ "**/*.m",
+ "**/*.pddm",
+ ]),
+)
+
################################################################################
# Distribution files
################################################################################
diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh
index d091a95..16981f9 100755
--- a/objectivec/DevTools/full_mac_build.sh
+++ b/objectivec/DevTools/full_mac_build.sh
@@ -2,8 +2,6 @@
#
# Helper to do build so you don't have to remember all the steps/args.
-echo "::group::Run full mac build"
-
set -eu
# Some base locations.
@@ -12,7 +10,7 @@
readonly BazelFlags="${BAZEL_FLAGS:---announce_rc --macos_minimum_os=10.9}"
# Invoke with BAZEL=bazelisk to use that instead.
-readonly BazelBin="${BAZEL:-bazel} ${BAZEL_STARTUP_FLAGS:-}"
+readonly BazelBin="${BAZEL:-bazel}"
printUsage() {
NAME=$(basename "${0}")
@@ -29,9 +27,6 @@
Show this message
-c, --clean
Issue a clean before the normal build.
- -r, --regenerate-descriptors
- Run generate_descriptor_proto.sh to regenerate all the checked in
- proto sources.
--full-build
By default only protoc is built within protobuf, this option will
enable a full build/test of the entire protobuf project.
@@ -76,7 +71,6 @@
fi
DO_CLEAN=no
-REGEN_DESCRIPTORS=no
FULL_BUILD=no
DO_XCODE_IOS_TESTS=yes
DO_XCODE_OSX_TESTS=yes
@@ -94,9 +88,6 @@
-c | --clean )
DO_CLEAN=yes
;;
- -r | --regenerate-descriptors )
- REGEN_DESCRIPTORS=yes
- ;;
--full-build )
FULL_BUILD=yes
;;
@@ -190,21 +181,16 @@
fi
fi
-if [[ "${REGEN_DESCRIPTORS}" == "yes" ]] ; then
- header "Regenerating the descriptor sources."
- ./generate_descriptor_proto.sh
-fi
-
if [[ "${FULL_BUILD}" == "yes" ]] ; then
header "Build/Test: everything"
- time ${BazelBin} test //:protoc //:protobuf //src/... $BazelFlags
+ ${BazelBin} test //:protoc //:protobuf //src/... $BazelFlags
else
header "Building: protoc"
- time ${BazelBin} build //:protoc $BazelFlags
+ ${BazelBin} build //:protoc $BazelFlags
fi
# Ensure the WKT sources checked in are current.
-time objectivec/generate_well_known_types.sh --check-only $BazelFlags
+objectivec/generate_well_known_types.sh --check-only
header "Checking on the ObjC Runtime Code"
# Some of the kokoro machines don't have python3 yet, so fall back to python if need be.
@@ -233,8 +219,7 @@
if [[ "${XCODE_QUIET}" == "yes" ]] ; then
XCODEBUILD_TEST_BASE_IOS+=( -quiet )
fi
- # Don't need to worry about form factors or retina/non retina;
- # just pick a mix of OS Versions and 32/64 bit.
+ # Don't need to worry about form factors or retina/non retina.
# NOTE: Different Xcode have different simulated hardware/os support.
case "${XCODE_VERSION}" in
[6-9].* | 1[0-2].* )
@@ -242,9 +227,8 @@
exit 11
;;
13.* | 14.*)
- # Dropped 32bit as Apple doesn't seem support the simulators either.
XCODEBUILD_TEST_BASE_IOS+=(
- -destination "platform=iOS Simulator,name=iPhone 8,OS=latest" # 64bit
+ -destination "platform=iOS Simulator,name=iPhone 13,OS=latest"
)
;;
* )
@@ -271,8 +255,7 @@
"${XCODEBUILD}"
-project objectivec/ProtocolBuffers_OSX.xcodeproj
-scheme ProtocolBuffers
- # Since the ObjC 2.0 Runtime is required, 32bit OS X isn't supported.
- -destination "platform=OS X,arch=x86_64" # 64bit
+ -destination "platform=macOS"
)
if [[ "${XCODE_QUIET}" == "yes" ]] ; then
XCODEBUILD_TEST_BASE_OSX+=( -quiet )
@@ -331,10 +314,8 @@
if [[ "${DO_OBJC_CONFORMANCE_TESTS}" == "yes" ]] ; then
header "Running ObjC Conformance Tests"
- time ${BazelBin} test //objectivec:conformance_test $BazelFlags
+ ${BazelBin} test //objectivec:conformance_test $BazelFlags
fi
echo ""
echo "$(basename "${0}"): Success!"
-
-echo "::endgroup::"
diff --git a/objectivec/DevTools/sources_pddm_expansion_test.sh b/objectivec/DevTools/sources_pddm_expansion_test.sh
new file mode 100755
index 0000000..99e01a1
--- /dev/null
+++ b/objectivec/DevTools/sources_pddm_expansion_test.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/pddm \
+ --dry-run \
+ ${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/*.[hm] \
+ ${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/Tests/*.[hm] \
+ || die "Update by running: objectivec/DevTools/pddm.py objectivec/*.[hm] objectivec/Tests/*.[hm]"
+
+echo "PASS"
diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m
index ad5c75e..9acf6f1 100644
--- a/objectivec/GPBCodedInputStream.m
+++ b/objectivec/GPBCodedInputStream.m
@@ -51,6 +51,10 @@
// int CodedInputStream::default_recursion_limit_ = 100;
static const NSUInteger kDefaultRecursionLimit = 100;
+// Bytes and Strings have a max size of 2GB.
+// https://protobuf.dev/programming-guides/encoding/#cheat-sheet
+static const uint32_t kMaxFieldSize = 0x7fffffff;
+
static void RaiseException(NSInteger code, NSString *reason) {
NSDictionary *errorInfo = nil;
if ([reason length]) {
@@ -223,14 +227,20 @@
}
NSString *GPBCodedInputStreamReadRetainedString(GPBCodedInputStreamState *state) {
- int32_t size = ReadRawVarint32(state);
+ uint64_t size = GPBCodedInputStreamReadUInt64(state);
+ if (size > kMaxFieldSize) {
+ // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
+ // so reuse an existing one.
+ RaiseException(GPBCodedInputStreamErrorInvalidSize, nil);
+ }
+ NSUInteger ns_size = (NSUInteger)size;
NSString *result;
if (size == 0) {
result = @"";
} else {
CheckSize(state, size);
result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos]
- length:size
+ length:ns_size
encoding:NSUTF8StringEncoding];
state->bufferPos += size;
if (!result) {
@@ -246,21 +256,31 @@
}
NSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state) {
- int32_t size = ReadRawVarint32(state);
- if (size < 0) return nil;
+ uint64_t size = GPBCodedInputStreamReadUInt64(state);
+ if (size > kMaxFieldSize) {
+ // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
+ // so reuse an existing one.
+ RaiseException(GPBCodedInputStreamErrorInvalidSize, nil);
+ }
+ NSUInteger ns_size = (NSUInteger)size;
CheckSize(state, size);
- NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos length:size];
+ NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos length:ns_size];
state->bufferPos += size;
return result;
}
NSData *GPBCodedInputStreamReadRetainedBytesNoCopy(GPBCodedInputStreamState *state) {
- int32_t size = ReadRawVarint32(state);
- if (size < 0) return nil;
+ uint64_t size = GPBCodedInputStreamReadUInt64(state);
+ if (size > kMaxFieldSize) {
+ // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking change
+ // so reuse an existing one.
+ RaiseException(GPBCodedInputStreamErrorInvalidSize, nil);
+ }
+ NSUInteger ns_size = (NSUInteger)size;
CheckSize(state, size);
// Cast is safe because freeWhenDone is NO.
NSData *result = [[NSData alloc] initWithBytesNoCopy:(void *)(state->bytes + state->bufferPos)
- length:size
+ length:ns_size
freeWhenDone:NO];
state->bufferPos += size;
return result;
diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h
index 5b7ce0c..d9fc898 100644
--- a/objectivec/GPBMessage.h
+++ b/objectivec/GPBMessage.h
@@ -293,6 +293,10 @@
*
* @note This can raise the GPBCodedOutputStreamException_* exceptions.
*
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
**/
- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output;
@@ -302,6 +306,11 @@
* @param output The output stream into which to write the message.
*
* @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
**/
- (void)writeToOutputStream:(NSOutputStream *)output;
@@ -312,6 +321,11 @@
* @param output The coded output stream into which to write the message.
*
* @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
**/
- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output;
@@ -322,6 +336,11 @@
* @param output The output stream into which to write the message.
*
* @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
**/
- (void)writeDelimitedToOutputStream:(NSOutputStream *)output;
@@ -336,6 +355,11 @@
* @note In DEBUG ONLY, the message is also checked for all required field,
* if one is missing, nil will be returned.
*
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
+ *
* @return The binary representation of the message.
**/
- (nullable NSData *)data;
@@ -347,6 +371,11 @@
* @note This value is not cached, so if you are using it repeatedly, it is
* recommended to keep a local copy.
*
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
+ *
* @return The binary representation of the size along with the message.
**/
- (NSData *)delimitedData;
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index 3342179..cb8d70a 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -1308,9 +1308,12 @@
@try {
[self writeToCodedOutputStream:stream];
} @catch (NSException *exception) {
- // This really shouldn't happen. The only way writeToCodedOutputStream:
- // could throw is if something in the library has a bug and the
- // serializedSize was wrong.
+ // This really shouldn't happen. Normally, this could mean there was a bug in the library and it
+ // failed to match between computing the size and writing out the bytes. However, the more
+ // common cause is while one thread was writing out the data, some other thread had a reference
+ // to this message or a message used as a nested field, and that other thread mutated that
+ // message, causing the pre computed serializedSize to no longer match the final size after
+ // serialization. It is not safe to mutate a message while accessing it from another thread.
#ifdef DEBUG
NSLog(@"%@: Internal exception while building message data: %@", [self class], exception);
#endif
@@ -1328,9 +1331,12 @@
@try {
[self writeDelimitedToCodedOutputStream:stream];
} @catch (NSException *exception) {
- // This really shouldn't happen. The only way writeToCodedOutputStream:
- // could throw is if something in the library has a bug and the
- // serializedSize was wrong.
+ // This really shouldn't happen. Normally, this could mean there was a bug in the library and it
+ // failed to match between computing the size and writing out the bytes. However, the more
+ // common cause is while one thread was writing out the data, some other thread had a reference
+ // to this message or a message used as a nested field, and that other thread mutated that
+ // message, causing the pre computed serializedSize to no longer match the final size after
+ // serialization. It is not safe to mutate a message while accessing it from another thread.
#ifdef DEBUG
NSLog(@"%@: Internal exception while building message delimitedData: %@", [self class],
exception);
@@ -1821,7 +1827,7 @@
//%PDDM-EXPAND-END (18 expansions)
-// clang-format off
+ // clang-format on
}
}
@@ -1848,8 +1854,7 @@
value = [autocreatedExtensionMap_ objectForKey:extension];
if (!value) {
// Auto create the message extensions to match normal fields.
- value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self,
- extension);
+ value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self, extension);
if (autocreatedExtensionMap_ == nil) {
autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init];
@@ -1926,8 +1931,7 @@
GPBExtensionDescriptor *descriptor = extension;
if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) {
- GPBMessage *autocreatedValue =
- [[autocreatedExtensionMap_ objectForKey:extension] retain];
+ GPBMessage *autocreatedValue = [[autocreatedExtensionMap_ objectForKey:extension] retain];
// Must remove from the map before calling GPBClearMessageAutocreator() so
// that GPBClearMessageAutocreator() knows its safe to clear.
[autocreatedExtensionMap_ removeObjectForKey:extension];
@@ -1959,9 +1963,7 @@
GPBBecomeVisibleToAutocreator(self);
}
-- (void)setExtension:(GPBExtensionDescriptor *)extension
- index:(NSUInteger)idx
- value:(id)value {
+- (void)setExtension:(GPBExtensionDescriptor *)extension index:(NSUInteger)idx value:(id)value {
CheckExtension(self, extension);
if (!extension.repeated) {
@@ -1991,8 +1993,7 @@
#pragma mark - mergeFrom
-- (void)mergeFromData:(NSData *)data
- extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
+- (void)mergeFromData:(NSData *)data extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
[self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
[input checkLastTagWas:0];
@@ -2008,9 +2009,6 @@
return;
}
NSData *data = GPBCodedInputStreamReadRetainedBytesNoCopy(state);
- if (data == nil) {
- return;
- }
[self mergeFromData:data extensionRegistry:extensionRegistry];
[data release];
}
@@ -2024,35 +2022,30 @@
+ (instancetype)parseFromData:(NSData *)data
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr {
- return [[[self alloc] initWithData:data
- extensionRegistry:extensionRegistry
+ return [[[self alloc] initWithData:data extensionRegistry:extensionRegistry
error:errorPtr] autorelease];
}
+ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr {
- return
- [[[self alloc] initWithCodedInputStream:input
- extensionRegistry:extensionRegistry
- error:errorPtr] autorelease];
+ return [[[self alloc] initWithCodedInputStream:input
+ extensionRegistry:extensionRegistry
+ error:errorPtr] autorelease];
}
#pragma mark - Parse Delimited From Data Support
+ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
- extensionRegistry:
- (id<GPBExtensionRegistry>)extensionRegistry
+ extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr {
GPBMessage *message = [[[self alloc] init] autorelease];
@try {
- [message mergeDelimitedFromCodedInputStream:input
- extensionRegistry:extensionRegistry];
+ [message mergeDelimitedFromCodedInputStream:input extensionRegistry:extensionRegistry];
if (errorPtr) {
*errorPtr = nil;
}
- }
- @catch (NSException *exception) {
+ } @catch (NSException *exception) {
message = nil;
if (errorPtr) {
*errorPtr = ErrorFromException(exception);
@@ -2098,12 +2091,10 @@
if (tag == GPBWireFormatMessageSetTypeIdTag) {
typeId = GPBCodedInputStreamReadUInt32(state);
if (typeId != 0) {
- extension = [extensionRegistry extensionForDescriptor:[self descriptor]
- fieldNumber:typeId];
+ extension = [extensionRegistry extensionForDescriptor:[self descriptor] fieldNumber:typeId];
}
} else if (tag == GPBWireFormatMessageSetMessageTag) {
- rawBytes =
- [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
+ rawBytes = [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
} else {
if (![input skipField:tag]) {
break;
@@ -2115,12 +2106,8 @@
if (rawBytes != nil && typeId != 0) {
if (extension != nil) {
- GPBCodedInputStream *newInput =
- [[GPBCodedInputStream alloc] initWithData:rawBytes];
- ExtensionMergeFromInputStream(extension,
- extension.packable,
- newInput,
- extensionRegistry,
+ GPBCodedInputStream *newInput = [[GPBCodedInputStream alloc] initWithData:rawBytes];
+ ExtensionMergeFromInputStream(extension, extension.packable, newInput, extensionRegistry,
self);
[newInput release];
} else {
@@ -2142,9 +2129,8 @@
int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag);
GPBDescriptor *descriptor = [self descriptor];
- GPBExtensionDescriptor *extension =
- [extensionRegistry extensionForDescriptor:descriptor
- fieldNumber:fieldNumber];
+ GPBExtensionDescriptor *extension = [extensionRegistry extensionForDescriptor:descriptor
+ fieldNumber:fieldNumber];
if (extension == nil) {
if (descriptor.wireFormat && GPBWireFormatMessageSetItemTag == tag) {
[self parseMessageSet:input extensionRegistry:extensionRegistry];
@@ -2152,23 +2138,14 @@
}
} else {
if (extension.wireType == wireType) {
- ExtensionMergeFromInputStream(extension,
- extension.packable,
- input,
- extensionRegistry,
- self);
+ ExtensionMergeFromInputStream(extension, extension.packable, input, extensionRegistry, self);
return YES;
}
// Primitive, repeated types can be packed on unpacked on the wire, and are
// parsed either way.
- if ([extension isRepeated] &&
- !GPBDataTypeIsObject(extension->description_->dataType) &&
+ if ([extension isRepeated] && !GPBDataTypeIsObject(extension->description_->dataType) &&
(extension.alternateWireType == wireType)) {
- ExtensionMergeFromInputStream(extension,
- !extension.packable,
- input,
- extensionRegistry,
- self);
+ ExtensionMergeFromInputStream(extension, !extension.packable, input, extensionRegistry, self);
return YES;
}
}
@@ -2187,38 +2164,38 @@
#pragma mark - MergeFromCodedInputStream Support
-static void MergeSingleFieldFromCodedInputStream(
- GPBMessage *self, GPBFieldDescriptor *field,
- GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) {
+static void MergeSingleFieldFromCodedInputStream(GPBMessage *self, GPBFieldDescriptor *field,
+ GPBCodedInputStream *input,
+ id<GPBExtensionRegistry> extensionRegistry) {
GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) {
-#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
- case GPBDataType##NAME: { \
- TYPE val = GPBCodedInputStreamRead##NAME(&input->state_); \
- GPBSet##FUNC_TYPE##IvarWithFieldPrivate(self, field, val); \
- break; \
- }
-#define CASE_SINGLE_OBJECT(NAME) \
- case GPBDataType##NAME: { \
- id val = GPBCodedInputStreamReadRetained##NAME(&input->state_); \
- GPBSetRetainedObjectIvarWithFieldPrivate(self, field, val); \
- break; \
- }
- CASE_SINGLE_POD(Bool, BOOL, Bool)
- CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
- CASE_SINGLE_POD(SFixed32, int32_t, Int32)
- CASE_SINGLE_POD(Float, float, Float)
- CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
- CASE_SINGLE_POD(SFixed64, int64_t, Int64)
- CASE_SINGLE_POD(Double, double, Double)
- CASE_SINGLE_POD(Int32, int32_t, Int32)
- CASE_SINGLE_POD(Int64, int64_t, Int64)
- CASE_SINGLE_POD(SInt32, int32_t, Int32)
- CASE_SINGLE_POD(SInt64, int64_t, Int64)
- CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
- CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
- CASE_SINGLE_OBJECT(Bytes)
- CASE_SINGLE_OBJECT(String)
+#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
+ case GPBDataType##NAME: { \
+ TYPE val = GPBCodedInputStreamRead##NAME(&input->state_); \
+ GPBSet##FUNC_TYPE##IvarWithFieldPrivate(self, field, val); \
+ break; \
+ }
+#define CASE_SINGLE_OBJECT(NAME) \
+ case GPBDataType##NAME: { \
+ id val = GPBCodedInputStreamReadRetained##NAME(&input->state_); \
+ GPBSetRetainedObjectIvarWithFieldPrivate(self, field, val); \
+ break; \
+ }
+ CASE_SINGLE_POD(Bool, BOOL, Bool)
+ CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
+ CASE_SINGLE_POD(SFixed32, int32_t, Int32)
+ CASE_SINGLE_POD(Float, float, Float)
+ CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
+ CASE_SINGLE_POD(SFixed64, int64_t, Int64)
+ CASE_SINGLE_POD(Double, double, Double)
+ CASE_SINGLE_POD(Int32, int32_t, Int32)
+ CASE_SINGLE_POD(Int64, int64_t, Int64)
+ CASE_SINGLE_POD(SInt32, int32_t, Int32)
+ CASE_SINGLE_POD(SInt64, int64_t, Int64)
+ CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
+ CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
+ CASE_SINGLE_OBJECT(Bytes)
+ CASE_SINGLE_OBJECT(String)
#undef CASE_SINGLE_POD
#undef CASE_SINGLE_OBJECT
@@ -2226,8 +2203,7 @@
if (GPBGetHasIvarField(self, field)) {
// GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
// check again.
- GPBMessage *message =
- GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+ GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
[input readMessage:message extensionRegistry:extensionRegistry];
} else {
GPBMessage *message = [[field.msgClass alloc] init];
@@ -2241,16 +2217,11 @@
if (GPBGetHasIvarField(self, field)) {
// GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
// check again.
- GPBMessage *message =
- GPBGetObjectIvarWithFieldNoAutocreate(self, field);
- [input readGroup:GPBFieldNumber(field)
- message:message
- extensionRegistry:extensionRegistry];
+ GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+ [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
} else {
GPBMessage *message = [[field.msgClass alloc] init];
- [input readGroup:GPBFieldNumber(field)
- message:message
- extensionRegistry:extensionRegistry];
+ [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
}
break;
@@ -2268,9 +2239,9 @@
} // switch
}
-static void MergeRepeatedPackedFieldFromCodedInputStream(
- GPBMessage *self, GPBFieldDescriptor *field,
- GPBCodedInputStream *input) {
+static void MergeRepeatedPackedFieldFromCodedInputStream(GPBMessage *self,
+ GPBFieldDescriptor *field,
+ GPBCodedInputStream *input) {
GPBDataType fieldDataType = GPBGetFieldDataType(field);
GPBCodedInputStreamState *state = &input->state_;
id genericArray = GetOrCreateArrayIvarWithField(self, field);
@@ -2278,25 +2249,25 @@
size_t limit = GPBCodedInputStreamPushLimit(state, length);
while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
switch (fieldDataType) {
-#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
- case GPBDataType##NAME: { \
- TYPE val = GPBCodedInputStreamRead##NAME(state); \
- [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
- break; \
- }
- CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
- CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
- CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
- CASE_REPEATED_PACKED_POD(Float, float, Float)
- CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
- CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
- CASE_REPEATED_PACKED_POD(Double, double, Double)
- CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
- CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
- CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
- CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
- CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
- CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
+#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
+ case GPBDataType##NAME: { \
+ TYPE val = GPBCodedInputStreamRead##NAME(state); \
+ [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
+ break; \
+ }
+ CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
+ CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
+ CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
+ CASE_REPEATED_PACKED_POD(Float, float, Float)
+ CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
+ CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
+ CASE_REPEATED_PACKED_POD(Double, double, Double)
+ CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
+ CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
+ CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
+ CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
+ CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
+ CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
#undef CASE_REPEATED_PACKED_POD
case GPBDataTypeBytes:
@@ -2309,7 +2280,7 @@
case GPBDataTypeEnum: {
int32_t val = GPBCodedInputStreamReadEnum(state);
if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
- [(GPBEnumArray*)genericArray addRawValue:val];
+ [(GPBEnumArray *)genericArray addRawValue:val];
} else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
[unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
@@ -2317,66 +2288,64 @@
break;
}
} // switch
- } // while(BytesUntilLimit() > 0)
+ } // while(BytesUntilLimit() > 0)
GPBCodedInputStreamPopLimit(state, limit);
}
static void MergeRepeatedNotPackedFieldFromCodedInputStream(
- GPBMessage *self, GPBFieldDescriptor *field,
- GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) {
+ GPBMessage *self, GPBFieldDescriptor *field, GPBCodedInputStream *input,
+ id<GPBExtensionRegistry> extensionRegistry) {
GPBCodedInputStreamState *state = &input->state_;
id genericArray = GetOrCreateArrayIvarWithField(self, field);
switch (GPBGetFieldDataType(field)) {
#define CASE_REPEATED_NOT_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
- case GPBDataType##NAME: { \
- TYPE val = GPBCodedInputStreamRead##NAME(state); \
- [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
- break; \
- }
-#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME) \
- case GPBDataType##NAME: { \
- id val = GPBCodedInputStreamReadRetained##NAME(state); \
- [(NSMutableArray*)genericArray addObject:val]; \
- [val release]; \
- break; \
- }
- CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
- CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
- CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
- CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
- CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
- CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
- CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
- CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
- CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
- CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
- CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
- CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
- CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
- CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
- CASE_REPEATED_NOT_PACKED_OBJECT(String)
+ case GPBDataType##NAME: { \
+ TYPE val = GPBCodedInputStreamRead##NAME(state); \
+ [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
+ break; \
+ }
+#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME) \
+ case GPBDataType##NAME: { \
+ id val = GPBCodedInputStreamReadRetained##NAME(state); \
+ [(NSMutableArray *)genericArray addObject:val]; \
+ [val release]; \
+ break; \
+ }
+ CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
+ CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
+ CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
+ CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
+ CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
+ CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
+ CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
+ CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
+ CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
+ CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
+ CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
+ CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
+ CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
+ CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
+ CASE_REPEATED_NOT_PACKED_OBJECT(String)
#undef CASE_REPEATED_NOT_PACKED_POD
#undef CASE_NOT_PACKED_OBJECT
case GPBDataTypeMessage: {
GPBMessage *message = [[field.msgClass alloc] init];
[input readMessage:message extensionRegistry:extensionRegistry];
- [(NSMutableArray*)genericArray addObject:message];
+ [(NSMutableArray *)genericArray addObject:message];
[message release];
break;
}
case GPBDataTypeGroup: {
GPBMessage *message = [[field.msgClass alloc] init];
- [input readGroup:GPBFieldNumber(field)
- message:message
- extensionRegistry:extensionRegistry];
- [(NSMutableArray*)genericArray addObject:message];
+ [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
+ [(NSMutableArray *)genericArray addObject:message];
[message release];
break;
}
case GPBDataTypeEnum: {
int32_t val = GPBCodedInputStreamReadEnum(state);
if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
- [(GPBEnumArray*)genericArray addRawValue:val];
+ [(GPBEnumArray *)genericArray addRawValue:val];
} else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
[unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
@@ -2406,30 +2375,28 @@
if (GPBFieldTag(fieldDescriptor) == tag) {
GPBFieldType fieldType = fieldDescriptor.fieldType;
if (fieldType == GPBFieldTypeSingle) {
- MergeSingleFieldFromCodedInputStream(self, fieldDescriptor,
- input, extensionRegistry);
+ MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, input, extensionRegistry);
// Well formed protos will only have a single field once, advance
// the starting index to the next field.
startingIndex += 1;
} else if (fieldType == GPBFieldTypeRepeated) {
if (fieldDescriptor.isPackable) {
- MergeRepeatedPackedFieldFromCodedInputStream(
- self, fieldDescriptor, input);
+ MergeRepeatedPackedFieldFromCodedInputStream(self, fieldDescriptor, input);
// Well formed protos will only have a repeated field that is
// packed once, advance the starting index to the next field.
startingIndex += 1;
} else {
- MergeRepeatedNotPackedFieldFromCodedInputStream(
- self, fieldDescriptor, input, extensionRegistry);
+ MergeRepeatedNotPackedFieldFromCodedInputStream(self, fieldDescriptor, input,
+ extensionRegistry);
}
} else { // fieldType == GPBFieldTypeMap
// GPB*Dictionary or NSDictionary, exact type doesn't matter at this
// point.
id map = GetOrCreateMapIvarWithField(self, fieldDescriptor);
[input readMapEntry:map
- extensionRegistry:extensionRegistry
- field:fieldDescriptor
- parentMessage:self];
+ extensionRegistry:extensionRegistry
+ field:fieldDescriptor
+ parentMessage:self];
}
merged = YES;
break;
@@ -2450,14 +2417,13 @@
(GPBFieldAlternateTag(fieldDescriptor) == tag)) {
BOOL alternateIsPacked = !fieldDescriptor.isPackable;
if (alternateIsPacked) {
- MergeRepeatedPackedFieldFromCodedInputStream(
- self, fieldDescriptor, input);
+ MergeRepeatedPackedFieldFromCodedInputStream(self, fieldDescriptor, input);
// Well formed protos will only have a repeated field that is
// packed once, advance the starting index to the next field.
startingIndex += 1;
} else {
- MergeRepeatedNotPackedFieldFromCodedInputStream(
- self, fieldDescriptor, input, extensionRegistry);
+ MergeRepeatedNotPackedFieldFromCodedInputStream(self, fieldDescriptor, input,
+ extensionRegistry);
}
merged = YES;
break;
@@ -2472,9 +2438,7 @@
// zero signals EOF / limit reached
return;
} else {
- if (![self parseUnknownField:input
- extensionRegistry:extensionRegistry
- tag:tag]) {
+ if (![self parseUnknownField:input extensionRegistry:extensionRegistry tag:tag]) {
// it's an endgroup tag
return;
}
@@ -2489,8 +2453,7 @@
- (void)mergeFrom:(GPBMessage *)other {
Class selfClass = [self class];
Class otherClass = [other class];
- if (!([selfClass isSubclassOfClass:otherClass] ||
- [otherClass isSubclassOfClass:selfClass])) {
+ if (!([selfClass isSubclassOfClass:otherClass] || [otherClass isSubclassOfClass:selfClass])) {
[NSException raise:NSInvalidArgumentException
format:@"Classes must match %@ != %@", selfClass, otherClass];
}
@@ -2512,39 +2475,32 @@
GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) {
case GPBDataTypeBool:
- GPBSetBoolIvarWithFieldPrivate(
- self, field, GPBGetMessageBoolField(other, field));
+ GPBSetBoolIvarWithFieldPrivate(self, field, GPBGetMessageBoolField(other, field));
break;
case GPBDataTypeSFixed32:
case GPBDataTypeEnum:
case GPBDataTypeInt32:
case GPBDataTypeSInt32:
- GPBSetInt32IvarWithFieldPrivate(
- self, field, GPBGetMessageInt32Field(other, field));
+ GPBSetInt32IvarWithFieldPrivate(self, field, GPBGetMessageInt32Field(other, field));
break;
case GPBDataTypeFixed32:
case GPBDataTypeUInt32:
- GPBSetUInt32IvarWithFieldPrivate(
- self, field, GPBGetMessageUInt32Field(other, field));
+ GPBSetUInt32IvarWithFieldPrivate(self, field, GPBGetMessageUInt32Field(other, field));
break;
case GPBDataTypeSFixed64:
case GPBDataTypeInt64:
case GPBDataTypeSInt64:
- GPBSetInt64IvarWithFieldPrivate(
- self, field, GPBGetMessageInt64Field(other, field));
+ GPBSetInt64IvarWithFieldPrivate(self, field, GPBGetMessageInt64Field(other, field));
break;
case GPBDataTypeFixed64:
case GPBDataTypeUInt64:
- GPBSetUInt64IvarWithFieldPrivate(
- self, field, GPBGetMessageUInt64Field(other, field));
+ GPBSetUInt64IvarWithFieldPrivate(self, field, GPBGetMessageUInt64Field(other, field));
break;
case GPBDataTypeFloat:
- GPBSetFloatIvarWithFieldPrivate(
- self, field, GPBGetMessageFloatField(other, field));
+ GPBSetFloatIvarWithFieldPrivate(self, field, GPBGetMessageFloatField(other, field));
break;
case GPBDataTypeDouble:
- GPBSetDoubleIvarWithFieldPrivate(
- self, field, GPBGetMessageDoubleField(other, field));
+ GPBSetDoubleIvarWithFieldPrivate(self, field, GPBGetMessageDoubleField(other, field));
break;
case GPBDataTypeBytes:
case GPBDataTypeString: {
@@ -2556,8 +2512,7 @@
case GPBDataTypeGroup: {
id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
if (GPBGetHasIvar(self, hasIndex, fieldNumber)) {
- GPBMessage *message =
- GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+ GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
[message mergeFrom:otherVal];
} else {
GPBMessage *message = [otherVal copy];
@@ -2565,27 +2520,23 @@
}
break;
}
- } // switch()
+ } // switch()
} else if (fieldType == GPBFieldTypeRepeated) {
// In the case of a list, they need to be appended, and there is no
// _hasIvar to worry about setting.
- id otherArray =
- GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+ id otherArray = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
if (otherArray) {
GPBDataType fieldDataType = field->description_->dataType;
if (GPBDataTypeIsObject(fieldDataType)) {
- NSMutableArray *resultArray =
- GetOrCreateArrayIvarWithField(self, field);
+ NSMutableArray *resultArray = GetOrCreateArrayIvarWithField(self, field);
[resultArray addObjectsFromArray:otherArray];
} else if (fieldDataType == GPBDataTypeEnum) {
- GPBEnumArray *resultArray =
- GetOrCreateArrayIvarWithField(self, field);
+ GPBEnumArray *resultArray = GetOrCreateArrayIvarWithField(self, field);
[resultArray addRawValuesFromArray:otherArray];
} else {
// The array type doesn't matter, that all implement
// -addValuesFromArray:.
- GPBInt32Array *resultArray =
- GetOrCreateArrayIvarWithField(self, field);
+ GPBInt32Array *resultArray = GetOrCreateArrayIvarWithField(self, field);
[resultArray addValuesFromArray:otherArray];
}
}
@@ -2596,27 +2547,23 @@
if (otherDict) {
GPBDataType keyDataType = field.mapKeyDataType;
GPBDataType valueDataType = field->description_->dataType;
- if (GPBDataTypeIsObject(keyDataType) &&
- GPBDataTypeIsObject(valueDataType)) {
- NSMutableDictionary *resultDict =
- GetOrCreateMapIvarWithField(self, field);
+ if (GPBDataTypeIsObject(keyDataType) && GPBDataTypeIsObject(valueDataType)) {
+ NSMutableDictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
[resultDict addEntriesFromDictionary:otherDict];
} else if (valueDataType == GPBDataTypeEnum) {
// The exact type doesn't matter, just need to know it is a
// GPB*EnumDictionary.
- GPBInt32EnumDictionary *resultDict =
- GetOrCreateMapIvarWithField(self, field);
+ GPBInt32EnumDictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
[resultDict addRawEntriesFromDictionary:otherDict];
} else {
// The exact type doesn't matter, they all implement
// -addEntriesFromDictionary:.
- GPBInt32Int32Dictionary *resultDict =
- GetOrCreateMapIvarWithField(self, field);
+ GPBInt32Int32Dictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
[resultDict addEntriesFromDictionary:otherDict];
}
}
} // if (fieldType)..else if...else
- } // for(fields)
+ } // for(fields)
// Unknown fields.
if (!unknownFields_) {
@@ -2632,8 +2579,7 @@
}
if (extensionMap_ == nil) {
- extensionMap_ =
- CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
+ extensionMap_ = CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
} else {
for (GPBExtensionDescriptor *extension in other->extensionMap_) {
id otherValue = [other->extensionMap_ objectForKey:extension];
@@ -2671,8 +2617,7 @@
}
if (isMessageExtension && !extension.isRepeated) {
- GPBMessage *autocreatedValue =
- [[autocreatedExtensionMap_ objectForKey:extension] retain];
+ GPBMessage *autocreatedValue = [[autocreatedExtensionMap_ objectForKey:extension] retain];
// Must remove from the map before calling GPBClearMessageAutocreator()
// so that GPBClearMessageAutocreator() knows its safe to clear.
[autocreatedExtensionMap_ removeObjectForKey:extension];
@@ -2706,10 +2651,8 @@
// NOTE: These are NSArray/GPB*Array or NSDictionary/GPB*Dictionary, but
// the type doesn't really matter as the objects all support -count and
// -isEqual:.
- NSArray *resultMapOrArray =
- GPBGetObjectIvarWithFieldNoAutocreate(self, field);
- NSArray *otherMapOrArray =
- GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+ NSArray *resultMapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+ NSArray *otherMapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
// nil and empty are equal
if (resultMapOrArray.count != 0 || otherMapOrArray.count != 0) {
if (![resultMapOrArray isEqual:otherMapOrArray]) {
@@ -2787,9 +2730,9 @@
}
break;
}
- } // switch()
- } // if(mapOrArray)...else
- } // for(fields)
+ } // switch()
+ } // if(mapOrArray)...else
+ } // for(fields)
// nil and empty are equal
if (extensionMap_.count != 0 || otherMsg->extensionMap_.count != 0) {
@@ -2800,8 +2743,7 @@
// nil and empty are equal
GPBUnknownFieldSet *otherUnknowns = otherMsg->unknownFields_;
- if ([unknownFields_ countOfFields] != 0 ||
- [otherUnknowns countOfFields] != 0) {
+ if ([unknownFields_ countOfFields] != 0 || [otherUnknowns countOfFields] != 0) {
if (![unknownFields_ isEqual:otherUnknowns]) {
return NO;
}
@@ -2904,7 +2846,7 @@
result = prime * result + (NSUInteger)[[*valPtr class] descriptor];
break;
}
- } // switch()
+ } // switch()
}
}
@@ -2917,8 +2859,8 @@
- (NSString *)description {
NSString *textFormat = GPBTextFormatForMessage(self, @" ");
- NSString *description = [NSString
- stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
+ NSString *description =
+ [NSString stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
return description;
}
@@ -2956,44 +2898,43 @@
uint32_t fieldNumber = GPBFieldNumber(fieldDescriptor);
switch (fieldDataType) {
-#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
- case GPBDataType##NAME: { \
- TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
- result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
- break; \
- }
-#define CASE_SINGLE_OBJECT(NAME) \
- case GPBDataType##NAME: { \
- id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
- result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
- break; \
- }
- CASE_SINGLE_POD(Bool, BOOL, Bool)
- CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
- CASE_SINGLE_POD(SFixed32, int32_t, Int32)
- CASE_SINGLE_POD(Float, float, Float)
- CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
- CASE_SINGLE_POD(SFixed64, int64_t, Int64)
- CASE_SINGLE_POD(Double, double, Double)
- CASE_SINGLE_POD(Int32, int32_t, Int32)
- CASE_SINGLE_POD(Int64, int64_t, Int64)
- CASE_SINGLE_POD(SInt32, int32_t, Int32)
- CASE_SINGLE_POD(SInt64, int64_t, Int64)
- CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
- CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
- CASE_SINGLE_OBJECT(Bytes)
- CASE_SINGLE_OBJECT(String)
- CASE_SINGLE_OBJECT(Message)
- CASE_SINGLE_OBJECT(Group)
- CASE_SINGLE_POD(Enum, int32_t, Int32)
+#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
+ case GPBDataType##NAME: { \
+ TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
+ result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
+ break; \
+ }
+#define CASE_SINGLE_OBJECT(NAME) \
+ case GPBDataType##NAME: { \
+ id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
+ result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
+ break; \
+ }
+ CASE_SINGLE_POD(Bool, BOOL, Bool)
+ CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
+ CASE_SINGLE_POD(SFixed32, int32_t, Int32)
+ CASE_SINGLE_POD(Float, float, Float)
+ CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
+ CASE_SINGLE_POD(SFixed64, int64_t, Int64)
+ CASE_SINGLE_POD(Double, double, Double)
+ CASE_SINGLE_POD(Int32, int32_t, Int32)
+ CASE_SINGLE_POD(Int64, int64_t, Int64)
+ CASE_SINGLE_POD(SInt32, int32_t, Int32)
+ CASE_SINGLE_POD(SInt64, int64_t, Int64)
+ CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
+ CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
+ CASE_SINGLE_OBJECT(Bytes)
+ CASE_SINGLE_OBJECT(String)
+ CASE_SINGLE_OBJECT(Message)
+ CASE_SINGLE_OBJECT(Group)
+ CASE_SINGLE_POD(Enum, int32_t, Int32)
#undef CASE_SINGLE_POD
#undef CASE_SINGLE_OBJECT
}
- // Repeated Fields
+ // Repeated Fields
} else if (fieldType == GPBFieldTypeRepeated) {
- id genericArray =
- GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+ id genericArray = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
NSUInteger count = [genericArray count];
if (count == 0) {
continue; // Nothing to add.
@@ -3001,41 +2942,41 @@
__block size_t dataSize = 0;
switch (fieldDataType) {
-#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE) \
- CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
-#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME) \
- case GPBDataType##NAME: { \
- GPB##ARRAY_TYPE##Array *array = genericArray; \
- [array enumerate##ARRAY_ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, __unused NSUInteger idx, __unused BOOL *stop) { \
- dataSize += GPBCompute##NAME##SizeNoTag(value); \
- }]; \
- break; \
- }
-#define CASE_REPEATED_OBJECT(NAME) \
- case GPBDataType##NAME: { \
- for (id value in genericArray) { \
- dataSize += GPBCompute##NAME##SizeNoTag(value); \
- } \
- break; \
- }
- CASE_REPEATED_POD(Bool, BOOL, Bool)
- CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
- CASE_REPEATED_POD(SFixed32, int32_t, Int32)
- CASE_REPEATED_POD(Float, float, Float)
- CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
- CASE_REPEATED_POD(SFixed64, int64_t, Int64)
- CASE_REPEATED_POD(Double, double, Double)
- CASE_REPEATED_POD(Int32, int32_t, Int32)
- CASE_REPEATED_POD(Int64, int64_t, Int64)
- CASE_REPEATED_POD(SInt32, int32_t, Int32)
- CASE_REPEATED_POD(SInt64, int64_t, Int64)
- CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
- CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
- CASE_REPEATED_OBJECT(Bytes)
- CASE_REPEATED_OBJECT(String)
- CASE_REPEATED_OBJECT(Message)
- CASE_REPEATED_OBJECT(Group)
- CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
+#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE) CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
+#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME) \
+ case GPBDataType##NAME: { \
+ GPB##ARRAY_TYPE##Array *array = genericArray; \
+ [array enumerate##ARRAY_ACCESSOR_NAME## \
+ ValuesWithBlock:^(TYPE value, __unused NSUInteger idx, __unused BOOL * stop) { \
+ dataSize += GPBCompute##NAME##SizeNoTag(value); \
+ }]; \
+ break; \
+ }
+#define CASE_REPEATED_OBJECT(NAME) \
+ case GPBDataType##NAME: { \
+ for (id value in genericArray) { \
+ dataSize += GPBCompute##NAME##SizeNoTag(value); \
+ } \
+ break; \
+ }
+ CASE_REPEATED_POD(Bool, BOOL, Bool)
+ CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
+ CASE_REPEATED_POD(SFixed32, int32_t, Int32)
+ CASE_REPEATED_POD(Float, float, Float)
+ CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
+ CASE_REPEATED_POD(SFixed64, int64_t, Int64)
+ CASE_REPEATED_POD(Double, double, Double)
+ CASE_REPEATED_POD(Int32, int32_t, Int32)
+ CASE_REPEATED_POD(Int64, int64_t, Int64)
+ CASE_REPEATED_POD(SInt32, int32_t, Int32)
+ CASE_REPEATED_POD(SInt64, int64_t, Int64)
+ CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
+ CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
+ CASE_REPEATED_OBJECT(Bytes)
+ CASE_REPEATED_OBJECT(String)
+ CASE_REPEATED_OBJECT(Message)
+ CASE_REPEATED_OBJECT(Group)
+ CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
#undef CASE_REPEATED_POD
#undef CASE_REPEATED_POD_EXTRA
#undef CASE_REPEATED_OBJECT
@@ -3053,20 +2994,18 @@
result += count * tagSize;
}
- // Map<> Fields
+ // Map<> Fields
} else { // fieldType == GPBFieldTypeMap
if (GPBDataTypeIsObject(fieldDataType) &&
(fieldDescriptor.mapKeyDataType == GPBDataTypeString)) {
// If key type was string, then the map is an NSDictionary.
- NSDictionary *map =
- GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+ NSDictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
if (map) {
result += GPBDictionaryComputeSizeInternalHelper(map, fieldDescriptor);
}
} else {
// Type will be GPB*GroupDictionary, exact type doesn't matter.
- GPBInt32Int32Dictionary *map =
- GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+ GPBInt32Int32Dictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
result += [map computeSerializedSizeAsField:fieldDescriptor];
}
}
@@ -3102,40 +3041,40 @@
ResolveIvarAccessorMethodResult *result) {
GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) {
-#define CASE_GET(NAME, TYPE, TRUE_NAME) \
- case GPBDataType##NAME: { \
- result->impToAdd = imp_implementationWithBlock(^(id obj) { \
- return GPBGetMessage##TRUE_NAME##Field(obj, field); \
- }); \
- result->encodingSelector = @selector(get##NAME); \
- break; \
- }
-#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME) \
- case GPBDataType##NAME: { \
- result->impToAdd = imp_implementationWithBlock(^(id obj) { \
- return GPBGetObjectIvarWithField(obj, field); \
- }); \
- result->encodingSelector = @selector(get##NAME); \
- break; \
- }
- CASE_GET(Bool, BOOL, Bool)
- CASE_GET(Fixed32, uint32_t, UInt32)
- CASE_GET(SFixed32, int32_t, Int32)
- CASE_GET(Float, float, Float)
- CASE_GET(Fixed64, uint64_t, UInt64)
- CASE_GET(SFixed64, int64_t, Int64)
- CASE_GET(Double, double, Double)
- CASE_GET(Int32, int32_t, Int32)
- CASE_GET(Int64, int64_t, Int64)
- CASE_GET(SInt32, int32_t, Int32)
- CASE_GET(SInt64, int64_t, Int64)
- CASE_GET(UInt32, uint32_t, UInt32)
- CASE_GET(UInt64, uint64_t, UInt64)
- CASE_GET_OBJECT(Bytes, id, Object)
- CASE_GET_OBJECT(String, id, Object)
- CASE_GET_OBJECT(Message, id, Object)
- CASE_GET_OBJECT(Group, id, Object)
- CASE_GET(Enum, int32_t, Enum)
+#define CASE_GET(NAME, TYPE, TRUE_NAME) \
+ case GPBDataType##NAME: { \
+ result->impToAdd = imp_implementationWithBlock(^(id obj) { \
+ return GPBGetMessage##TRUE_NAME##Field(obj, field); \
+ }); \
+ result->encodingSelector = @selector(get##NAME); \
+ break; \
+ }
+#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME) \
+ case GPBDataType##NAME: { \
+ result->impToAdd = imp_implementationWithBlock(^(id obj) { \
+ return GPBGetObjectIvarWithField(obj, field); \
+ }); \
+ result->encodingSelector = @selector(get##NAME); \
+ break; \
+ }
+ CASE_GET(Bool, BOOL, Bool)
+ CASE_GET(Fixed32, uint32_t, UInt32)
+ CASE_GET(SFixed32, int32_t, Int32)
+ CASE_GET(Float, float, Float)
+ CASE_GET(Fixed64, uint64_t, UInt64)
+ CASE_GET(SFixed64, int64_t, Int64)
+ CASE_GET(Double, double, Double)
+ CASE_GET(Int32, int32_t, Int32)
+ CASE_GET(Int64, int64_t, Int64)
+ CASE_GET(SInt32, int32_t, Int32)
+ CASE_GET(SInt64, int64_t, Int64)
+ CASE_GET(UInt32, uint32_t, UInt32)
+ CASE_GET(UInt64, uint64_t, UInt64)
+ CASE_GET_OBJECT(Bytes, id, Object)
+ CASE_GET_OBJECT(String, id, Object)
+ CASE_GET_OBJECT(Message, id, Object)
+ CASE_GET_OBJECT(Group, id, Object)
+ CASE_GET(Enum, int32_t, Enum)
#undef CASE_GET
}
}
@@ -3145,40 +3084,40 @@
ResolveIvarAccessorMethodResult *result) {
GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) {
-#define CASE_SET(NAME, TYPE, TRUE_NAME) \
- case GPBDataType##NAME: { \
- result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { \
- return GPBSet##TRUE_NAME##IvarWithFieldPrivate(obj, field, value); \
- }); \
- result->encodingSelector = @selector(set##NAME:); \
- break; \
- }
-#define CASE_SET_COPY(NAME) \
- case GPBDataType##NAME: { \
- result->impToAdd = imp_implementationWithBlock(^(id obj, id value) { \
- return GPBSetRetainedObjectIvarWithFieldPrivate(obj, field, [value copy]); \
- }); \
- result->encodingSelector = @selector(set##NAME:); \
- break; \
- }
- CASE_SET(Bool, BOOL, Bool)
- CASE_SET(Fixed32, uint32_t, UInt32)
- CASE_SET(SFixed32, int32_t, Int32)
- CASE_SET(Float, float, Float)
- CASE_SET(Fixed64, uint64_t, UInt64)
- CASE_SET(SFixed64, int64_t, Int64)
- CASE_SET(Double, double, Double)
- CASE_SET(Int32, int32_t, Int32)
- CASE_SET(Int64, int64_t, Int64)
- CASE_SET(SInt32, int32_t, Int32)
- CASE_SET(SInt64, int64_t, Int64)
- CASE_SET(UInt32, uint32_t, UInt32)
- CASE_SET(UInt64, uint64_t, UInt64)
- CASE_SET_COPY(Bytes)
- CASE_SET_COPY(String)
- CASE_SET(Message, id, Object)
- CASE_SET(Group, id, Object)
- CASE_SET(Enum, int32_t, Enum)
+#define CASE_SET(NAME, TYPE, TRUE_NAME) \
+ case GPBDataType##NAME: { \
+ result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { \
+ return GPBSet##TRUE_NAME##IvarWithFieldPrivate(obj, field, value); \
+ }); \
+ result->encodingSelector = @selector(set##NAME:); \
+ break; \
+ }
+#define CASE_SET_COPY(NAME) \
+ case GPBDataType##NAME: { \
+ result->impToAdd = imp_implementationWithBlock(^(id obj, id value) { \
+ return GPBSetRetainedObjectIvarWithFieldPrivate(obj, field, [value copy]); \
+ }); \
+ result->encodingSelector = @selector(set##NAME:); \
+ break; \
+ }
+ CASE_SET(Bool, BOOL, Bool)
+ CASE_SET(Fixed32, uint32_t, UInt32)
+ CASE_SET(SFixed32, int32_t, Int32)
+ CASE_SET(Float, float, Float)
+ CASE_SET(Fixed64, uint64_t, UInt64)
+ CASE_SET(SFixed64, int64_t, Int64)
+ CASE_SET(Double, double, Double)
+ CASE_SET(Int32, int32_t, Int32)
+ CASE_SET(Int64, int64_t, Int64)
+ CASE_SET(SInt32, int32_t, Int32)
+ CASE_SET(SInt64, int64_t, Int64)
+ CASE_SET(UInt32, uint32_t, UInt32)
+ CASE_SET(UInt64, uint64_t, UInt64)
+ CASE_SET_COPY(Bytes)
+ CASE_SET_COPY(String)
+ CASE_SET(Message, id, Object)
+ CASE_SET(Group, id, Object)
+ CASE_SET(Enum, int32_t, Enum)
#undef CASE_SET
}
}
@@ -3217,8 +3156,7 @@
result.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) {
if (value) {
[NSException raise:NSInvalidArgumentException
- format:@"%@: %@ can only be set to NO (to clear field).",
- [obj class],
+ format:@"%@: %@ can only be set to NO (to clear field).", [obj class],
NSStringFromSelector(field->setHasSel_)];
}
GPBClearMessageField(obj, field);
@@ -3262,8 +3200,7 @@
result.impToAdd = imp_implementationWithBlock(^(id obj) {
// Type doesn't matter, all *Array and *Dictionary types support
// -count.
- NSArray *arrayOrMap =
- GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
+ NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
return [arrayOrMap count];
});
result.encodingSelector = @selector(getArrayCount);
@@ -3272,8 +3209,7 @@
}
}
if (result.impToAdd) {
- const char *encoding =
- GPBMessageEncodingForSelector(result.encodingSelector, YES);
+ const char *encoding = GPBMessageEncodingForSelector(result.encodingSelector, YES);
Class msgClass = descriptor.messageClass;
BOOL methodAdded = class_addMethod(msgClass, sel, result.impToAdd, encoding);
// class_addMethod() is documented as also failing if the method was already
@@ -3307,8 +3243,7 @@
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [self init];
if (self) {
- NSData *data =
- [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
+ NSData *data = [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
if (data.length) {
[self mergeFromData:data extensionRegistry:nil];
}
@@ -3355,8 +3290,7 @@
#if defined(DEBUG) && DEBUG
if (field.fieldType != GPBFieldTypeRepeated) {
[NSException raise:NSInvalidArgumentException
- format:@"%@.%@ is not a repeated field.",
- [self class], field.name];
+ format:@"%@.%@ is not a repeated field.", [self class], field.name];
}
#endif
return GetOrCreateArrayIvarWithField(self, field);
@@ -3367,8 +3301,7 @@
#if defined(DEBUG) && DEBUG
if (field.fieldType != GPBFieldTypeMap) {
[NSException raise:NSInvalidArgumentException
- format:@"%@.%@ is not a map<> field.",
- [self class], field.name];
+ format:@"%@.%@ is not a map<> field.", [self class], field.name];
}
#endif
return GetOrCreateMapIvarWithField(self, field);
diff --git a/objectivec/GPBUnknownFieldSet.m b/objectivec/GPBUnknownFieldSet.m
index dcd4b44..1dce738 100644
--- a/objectivec/GPBUnknownFieldSet.m
+++ b/objectivec/GPBUnknownFieldSet.m
@@ -289,13 +289,6 @@
}
}
-- (void)mergeFromData:(NSData *)data {
- GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
- [self mergeFromCodedInputStream:input];
- [input checkLastTagWas:0];
- [input release];
-}
-
- (void)mergeVarintField:(int32_t)number value:(int32_t)value {
checkNumber(number);
[[self mutableFieldForNumber:number create:YES] addVarint:value];
diff --git a/objectivec/GPBUnknownFieldSet_PackagePrivate.h b/objectivec/GPBUnknownFieldSet_PackagePrivate.h
index e27127a..b65bdaa 100644
--- a/objectivec/GPBUnknownFieldSet_PackagePrivate.h
+++ b/objectivec/GPBUnknownFieldSet_PackagePrivate.h
@@ -50,7 +50,6 @@
- (void)mergeUnknownFields:(GPBUnknownFieldSet *)other;
- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input;
-- (void)mergeFromData:(NSData *)data;
- (void)mergeVarintField:(int32_t)number value:(int32_t)value;
- (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input;
diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m
index 0504062..0d0d327 100644
--- a/objectivec/Tests/GPBCodedInputStreamTests.m
+++ b/objectivec/Tests/GPBCodedInputStreamTests.m
@@ -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.
+#import <Foundation/Foundation.h>
#import "GPBTestUtilities.h"
#import "GPBCodedInputStream.h"
@@ -370,10 +371,23 @@
@"should throw a GPBCodedInputStreamException exception ");
}
-- (void)testBytesWithNegativeSize {
- NSData* data = bytes(0xFF, 0xFF, 0xFF, 0xFF, 0x0F);
+- (void)testBytesOver2GB {
+ NSData* data = bytes(0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x02, 0x03); // don't need all the bytes
GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
- XCTAssertNil([input readBytes]);
+ @try {
+ __unused NSData* result = [input readBytes];
+ XCTFail(@"Should have thrown");
+ } @catch (NSException* anException) {
+ // Ensure the correct error within the exception.
+ XCTAssertTrue([anException isKindOfClass:[NSException class]]);
+ XCTAssertEqualObjects(anException.name, GPBCodedInputStreamException);
+ NSDictionary* userInfo = anException.userInfo;
+ XCTAssertNotNil(userInfo);
+ NSError* err = userInfo[GPBCodedInputStreamUnderlyingErrorKey];
+ XCTAssertNotNil(err);
+ XCTAssertEqualObjects(err.domain, GPBCodedInputStreamErrorDomain);
+ XCTAssertEqual(err.code, GPBCodedInputStreamErrorInvalidSize);
+ }
}
// Verifies fix for b/10315336.
diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m
index 3c2381c..5a7dc16 100644
--- a/objectivec/Tests/GPBMessageTests+Serialization.m
+++ b/objectivec/Tests/GPBMessageTests+Serialization.m
@@ -1266,12 +1266,17 @@
XCTAssertEqual(error.code, GPBCodedInputStreamErrorRecursionDepthExceeded);
}
-- (void)testParseDelimitedDataWithNegativeSize {
- NSData *data = DataFromCStr("\xFF\xFF\xFF\xFF\x0F");
+- (void)testParseDelimitedDataOver2GB {
+ NSData *data = DataFromCStr("\xFF\xFF\xFF\xFF\x0F\x01\x02\0x3"); // Don't need all the bytes
GPBCodedInputStream *input = [GPBCodedInputStream streamWithData:data];
NSError *error;
- [GPBMessage parseDelimitedFromCodedInputStream:input extensionRegistry:nil error:&error];
- XCTAssertNil(error);
+ GPBMessage *result = [GPBMessage parseDelimitedFromCodedInputStream:input
+ extensionRegistry:nil
+ error:&error];
+ XCTAssertNil(result);
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, GPBCodedInputStreamErrorDomain);
+ XCTAssertEqual(error.code, GPBCodedInputStreamErrorInvalidSize);
}
#ifdef DEBUG
diff --git a/objectivec/Tests/GPBUnknownFieldSetTest.m b/objectivec/Tests/GPBUnknownFieldSetTest.m
index b98f52e..dbb6eb4 100644
--- a/objectivec/Tests/GPBUnknownFieldSetTest.m
+++ b/objectivec/Tests/GPBUnknownFieldSetTest.m
@@ -381,7 +381,8 @@
NSData* data = [fields data];
GPBUnknownFieldSet* parsed = [[[GPBUnknownFieldSet alloc] init] autorelease];
- [parsed mergeFromData:data];
+ GPBCodedInputStream* input = [[[GPBCodedInputStream alloc] initWithData:data] autorelease];
+ [parsed mergeFromCodedInputStream:input];
GPBUnknownField* field2 = [parsed getField:1];
XCTAssertEqual(field2.varintList.count, (NSUInteger)1);
XCTAssertEqual(0x7FFFFFFFFFFFFFFFULL, [field2.varintList valueAtIndex:0]);
diff --git a/objectivec/defs.bzl b/objectivec/defs.bzl
new file mode 100644
index 0000000..5535868
--- /dev/null
+++ b/objectivec/defs.bzl
@@ -0,0 +1,68 @@
+"""Starlark helpers for Objective-C protos."""
+
+# State constants for objc_proto_camel_case_name.
+_last_was_other = 0
+_last_was_lowercase = 1
+_last_was_uppercase = 2
+_last_was_number = 3
+
+def objc_proto_camel_case_name(name):
+ """A Starlark version of the ObjC generator's CamelCase name transform.
+
+ This needs to track
+ src/google/protobuf/compiler/objectivec/names.cc's UnderscoresToCamelCase()
+
+ NOTE: This code is written to model the C++ in protoc's ObjC generator so it
+ is easier to confirm that the algorithms between the implementations match.
+ The customizations for starlark performance are:
+ - The cascade within the loop is reordered and special cases "_" to
+ optimize for google3 inputs.
+ - The "last was" state is handled via integers instead of three booleans.
+
+ The `first_capitalized` argument in the C++ code is left off this code and
+ it acts as if the value were `True`.
+
+ Args:
+ name: The proto file name to convert to camel case. The extension should
+ already be removed.
+
+ Returns:
+ The converted proto name to camel case.
+ """
+ segments = []
+ current = ""
+ last_was = _last_was_other
+ for c in name.elems():
+ if c.islower():
+ # lowercase letter can follow a lowercase or uppercase letter.
+ if last_was != _last_was_lowercase and last_was != _last_was_uppercase:
+ segments.append(current)
+ current = c.upper()
+ else:
+ current += c
+ last_was = _last_was_lowercase
+ elif c == "_": # more common than rest, special case it.
+ last_was = _last_was_other
+ elif c.isdigit():
+ if last_was != _last_was_number:
+ segments.append(current)
+ current = ""
+ current += c
+ last_was = _last_was_number
+ elif c.isupper():
+ if last_was != _last_was_uppercase:
+ segments.append(current)
+ current = c
+ else:
+ current += c.lower()
+ last_was = _last_was_uppercase
+ else:
+ last_was = _last_was_other
+ segments.append(current)
+ result = ""
+ for x in segments:
+ if x in ("Url", "Http", "Https"):
+ result += x.upper()
+ else:
+ result += x
+ return result
diff --git a/objectivec/generate_well_known_types.sh b/objectivec/generate_well_known_types.sh
index 7e23a99..4b77412 100755
--- a/objectivec/generate_well_known_types.sh
+++ b/objectivec/generate_well_known_types.sh
@@ -9,8 +9,7 @@
readonly ObjCDir="${ScriptDir}"
readonly ProtoRootDir="${ObjCDir}/.."
-# Invoke with BAZEL=bazelisk to use that instead.
-readonly BazelBin="${BAZEL:-bazel} ${BAZEL_STARTUP_FLAGS:-}"
+cd "${ProtoRootDir}"
# Flag for continuous integration to check that everything is current.
CHECK_ONLY=0
@@ -19,7 +18,11 @@
shift
fi
-cd "${ProtoRootDir}"
+readonly PROTOC_PATH="${PROTOC:-${ProtoRootDir}/bazel-bin/protoc}"
+if [[ ! -x "${PROTOC_PATH}" ]] ; then
+ echo "Failed to find executable protoc: ${PROTOC_PATH}"
+ exit 1
+fi
if [[ ! -e src/google/protobuf/stubs/common.h ]]; then
cat >&2 << __EOF__
@@ -29,9 +32,6 @@
exit 1
fi
-# Make sure the compiler is current.
-${BazelBin} build //:protoc $@
-
cd src
declare -a RUNTIME_PROTO_FILES=( \
google/protobuf/any.proto \
@@ -50,7 +50,7 @@
# Generate to a temp directory to see if they match.
TMP_DIR=$(mktemp -d)
trap "rm -rf ${TMP_DIR}" EXIT
-${ProtoRootDir}/bazel-bin/protoc --objc_out="${TMP_DIR}" ${RUNTIME_PROTO_FILES[@]}
+"${PROTOC_PATH}" --objc_out="${TMP_DIR}" ${RUNTIME_PROTO_FILES[@]}
DID_COPY=0
for PROTO_FILE in "${RUNTIME_PROTO_FILES[@]}"; do
diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c
index 72c7809..09daffa 100644
--- a/php/ext/google/protobuf/array.c
+++ b/php/ext/google/protobuf/array.c
@@ -406,13 +406,13 @@
return;
}
- if (size == 0 || index != size - 1) {
+ if (size == 0 || index < 0 || index >= size) {
php_error_docref(NULL, E_USER_ERROR, "Cannot remove element at %ld.\n",
index);
return;
}
- upb_Array_Resize(intern->array, size - 1, Arena_Get(&intern->arena));
+ upb_Array_Delete(intern->array, index, 1);
}
/**
diff --git a/php/src/Google/Protobuf/Internal/RepeatedField.php b/php/src/Google/Protobuf/Internal/RepeatedField.php
index ea7971f..f6ecd1c 100644
--- a/php/src/Google/Protobuf/Internal/RepeatedField.php
+++ b/php/src/Google/Protobuf/Internal/RepeatedField.php
@@ -219,13 +219,13 @@
public function offsetUnset($offset)
{
$count = count($this->container);
- if (!is_numeric($offset) || $count === 0 || $offset !== $count - 1) {
+ if (!is_numeric($offset) || $count === 0 || $offset < 0 || $offset >= $count) {
trigger_error(
"Cannot remove element at the given index",
E_USER_ERROR);
return;
}
- array_pop($this->container);
+ array_splice($this->container, $offset, 1);
}
/**
diff --git a/php/tests/ArrayTest.php b/php/tests/ArrayTest.php
index 9e8fcb8..2cade79 100644
--- a/php/tests/ArrayTest.php
+++ b/php/tests/ArrayTest.php
@@ -655,4 +655,31 @@
$arr2 = clone $arr;
$this->assertSame($arr[0], $arr2[0]);
}
+
+ #########################################################
+ # Test offsetUnset
+ #########################################################
+
+ public function testOffsetUnset()
+ {
+ $arr = new RepeatedField(GPBType::INT32);
+ $arr[] = 0;
+ $arr[] = 1;
+ $arr[] = 2;
+
+ $this->assertSame(3, count($arr));
+ $this->assertSame(0, $arr[0]);
+ $this->assertSame(1, $arr[1]);
+ $this->assertSame(2, $arr[2]);
+
+ $arr->offsetUnset(1);
+ $this->assertSame(0, $arr[0]);
+ $this->assertSame(2, $arr[1]);
+
+ $arr->offsetUnset(0);
+ $this->assertSame(2, $arr[0]);
+
+ $arr->offsetUnset(0);
+ $this->assertCount(0, $arr);
+ }
}
diff --git a/push_auto_update.sh b/push_auto_update.sh
index 0d0e437..9972da6 100755
--- a/push_auto_update.sh
+++ b/push_auto_update.sh
@@ -39,6 +39,7 @@
commit_message="Auto-generate files"
fi
+git pull --rebase
git add -A
git diff --staged --quiet || git commit -am "$commit_message"
git push
diff --git a/regenerate_stale_files.sh b/regenerate_stale_files.sh
index 1c38104..58c640b 100755
--- a/regenerate_stale_files.sh
+++ b/regenerate_stale_files.sh
@@ -15,6 +15,7 @@
# Run and fix all staleness tests.
${BazelBin} test src:cmake_lists_staleness_test "$@" || ./bazel-bin/src/cmake_lists_staleness_test --fix
${BazelBin} test src/google/protobuf:well_known_types_staleness_test "$@" || ./bazel-bin/src/google/protobuf/well_known_types_staleness_test --fix
+${BazelBin} test objectivec:well_known_types_staleness_test "$@" || ./bazel-bin/objectivec/well_known_types_staleness_test --fix
# Generate C# code.
# This doesn't currently have Bazel staleness tests, but there's an existing
diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel
index d986479..e3db90c 100644
--- a/src/google/protobuf/BUILD.bazel
+++ b/src/google/protobuf/BUILD.bazel
@@ -1257,6 +1257,7 @@
"//src/google/protobuf/io",
"//src/google/protobuf/stubs",
"//src/google/protobuf/testing",
+ "@com_google_absl//absl/functional:bind_front",
"@com_google_absl//absl/synchronization",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index e9e7a15..23e6999 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -681,11 +681,6 @@
friend struct internal::ArenaTestPeer;
};
-template <>
-inline void* Arena::AllocateInternal<std::string, false>() {
- return impl_.AllocateFromStringBlock();
-}
-
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
index 9744204..19bd6b5 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
@@ -51,6 +51,7 @@
namespace compiler {
namespace cpp {
namespace {
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
using Sub = ::google::protobuf::io::Printer::Sub;
std::vector<Sub> Vars(const FieldDescriptor* field, const Options& opts) {
@@ -172,7 +173,8 @@
void SingularEnum::GenerateAccessorDeclarations(io::Printer* p) const {
auto v = p->WithVars(
- AnnotatedAccessors(field_, {"", "set_", "_internal_", "_internal_set_"}));
+ AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
+ auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
p->Emit(R"cc(
$DEPRECATED$ $Enum$ $name$() const;
$DEPRECATED$ void $set_name$($Enum$ value);
@@ -331,9 +333,12 @@
};
void RepeatedEnum::GenerateAccessorDeclarations(io::Printer* p) const {
- auto v = p->WithVars(
- AnnotatedAccessors(field_, {"", "set_", "add_", "mutable_", "_internal_",
- "_internal_add_", "_internal_mutable_"}));
+ auto v = p->WithVars(AnnotatedAccessors(
+ field_, {"", "_internal_", "_internal_add_", "_internal_mutable_"}));
+ auto vs =
+ p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
+ auto vm =
+ p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
p->Emit(R"cc(
public:
diff --git a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
index 79f1015..a91a394 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
@@ -30,6 +30,7 @@
#include <memory>
#include <string>
+#include <tuple>
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
@@ -141,10 +142,12 @@
" ${1$_internal_mutable_$name$$}$();\n"
"public:\n"
"$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
- " ${1$$name$$}$() const;\n"
+ " ${1$$name$$}$() const;\n",
+ descriptor_);
+ format(
"$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
" ${1$mutable_$name$$}$();\n",
- descriptor_);
+ std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::ALIAS));
}
void MapFieldGenerator::GenerateInlineAccessorDefinitions(
diff --git a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
index 6eaadef..b4bf2a9 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
@@ -809,9 +809,11 @@
"$type$* ${1$_internal_add_$name$$}$();\n"
"public:\n",
descriptor_);
+ format("$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n",
+ descriptor_);
+ format("$deprecated_attr$$type$* ${1$add_$name$$}$();\n",
+ std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::SET));
format(
- "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n"
- "$deprecated_attr$$type$* ${1$add_$name$$}$();\n"
"$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
" ${1$$name$$}$() const;\n",
descriptor_);
diff --git a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
index 5bbf298..b15801e 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
@@ -56,7 +56,7 @@
using ::google::protobuf::internal::WireFormat;
using ::google::protobuf::internal::WireFormatLite;
using Sub = ::google::protobuf::io::Printer::Sub;
-using Annotation = ::google::protobuf::GeneratedCodeInfo::Annotation;
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
// For encodings with fixed sizes, returns that size in bytes.
absl::optional<size_t> FixedSize(FieldDescriptor::Type type) {
@@ -193,18 +193,10 @@
};
void SingularPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
+ auto v = p->WithVars(
+ AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
+ auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
p->Emit(
- {
- Sub("name", p->LookupVar("name")).AnnotatedAs(field_),
- Sub("set_name", absl::StrCat("set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_name",
- absl::StrCat("_internal_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_set_name",
- absl::StrCat("_internal_set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- },
R"cc(
$DEPRECATED$ $Type$ $name$() const;
$DEPRECATED$ void $set_name$($Type$ value);
@@ -397,41 +389,27 @@
}
void RepeatedPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
- p->Emit(
- {
- Sub("name", p->LookupVar("name")).AnnotatedAs(field_),
- Sub("set_name", absl::StrCat("set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("add_name", absl::StrCat("add_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("mutable_name", absl::StrCat("mutable_", p->LookupVar("name")))
- .AnnotatedAs(field_),
+ auto v = p->WithVars(AnnotatedAccessors(
+ field_, {"", "_internal_", "_internal_add_", "_internal_mutable_"}));
+ auto vs =
+ p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
+ auto va =
+ p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
+ p->Emit(R"cc(
+ $DEPRECATED$ $Type$ $name$(int index) const;
+ $DEPRECATED$ void $set_name$(int index, $Type$ value);
+ $DEPRECATED$ void $add_name$($Type$ value);
+ $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
+ $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
- Sub("_internal_name",
- absl::StrCat("_internal_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_add_name",
- absl::StrCat("_internal_add_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_mutable_name",
- absl::StrCat("_internal_mutable_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- },
- R"cc(
- $DEPRECATED$ $Type$ $name$(int index) const;
- $DEPRECATED$ void $set_name$(int index, $Type$ value);
- $DEPRECATED$ void $add_name$($Type$ value);
- $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
- $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
+ private:
+ $Type$ $_internal_name$(int index) const;
+ void $_internal_add_name$($Type$ value);
+ const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
+ $pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
- private:
- $Type$ $_internal_name$(int index) const;
- void $_internal_add_name$($Type$ value);
- const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
- $pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
-
- public:
- )cc");
+ public:
+ )cc");
}
void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc
index e815e8b..7b14149 100644
--- a/src/google/protobuf/compiler/cpp/helpers.cc
+++ b/src/google/protobuf/compiler/cpp/helpers.cc
@@ -211,9 +211,9 @@
// Returns true if "field" is a message field that is backed by LazyField per
// profile (go/pdlazy).
-inline bool IsEagerlyVerifiedLazyByProfile(const FieldDescriptor* field,
- const Options& options,
- MessageSCCAnalyzer* scc_analyzer) {
+inline bool IsLazyByProfile(const FieldDescriptor* field,
+ const Options& options,
+ MessageSCCAnalyzer* scc_analyzer) {
return false;
}
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc
index 88bb015..a9cb054 100644
--- a/src/google/protobuf/compiler/cpp/message.cc
+++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -85,6 +85,7 @@
using ::google::protobuf::internal::WireFormatLite;
using ::google::protobuf::internal::cpp::HasHasbit;
using ::google::protobuf::internal::cpp::Utf8CheckMode;
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
using Sub = ::google::protobuf::io::Printer::Sub;
static constexpr int kNoHasbit = -1;
@@ -730,7 +731,10 @@
{"clearer",
[&] {
p->Emit({Sub("clear_name", absl::StrCat("clear_", name))
- .AnnotatedAs(field)},
+ .AnnotatedAs({
+ field,
+ Semantic::kSet,
+ })},
R"cc(
$deprecated_attr $void $clear_name$() $impl$;
)cc");
diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
index feb5a7f..e95ee56 100644
--- a/src/google/protobuf/compiler/cpp/metadata_test.cc
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -177,6 +177,270 @@
EXPECT_FALSE(atu::GetAnnotationSubstring(test, annotation).has_value());
}
+constexpr absl::string_view kEnumFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ enum Enum { VALUE = 0; }
+ message Message {
+ optional Enum efield = 1;
+ repeated Enum refield = 2;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesEnumSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kEnumFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "efield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_efield" || *substring == "clear_efield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_refield" || *substring == "clear_refield" ||
+ *substring == "add_refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kMapFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ map<string, int32> mfield = 1;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesMapSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kMapFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kPrimFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional int32 ifield = 1;
+ repeated int32 rifield = 2;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesPrimSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kPrimFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "ifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_ifield" || *substring == "clear_ifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rifield" || *substring == "clear_rifield" ||
+ *substring == "add_rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kCordFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional string sfield = 1 [ctype = CORD];
+ repeated string rsfield = 2 [ctype = CORD];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesCordSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kCordFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_sfield" || *substring == "clear_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rsfield" || *substring == "clear_rsfield" ||
+ *substring == "add_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kStringPieceFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional string sfield = 1 [ctype = STRING_PIECE];
+ repeated string rsfield = 2 [ctype = STRING_PIECE];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesStringPieceSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kStringPieceFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_sfield" || *substring == "set_alias_sfield" ||
+ *substring == "clear_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rsfield" ||
+ *substring == "set_alias_rsfield" ||
+ *substring == "clear_rsfield" ||
+ *substring == "add_alias_rsfield" ||
+ *substring == "add_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
constexpr absl::string_view kStringFieldTestFile = R"(
syntax = "proto2";
package foo;
@@ -205,7 +469,7 @@
if (*substring == "sfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (*substring == "set_sfield") {
+ } else if (*substring == "set_sfield" || *substring == "clear_sfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
annotation->semantic());
} else if (*substring == "mutable_sfield") {
@@ -223,7 +487,8 @@
if (*substring == "rsfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (*substring == "set_rsfield") {
+ } else if (*substring == "set_rsfield" || *substring == "clear_rsfield" ||
+ *substring == "add_rsfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
annotation->semantic());
} else if (*substring == "mutable_rsfield") {
@@ -265,6 +530,9 @@
if (*substring == "mfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
+ } else if (*substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
} else if (*substring == "mutable_mfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
annotation->semantic());
@@ -277,15 +545,60 @@
for (const auto* annotation : annotations) {
auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
ASSERT_TRUE(substring.has_value());
- if (substring == "rmfield") {
+ if (*substring == "rmfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (substring == "mutable_rmfield") {
+ } else if (*substring == "add_rmfield" || *substring == "clear_rmfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rmfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
annotation->semantic());
}
}
}
+
+constexpr absl::string_view kLazyMessageFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message SMessage { }
+ message Message {
+ optional SMessage mfield = 1 [lazy=true];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesLazyMessageSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kLazyMessageFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(1).name());
+ std::vector<int> field_path;
+ field_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+ field_path.push_back(1);
+ field_path.push_back(DescriptorProto::kFieldFieldNumber);
+ field_path.push_back(0);
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "mutable_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ } else if (*substring == "set_encoded_mfield" ||
+ *substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+}
} // namespace
} // namespace cpp
} // namespace compiler
diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
index 7e93fcd..791a7d5 100644
--- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc
+++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
@@ -494,14 +494,10 @@
} else {
format("0, // no _has_bits_\n");
}
- if (descriptor_->extension_range_count() == 1) {
- format(
- "PROTOBUF_FIELD_OFFSET($classname$, $extensions$),\n"
- "$1$, $2$, // extension_range_{low,high}\n",
- descriptor_->extension_range(0)->start,
- descriptor_->extension_range(0)->end);
+ if (descriptor_->extension_range_count() != 0) {
+ format("PROTOBUF_FIELD_OFFSET($classname$, $extensions$),\n");
} else {
- format("0, 0, 0, // no _extensions_\n");
+ format("0, // no _extensions_\n");
}
format("$1$, $2$, // max_field_number, fast_idx_mask\n",
(ordered_fields_.empty() ? 0 : ordered_fields_.back()->number()),
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 9e3a49d..efcd86e 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -5375,6 +5375,7 @@
} // namespace
+
void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
const Descriptor* parent,
Descriptor* result,
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index f6359e8..22bc03c 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -65,6 +65,7 @@
#include "google/protobuf/port.h"
#include "absl/base/attributes.h"
#include "absl/base/call_once.h"
+#include "absl/container/btree_map.h"
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
@@ -1902,7 +1903,7 @@
// in a .proto file.
enum ErrorLocation {
NAME, // the symbol name, or the package name for files
- NUMBER, // field or extension range number
+ NUMBER, // field, extension range or extension decl number
TYPE, // field type
EXTENDEE, // field extendee
DEFAULT_VALUE, // field default value
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index 80eebfe..64e6b2c 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -3979,6 +3979,16 @@
BuildFileInTestPool(DescriptorProto::descriptor()->file());
}
+ void BuildDescriptorMessagesInTestPoolWithErrors(
+ absl::string_view expected_errors) {
+ FileDescriptorProto file_proto;
+ DescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+ MockErrorCollector error_collector;
+ EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector) ==
+ nullptr);
+ EXPECT_EQ(error_collector.text_, expected_errors);
+ }
+
DescriptorPool pool_;
};
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 80a3eb5..efe5d7a 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -3092,9 +3092,9 @@
// We use `operator new` here because the destruction will be done with
// `operator delete` unconditionally.
void* p = ::operator new(sizeof(Table));
- auto* full_table = ::new (p) Table{
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, schema_.default_instance_, nullptr},
- {{{&internal::TcParser::ReflectionParseLoop, {}}}}};
+ auto* full_table = ::new (p)
+ Table{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, schema_.default_instance_, nullptr},
+ {{{&internal::TcParser::ReflectionParseLoop, {}}}}};
ABSL_DCHECK_EQ(static_cast<void*>(&full_table->header),
static_cast<void*>(full_table));
return &full_table->header;
@@ -3292,14 +3292,19 @@
void* p = ::operator new(byte_size);
auto* res = ::new (p) TcParseTableBase{
static_cast<uint16_t>(schema_.HasHasbits() ? schema_.HasBitsOffset() : 0),
- // extensions handled through reflection.
- 0, 0, 0,
+ schema_.HasExtensionSet()
+ ? static_cast<uint16_t>(schema_.GetExtensionSetOffset())
+ : uint16_t{0},
static_cast<uint32_t>(fields.empty() ? 0 : fields.back()->number()),
- static_cast<uint8_t>((fast_entries_count - 1) << 3), lookup_table_offset,
- table_info.num_to_entry_table.skipmap32, field_entry_offset,
+ static_cast<uint8_t>((fast_entries_count - 1) << 3),
+ lookup_table_offset,
+ table_info.num_to_entry_table.skipmap32,
+ field_entry_offset,
static_cast<uint16_t>(fields.size()),
- static_cast<uint16_t>(table_info.aux_entries.size()), aux_offset,
- schema_.default_instance_, &internal::TcParser::ReflectionFallback};
+ static_cast<uint16_t>(table_info.aux_entries.size()),
+ aux_offset,
+ schema_.default_instance_,
+ &internal::TcParser::ReflectionFallback};
// Now copy the rest of the payloads
PopulateTcParseFastEntries(table_info, res->fast_entry(0));
diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h
index dd4845b..33b094e 100644
--- a/src/google/protobuf/generated_message_tctable_decl.h
+++ b/src/google/protobuf/generated_message_tctable_decl.h
@@ -54,6 +54,7 @@
// Additional information about this field:
struct TcFieldData {
constexpr TcFieldData() : data(0) {}
+ explicit constexpr TcFieldData(uint64_t data) : data(data) {}
// Fast table entry constructor:
constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint8_t aux_idx,
@@ -63,6 +64,24 @@
uint64_t{hasbit_idx} << 16 | //
uint64_t{coded_tag}) {}
+ // Constructor to create an explicit 'uninitialized' instance.
+ // This constructor can be used to pass an uninitialized `data` value to a
+ // table driven parser function that does not use `data`. The purpose of this
+ // is that it allows the compiler to reallocate and re-purpose the register
+ // that is currently holding its value for other data. This reduces register
+ // allocations inside the highly optimized varint parsing functions.
+ //
+ // Applications not using `data` use the `PROTOBUF_TC_PARAM_NO_DATA_DECL`
+ // macro to declare the standard input arguments with no name for the `data`
+ // argument. Callers then use the `PROTOBUF_TC_PARAM_NO_DATA_PASS` macro.
+ //
+ // Example:
+ // if (ptr == nullptr) {
+ // PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ // }
+ struct DefaultInit {};
+ TcFieldData(DefaultInit) {} // NOLINT(google-explicit-constructor)
+
// Fields used in fast table parsing:
//
// Bit:
@@ -122,7 +141,9 @@
uint32_t tag() const { return static_cast<uint32_t>(data); }
uint32_t entry_offset() const { return static_cast<uint32_t>(data >> 32); }
- uint64_t data;
+ union {
+ uint64_t data;
+ };
};
struct TcParseTableBase;
@@ -149,8 +170,6 @@
// Common attributes for message layout:
uint16_t has_bits_offset;
uint16_t extension_offset;
- uint32_t extension_range_low;
- uint32_t extension_range_high;
uint32_t max_field_number;
uint8_t fast_idx_mask;
uint16_t lookup_table_offset;
@@ -173,7 +192,6 @@
// compiled.
constexpr TcParseTableBase(
uint16_t has_bits_offset, uint16_t extension_offset,
- uint32_t extension_range_low, uint32_t extension_range_high,
uint32_t max_field_number, uint8_t fast_idx_mask,
uint16_t lookup_table_offset, uint32_t skipmap32,
uint32_t field_entries_offset, uint16_t num_field_entries,
@@ -181,8 +199,6 @@
const MessageLite* default_instance, TailCallParseFunc fallback)
: has_bits_offset(has_bits_offset),
extension_offset(extension_offset),
- extension_range_low(extension_range_low),
- extension_range_high(extension_range_high),
max_field_number(max_field_number),
fast_idx_mask(fast_idx_mask),
lookup_table_offset(lookup_table_offset),
diff --git a/src/google/protobuf/generated_message_tctable_gen.cc b/src/google/protobuf/generated_message_tctable_gen.cc
index b829bb7..a5791f9 100644
--- a/src/google/protobuf/generated_message_tctable_gen.cc
+++ b/src/google/protobuf/generated_message_tctable_gen.cc
@@ -824,8 +824,7 @@
// If there are no fallback fields, and at most one extension range, the
// parser can use a generic fallback function. Otherwise, a message-specific
// fallback routine is needed.
- use_generated_fallback =
- !fallback_fields.empty() || descriptor->extension_range_count() > 1;
+ use_generated_fallback = !fallback_fields.empty();
}
} // namespace internal
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h
index a39245d..1adea2d 100644
--- a/src/google/protobuf/generated_message_tctable_impl.h
+++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -292,7 +292,7 @@
// the function is used as a way to get a UnknownFieldOps vtable, returned
// via the `const char*` return type. See `GetUnknownFieldOps()`
- static bool MustFallbackToGeneric(PROTOBUF_TC_PARAM_DECL) {
+ static bool MustFallbackToGeneric(PROTOBUF_TC_PARAM_NO_DATA_DECL) {
return ptr == nullptr;
}
@@ -359,36 +359,16 @@
static const char* FastZ64P1(PROTOBUF_TC_PARAM_DECL);
static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL);
- // Manually unrolled and specialized Varint parsing.
- template <typename FieldType, int data_offset, int hasbit_idx>
- static const char* FastTV32S1(PROTOBUF_TC_PARAM_DECL);
- template <typename FieldType, int data_offset, int hasbit_idx>
- static const char* FastTV64S1(PROTOBUF_TC_PARAM_DECL);
- template <int data_offset, int hasbit_idx>
- static const char* FastTV8S1(PROTOBUF_TC_PARAM_DECL);
-
- template <typename FieldType, int data_offset, int hasbit_idx>
+ template <typename FieldType, int unused_data_offset, int unused_hasbit_idx>
static constexpr TailCallParseFunc SingularVarintNoZag1() {
if (sizeof(FieldType) == 1) {
- if (data_offset < 100) {
- return &FastTV8S1<data_offset, hasbit_idx>;
- } else {
- return &FastV8S1;
- }
+ return &FastV8S1;
}
if (sizeof(FieldType) == 4) {
- if (data_offset < 100) {
- return &FastTV32S1<FieldType, data_offset, hasbit_idx>;
- } else { //
- return &FastV32S1;
- }
+ return &FastV32S1;
}
if (sizeof(FieldType) == 8) {
- if (data_offset < 128) {
- return &FastTV64S1<FieldType, data_offset, hasbit_idx>;
- } else {
- return &FastV64S1;
- }
+ return &FastV64S1;
}
static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4 ||
sizeof(FieldType) == 8,
@@ -529,12 +509,16 @@
// NOTE: Currently, this function only calls the table-level fallback
// function, so it should only be called as the fallback from fast table
// parsing.
- static const char* MiniParse(PROTOBUF_TC_PARAM_DECL);
+ static const char* MiniParse(PROTOBUF_TC_PARAM_NO_DATA_DECL);
static const char* FastEndG1(PROTOBUF_TC_PARAM_DECL);
static const char* FastEndG2(PROTOBUF_TC_PARAM_DECL);
private:
+ // Optimized small tag varint parser for int32/int64
+ template <typename FieldType>
+ static const char* FastVarintS1(PROTOBUF_TC_PARAM_DECL);
+
friend class GeneratedTcTableLiteTest;
static void* MaybeGetSplitBase(MessageLite* msg, const bool is_split,
const TcParseTableBase* table);
@@ -569,10 +553,10 @@
}
}
- static const char* TagDispatch(PROTOBUF_TC_PARAM_DECL);
- static const char* ToTagDispatch(PROTOBUF_TC_PARAM_DECL);
- static const char* ToParseLoop(PROTOBUF_TC_PARAM_DECL);
- static const char* Error(PROTOBUF_TC_PARAM_DECL);
+ static const char* TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+ static const char* ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+ static const char* ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+ static const char* Error(PROTOBUF_TC_PARAM_NO_DATA_DECL);
static const char* FastUnknownEnumFallback(PROTOBUF_TC_PARAM_DECL);
@@ -618,18 +602,21 @@
return ptr;
}
- uint32_t num = tag >> 3;
- if (table->extension_range_low <= num &&
- num <= table->extension_range_high) {
+ if (table->extension_offset != 0) {
+ // We don't need to check the extension ranges. If it is not an extension
+ // it will be handled just like if it was an unknown extension: sent to
+ // the unknown field set.
return RefAt<ExtensionSet>(msg, table->extension_offset)
.ParseField(tag, ptr,
static_cast<const MessageBaseT*>(table->default_instance),
&msg->_internal_metadata_, ctx);
+ } else {
+ // Otherwise, we directly put it on the unknown field set.
+ return UnknownFieldParse(
+ tag,
+ msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
+ ptr, ctx);
}
-
- return UnknownFieldParse(
- tag, msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
- ptr, ctx);
}
// Note: `inline` is needed on template function declarations below to avoid
@@ -726,262 +713,14 @@
static const char* MpFallback(PROTOBUF_TC_PARAM_DECL);
};
-// Shift "byte" left by n * 7 bits, filling vacated bits with ones.
-template <int n>
-inline PROTOBUF_ALWAYS_INLINE int64_t shift_left_fill_with_ones(uint64_t byte,
- uint64_t ones) {
- return static_cast<int64_t>((byte << (n * 7)) | (ones >> (64 - (n * 7))));
-}
-
-// Shift "byte" left by n * 7 bits, filling vacated bits with ones, and
-// put the new value in res. Return whether the result was negative.
-template <int n>
-inline PROTOBUF_ALWAYS_INLINE bool shift_left_fill_with_ones_was_negative(
- uint64_t byte, uint64_t ones, int64_t& res) {
-#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
- // For the first two rounds (ptr[1] and ptr[2]), micro benchmarks show a
- // substantial improvement from capturing the sign from the condition code
- // register on x86-64.
- bool sign_bit;
- asm("shldq %3, %2, %1"
- : "=@ccs"(sign_bit), "+r"(byte)
- : "r"(ones), "i"(n * 7));
- res = static_cast<int64_t>(byte);
- return sign_bit;
-#else
- // Generic fallback:
- res = shift_left_fill_with_ones<n>(byte, ones);
- return res < 0;
-#endif
-}
-
-template <class VarintType>
-inline PROTOBUF_ALWAYS_INLINE std::pair<const char*, VarintType>
-ParseFallbackPair(const char* p, int64_t res1) {
- constexpr bool kIs64BitVarint = std::is_same<VarintType, uint64_t>::value;
- constexpr bool kIs32BitVarint = std::is_same<VarintType, uint32_t>::value;
- static_assert(kIs64BitVarint || kIs32BitVarint,
- "Only 32 or 64 bit varints are supported");
- auto ptr = reinterpret_cast<const int8_t*>(p);
-
- // The algorithm relies on sign extension for each byte to set all high bits
- // when the varint continues. It also relies on asserting all of the lower
- // bits for each successive byte read. This allows the result to be aggregated
- // using a bitwise AND. For example:
- //
- // 8 1 64 57 ... 24 17 16 9 8 1
- // ptr[0] = 1aaa aaaa ; res1 = 1111 1111 ... 1111 1111 1111 1111 1aaa aaaa
- // ptr[1] = 1bbb bbbb ; res2 = 1111 1111 ... 1111 1111 11bb bbbb b111 1111
- // ptr[2] = 1ccc cccc ; res3 = 0000 0000 ... 000c cccc cc11 1111 1111 1111
- // ---------------------------------------------
- // res1 & res2 & res3 = 0000 0000 ... 000c cccc ccbb bbbb baaa aaaa
- //
- // On x86-64, a shld from a single register filled with enough 1s in the high
- // bits can accomplish all this in one instruction. It so happens that res1
- // has 57 high bits of ones, which is enough for the largest shift done.
- //
- // Just as importantly, by keeping results in res1, res2, and res3, we take
- // advantage of the superscalar abilities of the CPU.
- ABSL_DCHECK_EQ(res1 >> 7, -1);
- uint64_t ones = res1; // save the high 1 bits from res1 (input to SHLD)
- int64_t res2, res3; // accumulated result chunks
-
- if (!shift_left_fill_with_ones_was_negative<1>(ptr[1], ones, res2))
- goto done2;
- if (!shift_left_fill_with_ones_was_negative<2>(ptr[2], ones, res3))
- goto done3;
-
- // For the remainder of the chunks, check the sign of the AND result.
- res2 &= shift_left_fill_with_ones<3>(ptr[3], ones);
- if (res2 >= 0) goto done4;
- res1 &= shift_left_fill_with_ones<4>(ptr[4], ones);
- if (res1 >= 0) goto done5;
- if (kIs64BitVarint) {
- res2 &= shift_left_fill_with_ones<5>(ptr[5], ones);
- if (res2 >= 0) goto done6;
- res3 &= shift_left_fill_with_ones<6>(ptr[6], ones);
- if (res3 >= 0) goto done7;
- res1 &= shift_left_fill_with_ones<7>(ptr[7], ones);
- if (res1 >= 0) goto done8;
- res3 &= shift_left_fill_with_ones<8>(ptr[8], ones);
- if (res3 >= 0) goto done9;
- } else if (kIs32BitVarint) {
- if (PROTOBUF_PREDICT_TRUE(!(ptr[5] & 0x80))) goto done6;
- if (PROTOBUF_PREDICT_TRUE(!(ptr[6] & 0x80))) goto done7;
- if (PROTOBUF_PREDICT_TRUE(!(ptr[7] & 0x80))) goto done8;
- if (PROTOBUF_PREDICT_TRUE(!(ptr[8] & 0x80))) goto done9;
- }
-
- // For valid 64bit varints, the 10th byte/ptr[9] should be exactly 1. In this
- // case, the continuation bit of ptr[8] already set the top bit of res3
- // correctly, so all we have to do is check that the expected case is true.
- if (PROTOBUF_PREDICT_TRUE(kIs64BitVarint && ptr[9] == 1)) goto done10;
-
- if (PROTOBUF_PREDICT_FALSE(ptr[9] & 0x80)) {
- // If the continue bit is set, it is an unterminated varint.
- return {nullptr, 0};
- }
-
- // A zero value of the first bit of the 10th byte represents an
- // over-serialized varint. This case should not happen, but if does (say, due
- // to a nonconforming serializer), deassert the continuation bit that came
- // from ptr[8].
- if (kIs64BitVarint && (ptr[9] & 1) == 0) {
-#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
- // Use a small instruction since this is an uncommon code path.
- asm("btcq $63,%0" : "+r"(res3));
-#else
- res3 ^= static_cast<uint64_t>(1) << 63;
-#endif
- }
- goto done10;
-
-done2:
- return {p + 2, res1 & res2};
-done3:
- return {p + 3, res1 & res2 & res3};
-done4:
- return {p + 4, res1 & res2 & res3};
-done5:
- return {p + 5, res1 & res2 & res3};
-done6:
- return {p + 6, res1 & res2 & res3};
-done7:
- return {p + 7, res1 & res2 & res3};
-done8:
- return {p + 8, res1 & res2 & res3};
-done9:
- return {p + 9, res1 & res2 & res3};
-done10:
- return {p + 10, res1 & res2 & res3};
-}
-
-// Notes:
-// 1) if data_offset is negative, it's read from data.offset()
-// 2) if hasbit_idx is negative, it's read from data.hasbit_idx()
-template <int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV8S1(PROTOBUF_TC_PARAM_DECL) {
- using TagType = uint8_t;
-
- // Special case for a varint bool field with a tag of 1 byte:
- // The coded_tag() field will actually contain the value too and we can check
- // both at the same time.
- auto coded_tag = data.coded_tag<uint16_t>();
- if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) {
- auto& field =
- RefAt<bool>(msg, data_offset >= 0 ? data_offset : data.offset());
- // Note: we use `data.data` because Clang generates suboptimal code when
- // using coded_tag.
- // In x86_64 this uses the CH register to read the second byte out of
- // `data`.
- uint8_t value = data.data >> 8;
- // The assume allows using a mov instead of test+setne.
- PROTOBUF_ASSUME(value <= 1);
- field = static_cast<bool>(value);
-
- ptr += sizeof(TagType) + 1; // Consume the tag and the value.
- if (hasbit_idx < 0) {
- hasbits |= (uint64_t{1} << data.hasbit_idx());
- } else {
- if (hasbit_idx < 32) {
- // `& 31` avoids a compiler warning when hasbit_idx is negative.
- hasbits |= (uint64_t{1} << (hasbit_idx & 31));
- } else {
- static_assert(hasbit_idx == 63 || (hasbit_idx < 32),
- "hard-coded hasbit_idx should be 0-31, or the special"
- "value 63, which indicates the field has no has-bit.");
- // TODO(jorg): investigate whether higher hasbit indices are worth
- // supporting. Something like:
- // auto& hasblock = TcParser::RefAt<uint32_t>(msg, hasbit_idx / 32 * 4);
- // hasblock |= uint32_t{1} << (hasbit_idx % 32);
- }
- }
-
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
- }
-
- // If it didn't match above either the tag is wrong, or the value is encoded
- // non-canonically.
- // Jump to MiniParse as wrong tag is the most probable reason.
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
-}
-
-template <typename FieldType, int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV64S1(PROTOBUF_TC_PARAM_DECL) {
- using TagType = uint8_t;
- // super-early success test...
- if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
- ptr += sizeof(TagType); // Consume tag
- if (hasbit_idx < 32) {
- hasbits |= (uint64_t{1} << hasbit_idx);
- }
- uint8_t value = data.data >> 8;
- RefAt<FieldType>(msg, data_offset) = value;
- ptr += 1;
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
- }
- if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
- }
- ptr += sizeof(TagType); // Consume tag
- if (hasbit_idx < 32) {
- hasbits |= (uint64_t{1} << hasbit_idx);
- }
-
- auto tmp =
- ParseFallbackPair<uint64_t>(ptr, static_cast<int8_t>(data.data >> 8));
- data.data = 0; // Indicate to the compiler that we don't need this anymore.
- ptr = tmp.first;
- if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- return Error(PROTOBUF_TC_PARAM_PASS);
- }
-
- RefAt<FieldType>(msg, data_offset) = static_cast<FieldType>(tmp.second);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-}
-
-template <typename FieldType, int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV32S1(PROTOBUF_TC_PARAM_DECL) {
- using TagType = uint8_t;
- // super-early success test...
- if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
- ptr += sizeof(TagType); // Consume tag
- if (hasbit_idx < 32) {
- hasbits |= (uint64_t{1} << hasbit_idx);
- }
- uint8_t value = data.data >> 8;
- RefAt<FieldType>(msg, data_offset) = value;
- ptr += 1;
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
- }
- if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
- }
- ptr += sizeof(TagType); // Consume tag
- if (hasbit_idx < 32) {
- hasbits |= (uint64_t{1} << hasbit_idx);
- }
-
- auto tmp =
- ParseFallbackPair<uint32_t>(ptr, static_cast<int8_t>(data.data >> 8));
- data.data = 0; // Indicate to the compiler that we don't need this anymore.
- ptr = tmp.first;
- if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- return Error(PROTOBUF_TC_PARAM_PASS);
- }
-
- RefAt<FieldType>(msg, data_offset) = static_cast<FieldType>(tmp.second);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-}
-
// Dispatch to the designated parse function
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
- PROTOBUF_TC_PARAM_DECL) {
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
const size_t idx = coded_tag & table->fast_idx_mask;
PROTOBUF_ASSUME((idx & 7) == 0);
auto* fast_entry = table->fast_entry(idx >> 3);
- data = fast_entry->bits;
+ TcFieldData data = fast_entry->bits;
data.data ^= coded_tag;
PROTOBUF_MUSTTAIL return fast_entry->target()(PROTOBUF_TC_PARAM_PASS);
}
@@ -992,25 +731,23 @@
// mode. Luckily the structure of the algorithm is such that it's always
// possible to just return and use the enclosing parse loop as a trampoline.
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
- PROTOBUF_TC_PARAM_DECL) {
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
constexpr bool always_return = !PROTOBUF_TAILCALL;
if (always_return || !ctx->DataAvailable(ptr)) {
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
- PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
- PROTOBUF_TC_PARAM_DECL) {
- (void)data;
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
(void)ctx;
SyncHasbits(msg, hasbits, table);
return ptr;
}
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
- PROTOBUF_TC_PARAM_DECL) {
- (void)data;
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
(void)ctx;
(void)ptr;
SyncHasbits(msg, hasbits, table);
diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc
index 86d067b..1455a9e 100644
--- a/src/google/protobuf/generated_message_tctable_lite.cc
+++ b/src/google/protobuf/generated_message_tctable_lite.cc
@@ -98,7 +98,7 @@
// TODO(b/64614992): remove this asm
asm("" : "+r"(table));
#endif
- ptr = TagDispatch(msg, ptr, ctx, {}, table - 1, 0);
+ ptr = TagDispatch(msg, ptr, ctx, TcFieldData::DefaultInit(), table - 1, 0);
if (ptr == nullptr) break;
if (ctx->LastTag() != 1) break; // Ended on terminating tag
}
@@ -279,7 +279,7 @@
ptr = ReadTagInlined(ptr, &tag);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
if (export_called_function) *test_out = {Error};
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
auto* entry = FindFieldEntry(table, tag >> 3);
@@ -351,8 +351,9 @@
PROTOBUF_MUSTTAIL return parse_fn(PROTOBUF_TC_PARAM_PASS);
}
-PROTOBUF_NOINLINE const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse<false>(PROTOBUF_TC_PARAM_PASS);
+PROTOBUF_NOINLINE const char* TcParser::MiniParse(
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
+ PROTOBUF_MUSTTAIL return MiniParse<false>(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE TcParser::TestMiniParseResult TcParser::TestMiniParse(
PROTOBUF_TC_PARAM_DECL) {
@@ -369,11 +370,11 @@
template <typename TagType>
const char* TcParser::FastEndGroupImpl(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
ctx->SetLastTag(data.decoded_tag());
ptr += sizeof(TagType);
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastEndG1(PROTOBUF_TC_PARAM_DECL) {
@@ -403,7 +404,7 @@
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularParseMessageAuxImpl(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
auto saved_tag = UnalignedLoad<TagType>(ptr);
ptr += sizeof(TagType);
@@ -478,7 +479,7 @@
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedParseMessageAuxImpl(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const auto expected_tag = UnalignedLoad<TagType>(ptr);
const auto aux = *table->field_aux(data.aux_idx());
@@ -502,14 +503,14 @@
}
}
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) {
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastMdR1(PROTOBUF_TC_PARAM_DECL) {
@@ -560,13 +561,13 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularFixed(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
ptr += sizeof(TagType); // Consume tag
hasbits |= (uint64_t{1} << data.hasbit_idx());
RefAt<LayoutType>(msg, data.offset()) = UnalignedLoad<LayoutType>(ptr);
ptr += sizeof(LayoutType);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastF32S1(PROTOBUF_TC_PARAM_DECL) {
@@ -598,7 +599,7 @@
if (data.coded_tag<TagType>() == 0) {
return PackedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
auto& field = RefAt<RepeatedField<LayoutType>>(msg, data.offset());
@@ -607,7 +608,7 @@
field.Add(UnalignedLoad<LayoutType>(ptr + sizeof(TagType)));
ptr += sizeof(TagType) + sizeof(LayoutType);
} while (ctx->DataAvailable(ptr) && UnalignedLoad<TagType>(ptr) == tag);
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastF32R1(PROTOBUF_TC_PARAM_DECL) {
@@ -643,7 +644,7 @@
if (data.coded_tag<TagType>() == 0) {
return RepeatedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
ptr += sizeof(TagType);
@@ -680,6 +681,136 @@
namespace {
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE int64_t shift_left_fill_with_ones(uint64_t byte,
+ uint64_t ones) {
+ return static_cast<int64_t>((byte << (n * 7)) | (ones >> (64 - (n * 7))));
+}
+
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones, and
+// put the new value in res. Return whether the result was negative.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE bool shift_left_fill_with_ones_was_negative(
+ uint64_t byte, uint64_t ones, int64_t& res) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+ // For the first two rounds (up to 2 varint bytes), micro benchmarks show a
+ // substantial improvement from capturing the sign from the condition code
+ // register on x86-64.
+ bool sign_bit;
+ asm("shldq %3, %2, %1"
+ : "=@ccs"(sign_bit), "+r"(byte)
+ : "r"(ones), "i"(n * 7));
+ res = static_cast<int64_t>(byte);
+ return sign_bit;
+#else
+ // Generic fallback:
+ res = shift_left_fill_with_ones<n>(byte, ones);
+ return res < 0;
+#endif
+}
+
+template <class VarintType>
+inline PROTOBUF_ALWAYS_INLINE std::pair<const char*, VarintType>
+ParseFallbackPair(const char* p, int64_t res1) {
+ constexpr bool kIs64BitVarint = std::is_same<VarintType, uint64_t>::value;
+ constexpr bool kIs32BitVarint = std::is_same<VarintType, uint32_t>::value;
+ static_assert(kIs64BitVarint || kIs32BitVarint,
+ "Only 32 or 64 bit varints are supported");
+ auto ptr = reinterpret_cast<const int8_t*>(p);
+
+ // The algorithm relies on sign extension for each byte to set all high bits
+ // when the varint continues. It also relies on asserting all of the lower
+ // bits for each successive byte read. This allows the result to be aggregated
+ // using a bitwise AND. For example:
+ //
+ // 8 1 64 57 ... 24 17 16 9 8 1
+ // ptr[0] = 1aaa aaaa ; res1 = 1111 1111 ... 1111 1111 1111 1111 1aaa aaaa
+ // ptr[1] = 1bbb bbbb ; res2 = 1111 1111 ... 1111 1111 11bb bbbb b111 1111
+ // ptr[2] = 0ccc cccc ; res3 = 0000 0000 ... 000c cccc cc11 1111 1111 1111
+ // ---------------------------------------------
+ // res1 & res2 & res3 = 0000 0000 ... 000c cccc ccbb bbbb baaa aaaa
+ //
+ // On x86-64, a shld from a single register filled with enough 1s in the high
+ // bits can accomplish all this in one instruction. It so happens that res1
+ // has 57 high bits of ones, which is enough for the largest shift done.
+ //
+ // Just as importantly, by keeping results in res1, res2, and res3, we take
+ // advantage of the superscalar abilities of the CPU.
+ ABSL_DCHECK_EQ(res1 >> 7, -1);
+ uint64_t ones = res1; // save the high 1 bits from res1 (input to SHLD)
+ int64_t res2, res3; // accumulated result chunks
+
+ if (!shift_left_fill_with_ones_was_negative<1>(ptr[1], ones, res2))
+ goto done2;
+ if (!shift_left_fill_with_ones_was_negative<2>(ptr[2], ones, res3))
+ goto done3;
+
+ // For the remainder of the chunks, check the sign of the AND result.
+ res2 &= shift_left_fill_with_ones<3>(ptr[3], ones);
+ if (res2 >= 0) goto done4;
+ res1 &= shift_left_fill_with_ones<4>(ptr[4], ones);
+ if (res1 >= 0) goto done5;
+ if (kIs64BitVarint) {
+ res2 &= shift_left_fill_with_ones<5>(ptr[5], ones);
+ if (res2 >= 0) goto done6;
+ res3 &= shift_left_fill_with_ones<6>(ptr[6], ones);
+ if (res3 >= 0) goto done7;
+ res1 &= shift_left_fill_with_ones<7>(ptr[7], ones);
+ if (res1 >= 0) goto done8;
+ res3 &= shift_left_fill_with_ones<8>(ptr[8], ones);
+ if (res3 >= 0) goto done9;
+ } else if (kIs32BitVarint) {
+ if (PROTOBUF_PREDICT_TRUE(!(ptr[5] & 0x80))) goto done6;
+ if (PROTOBUF_PREDICT_TRUE(!(ptr[6] & 0x80))) goto done7;
+ if (PROTOBUF_PREDICT_TRUE(!(ptr[7] & 0x80))) goto done8;
+ if (PROTOBUF_PREDICT_TRUE(!(ptr[8] & 0x80))) goto done9;
+ }
+
+ // For valid 64bit varints, the 10th byte/ptr[9] should be exactly 1. In this
+ // case, the continuation bit of ptr[8] already set the top bit of res3
+ // correctly, so all we have to do is check that the expected case is true.
+ if (PROTOBUF_PREDICT_TRUE(kIs64BitVarint && ptr[9] == 1)) goto done10;
+
+ if (PROTOBUF_PREDICT_FALSE(ptr[9] & 0x80)) {
+ // If the continue bit is set, it is an unterminated varint.
+ return {nullptr, 0};
+ }
+
+ // A zero value of the first bit of the 10th byte represents an
+ // over-serialized varint. This case should not happen, but if does (say, due
+ // to a nonconforming serializer), deassert the continuation bit that came
+ // from ptr[8].
+ if (kIs64BitVarint && (ptr[9] & 1) == 0) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+ // Use a small instruction since this is an uncommon code path.
+ asm("btcq $63,%0" : "+r"(res3));
+#else
+ res3 ^= static_cast<uint64_t>(1) << 63;
+#endif
+ }
+ goto done10;
+
+done2:
+ return {p + 2, res1 & res2};
+done3:
+ return {p + 3, res1 & res2 & res3};
+done4:
+ return {p + 4, res1 & res2 & res3};
+done5:
+ return {p + 5, res1 & res2 & res3};
+done6:
+ return {p + 6, res1 & res2 & res3};
+done7:
+ return {p + 7, res1 & res2 & res3};
+done8:
+ return {p + 8, res1 & res2 & res3};
+done9:
+ return {p + 9, res1 & res2 & res3};
+done10:
+ return {p + 10, res1 & res2 & res3};
+}
+
template <typename Type>
inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p,
Type* value) {
@@ -792,7 +923,7 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularVarint(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
ptr += sizeof(TagType); // Consume tag
hasbits |= (uint64_t{1} << data.hasbit_idx());
@@ -807,7 +938,7 @@
RefAt<FieldType>(msg, data.offset()) =
ZigZagDecodeHelper<FieldType, zigzag>(static_cast<uint8_t>(*ptr++));
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <typename FieldType, typename TagType, bool zigzag>
@@ -842,31 +973,86 @@
hasbits = spill.hasbits;
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
RefAt<FieldType>(msg, data.offset()) =
ZigZagDecodeHelper<FieldType, zigzag>(tmp);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+}
+
+template <typename FieldType>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::FastVarintS1(
+ PROTOBUF_TC_PARAM_DECL) {
+ using TagType = uint8_t;
+ // super-early success test...
+ if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
+ ptr += sizeof(TagType); // Consume tag
+ hasbits |= (uint64_t{1} << data.hasbit_idx());
+ uint8_t value = data.data >> 8;
+ RefAt<FieldType>(msg, data.offset()) = value;
+ ptr += 1;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+ if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+ ptr += sizeof(TagType); // Consume tag
+ hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+ auto tmp =
+ ParseFallbackPair<FieldType>(ptr, static_cast<int8_t>(data.data >> 8));
+ ptr = tmp.first;
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+
+ RefAt<FieldType>(msg, data.offset()) = tmp.second;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return FastTV8S1<-1, -1>(PROTOBUF_TC_PARAM_PASS);
+ using TagType = uint8_t;
+
+ // Special case for a varint bool field with a tag of 1 byte:
+ // The coded_tag() field will actually contain the value too and we can check
+ // both at the same time.
+ auto coded_tag = data.coded_tag<uint16_t>();
+ if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) {
+ auto& field = RefAt<bool>(msg, data.offset());
+ // Note: we use `data.data` because Clang generates suboptimal code when
+ // using coded_tag.
+ // In x86_64 this uses the CH register to read the second byte out of
+ // `data`.
+ uint8_t value = data.data >> 8;
+ // The assume allows using a mov instead of test+setne.
+ PROTOBUF_ASSUME(value <= 1);
+ field = static_cast<bool>(value);
+
+ ptr += sizeof(TagType) + 1; // Consume the tag and the value.
+ hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+
+ // If it didn't match above either the tag is wrong, or the value is encoded
+ // non-canonically.
+ // Jump to MiniParse as wrong tag is the most probable reason.
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
+
PROTOBUF_NOINLINE const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(
PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV32S1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint8_t>(
- PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return FastVarintS1<uint32_t>(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV32S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint16_t>(
PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV64S1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint8_t>(
- PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return FastVarintS1<uint64_t>(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV64S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint16_t>(
@@ -899,7 +1085,7 @@
if (data.coded_tag<TagType>() == 0) {
return PackedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
auto& field = RefAt<RepeatedField<FieldType>>(msg, data.offset());
@@ -909,14 +1095,14 @@
FieldType tmp;
ptr = ParseVarint(ptr, &tmp);
if (ptr == nullptr) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
field.Add(ZigZagDecodeHelper<FieldType, zigzag>(tmp));
if (!ctx->DataAvailable(ptr)) {
break;
}
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV8R1(PROTOBUF_TC_PARAM_DECL) {
@@ -969,7 +1155,7 @@
if (data.coded_tag<TagType>() == 0) {
return RepeatedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
ptr += sizeof(TagType);
@@ -1044,7 +1230,7 @@
uint32_t tag;
ptr = ReadTag(ptr, &tag);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
data.data = tag;
PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
@@ -1054,14 +1240,14 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnum(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* ptr2 = ptr; // Save for unknown enum case
ptr += sizeof(TagType); // Consume tag
uint64_t tmp;
ptr = ParseVarint(ptr, &tmp);
if (ptr == nullptr) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
if (PROTOBUF_PREDICT_FALSE(
@@ -1071,7 +1257,7 @@
}
hasbits |= (uint64_t{1} << data.hasbit_idx());
RefAt<int32_t>(msg, data.offset()) = tmp;
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastErS1(PROTOBUF_TC_PARAM_DECL) {
@@ -1099,7 +1285,7 @@
PROTOBUF_MUSTTAIL return PackedEnum<TagType, xform_val>(
PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
@@ -1111,7 +1297,7 @@
uint64_t tmp;
ptr = ParseVarint(ptr, &tmp);
if (ptr == nullptr) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (PROTOBUF_PREDICT_FALSE(
!EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
@@ -1125,7 +1311,7 @@
break;
}
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const TcParser::UnknownFieldOps& TcParser::GetUnknownFieldOps(
@@ -1153,7 +1339,7 @@
PROTOBUF_MUSTTAIL return RepeatedEnum<TagType, xform_val>(
PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
const auto saved_tag = UnalignedLoad<TagType>(ptr);
@@ -1210,18 +1396,18 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnumSmallRange(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
uint8_t v = ptr[sizeof(TagType)];
if (PROTOBUF_PREDICT_FALSE(min > v || v > data.aux_idx())) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
RefAt<int32_t>(msg, data.offset()) = v;
ptr += sizeof(TagType) + 1;
hasbits |= (uint64_t{1} << data.hasbit_idx());
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastEr0S1(PROTOBUF_TC_PARAM_DECL) {
@@ -1252,7 +1438,7 @@
PROTOBUF_MUSTTAIL return PackedEnumSmallRange<TagType, min>(
PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
@@ -1261,14 +1447,14 @@
do {
uint8_t v = ptr[sizeof(TagType)];
if (PROTOBUF_PREDICT_FALSE(min > v || v > max)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
field.Add(static_cast<int32_t>(v));
ptr += sizeof(TagType) + 1;
if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) break;
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastEr0R1(PROTOBUF_TC_PARAM_DECL) {
@@ -1297,7 +1483,7 @@
PROTOBUF_MUSTTAIL return RepeatedEnumSmallRange<TagType, min>(
PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
@@ -1387,7 +1573,7 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
auto saved_tag = UnalignedLoad<TagType>(ptr);
ptr += sizeof(TagType);
@@ -1400,20 +1586,24 @@
} else {
ptr = ReadStringNoArena(msg, ptr, ctx, data.aux_idx(), table, field);
}
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
switch (utf8) {
case kNoUtf8:
#ifdef NDEBUG
case kUtf8ValidateOnly:
#endif
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
default:
if (PROTOBUF_PREDICT_TRUE(IsValidUTF8(field))) {
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
ReportFastUtf8Error(FastDecodeTag(saved_tag), table);
- return utf8 == kUtf8 ? Error(PROTOBUF_TC_PARAM_PASS)
- : ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ if (utf8 == kUtf8) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
@@ -1447,49 +1637,49 @@
// Inlined string variants:
const char* TcParser::FastBiS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastBiS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastSiS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastSiS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastUiS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastUiS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
// Corded string variants:
const char* TcParser::FastBcS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastBcS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastScS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastScS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastUcS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastUcS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <typename TagType, typename FieldType, TcParser::Utf8Type utf8>
PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedString(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const auto expected_tag = UnalignedLoad<TagType>(ptr);
auto& field = RefAt<FieldType>(msg, data.offset());
@@ -1522,7 +1712,7 @@
ptr = ParseRepeatedStringOnce(ptr, arena, serial_arena, ctx, field);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr || !validate_last_string())) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (!ctx->DataAvailable(ptr)) break;
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
@@ -1532,12 +1722,12 @@
std::string* str = field.Add();
ptr = InlineGreedyStringParser(str, ptr, ctx);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr || !validate_last_string())) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (!ctx->DataAvailable(ptr)) break;
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
}
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastBR1(PROTOBUF_TC_PARAM_DECL) {
@@ -1712,7 +1902,7 @@
RefAt<uint32_t>(base, entry.offset) = UnalignedLoad<uint32_t>(ptr);
ptr += sizeof(uint32_t);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::MpRepeatedFixed(
@@ -1761,7 +1951,7 @@
} while (next_tag == decoded_tag);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::MpPackedFixed(PROTOBUF_TC_PARAM_DECL) {
@@ -1790,9 +1980,9 @@
}
if (ptr == nullptr) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <bool is_split>
@@ -1817,7 +2007,9 @@
const char* ptr2 = ptr; // save for unknown enum case
uint64_t tmp;
ptr = ParseVarint(ptr, &tmp);
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
// Transform and/or validate the value
uint16_t rep = type_card & field_layout::kRepMask;
@@ -1854,7 +2046,7 @@
RefAt<bool>(base, entry.offset) = static_cast<bool>(tmp);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
@@ -1884,11 +2076,15 @@
do {
uint64_t tmp;
ptr = ParseVarint(ptr2, &tmp);
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
field.Add(is_zigzag ? WireFormatLite::ZigZagDecode64(tmp) : tmp);
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
- if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr2 == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
} while (next_tag == decoded_tag);
} else if (rep == field_layout::kRep32Bits) {
auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
@@ -1897,7 +2093,9 @@
do {
uint64_t tmp;
ptr = ParseVarint(ptr2, &tmp);
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
if (is_validated_enum) {
if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
ptr = ptr2;
@@ -1909,7 +2107,9 @@
field.Add(tmp);
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
- if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr2 == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
} while (next_tag == decoded_tag);
} else {
ABSL_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
@@ -1919,15 +2119,19 @@
do {
uint64_t tmp;
ptr = ParseVarint(ptr2, &tmp);
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
field.Add(static_cast<bool>(tmp));
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
- if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr2 == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
} while (next_tag == decoded_tag);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
@@ -1978,7 +2182,7 @@
ptr, [field](uint64_t value) { field->Add(value); });
}
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
bool TcParser::MpVerifyUtf8(absl::string_view wire_bytes,
@@ -2056,9 +2260,9 @@
}
if (ptr == nullptr || !is_valid) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_ALWAYS_INLINE const char* TcParser::ParseRepeatedStringOnce(
@@ -2105,7 +2309,7 @@
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr ||
!MpVerifyUtf8(field[field.size() - 1],
table, entry, xform_val))) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
@@ -2118,7 +2322,7 @@
if (PROTOBUF_PREDICT_FALSE(
ptr == nullptr ||
!MpVerifyUtf8(*str, table, entry, xform_val))) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
@@ -2135,7 +2339,7 @@
#endif
}
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <bool is_split>
diff --git a/src/google/protobuf/generated_message_tctable_lite_test.cc b/src/google/protobuf/generated_message_tctable_lite_test.cc
index e242d83..12aeced 100644
--- a/src/google/protobuf/generated_message_tctable_lite_test.cc
+++ b/src/google/protobuf/generated_message_tctable_lite_test.cc
@@ -94,7 +94,7 @@
const TcParseTable<0, 1, 0, 0, 2> parse_table = {
{
kHasBitsOffset, //
- 0, 0, 0, // no _extensions_
+ 0, // no _extensions_
1, 0, // max_field_number, fast_idx_mask
offsetof(decltype(parse_table), field_lookup_table),
0xFFFFFFFF - 1, // skipmap
@@ -125,7 +125,7 @@
// clang-format on
uint8_t serialize_buffer[64];
- for (int size : {8, 32, 64, -8, -32, -64}) {
+ for (int size : {8, 32, 64}) {
SCOPED_TRACE(size);
auto next_i = [](uint64_t i) {
// if i + 1 is a power of two, return that.
@@ -192,21 +192,12 @@
case 8:
fn = &TcParser::FastV8S1;
break;
- case -8:
- fn = &TcParser::FastTV8S1<kFieldOffset, kHasBitIndex>;
- break;
case 32:
fn = &TcParser::FastV32S1;
break;
- case -32:
- fn = &TcParser::FastTV32S1<uint32_t, kFieldOffset, kHasBitIndex>;
- break;
case 64:
fn = &TcParser::FastV64S1;
break;
- case -64:
- fn = &TcParser::FastTV64S1<uint64_t, kFieldOffset, kHasBitIndex>;
- break;
}
fallback_ptr_received = absl::nullopt;
fallback_hasbits_received = absl::nullopt;
@@ -215,7 +206,6 @@
Xor2SerializedBytes(parse_table.fast_entries[0].bits, ptr),
&parse_table.header, /*hasbits=*/0);
switch (size) {
- case -8:
case 8: {
if (end_ptr == nullptr) {
// If end_ptr is nullptr, that means the FastParser gave up and
@@ -240,7 +230,6 @@
EXPECT_EQ(actual_field, static_cast<decltype(actual_field)>(i)) //
<< " hex: " << absl::StrCat(absl::Hex(actual_field));
}; break;
- case -32:
case 32: {
ASSERT_TRUE(end_ptr);
ASSERT_EQ(end_ptr - ptr, serialized.size());
@@ -249,7 +238,6 @@
EXPECT_EQ(actual_field, static_cast<decltype(actual_field)>(i)) //
<< " hex: " << absl::StrCat(absl::Hex(actual_field));
}; break;
- case -64:
case 64: {
ASSERT_EQ(end_ptr - ptr, serialized.size());
@@ -297,9 +285,9 @@
TcParseTable<0, 3, 0, 0, 2> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 0, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 0, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - 7, // 7 = fields 1, 2, and 3.
offsetof(decltype(table), field_names),
@@ -364,9 +352,9 @@
TcParseTable<0, 5, 0, 0, 8> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 111, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 111, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - (1 << 1) - (1 << 2) // fields 2, 3
- (1 << 3) - (1 << 4), // fields 4, 5
@@ -405,9 +393,9 @@
TcParseTable<0, 6, 0, 0, 8> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 111, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 111, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - (1<<0) - (1<<2) - (1<<3) - (1<<4) - (1<<6), // 1,3-5,7
offsetof(decltype(table), field_entries),
@@ -451,9 +439,9 @@
TcParseTable<0, 10, 0, 0, 8> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 70, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 70, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - (1<<0) - (1<<2) - (1<<3) - (1<<4) // 1, 3, 4, 5, 6
- (1<<5) - (1<<7) - (1<<8) - (1<<10) // 8, 9, 11, 12
@@ -497,9 +485,9 @@
TcParseTable<0, 3, 0, 15, 2> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 3, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 3, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - (1<<0) - (1<<1) - (1<<2), // fields 1, 2, 3
offsetof(decltype(table), field_entries),
@@ -547,9 +535,9 @@
TableType table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 0, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 0, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF, // no fields
offsetof(decltype(table), field_names), // no field_entries
@@ -598,7 +586,7 @@
const TcParseTable<5, 134, 5, 2176, 55> test_all_types_table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
+ 0, 0, // has_bits_offset, extensions
418, 248, // max_field_number, fast_idx_mask
offsetof(decltype(test_all_types_table), field_lookup_table),
977895424, // skipmap for fields 1-15,18-19,21-22,24-25,27,31-32
diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc
index 204da69..c41d8b3 100644
--- a/src/google/protobuf/message_unittest.inc
+++ b/src/google/protobuf/message_unittest.inc
@@ -1166,6 +1166,31 @@
std::signbit(out_message.optional_double()));
}
+TEST(MESSAGE_TEST_NAME,
+ RegressionTestForParseMessageReadingUninitializedLimit) {
+ UNITTEST::TestAllTypes in_message;
+ in_message.mutable_optional_nested_message();
+ std::string serialized = in_message.SerializeAsString();
+ // We expect this to have 3 bytes: two for the tag, and one for the zero size.
+ // Break the size by making it overlong.
+ ASSERT_EQ(serialized.size(), 3);
+ serialized.back() = '\200';
+ serialized += std::string(10, '\200');
+ EXPECT_FALSE(in_message.ParseFromString(serialized));
+}
+
+TEST(MESSAGE_TEST_NAME,
+ RegressionTestForParseMessageWithSizeBeyondInputFailsToPopLimit) {
+ UNITTEST::TestAllTypes in_message;
+ in_message.mutable_optional_nested_message();
+ std::string serialized = in_message.SerializeAsString();
+ // We expect this to have 3 bytes: two for the tag, and one for the zero size.
+ // Make the size a valid varint, but it overflows in the input.
+ ASSERT_EQ(serialized.size(), 3);
+ serialized.back() = 10;
+ EXPECT_FALSE(in_message.ParseFromString(serialized));
+}
+
const uint8_t* SkipTag(const uint8_t* buf) {
while (*buf & 0x80) ++buf;
++buf;
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
index 11d2181..b96e7ac 100644
--- a/src/google/protobuf/parse_context.cc
+++ b/src/google/protobuf/parse_context.cc
@@ -319,26 +319,19 @@
}
const char* ParseContext::ReadSizeAndPushLimitAndDepth(const char* ptr,
- int* old_limit) {
- int size = ReadSize(&ptr);
- if (PROTOBUF_PREDICT_FALSE(!ptr) || depth_ <= 0) {
- *old_limit = 0; // Make sure this isn't uninitialized even on error return
- return nullptr;
- }
- *old_limit = PushLimit(ptr, size);
- --depth_;
- return ptr;
+ LimitToken* old_limit) {
+ return ReadSizeAndPushLimitAndDepthInlined(ptr, old_limit);
}
const char* ParseContext::ParseMessage(MessageLite* msg, const char* ptr) {
- int old;
+ LimitToken old;
ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
if (ptr == nullptr) return ptr;
auto old_depth = depth_;
ptr = msg->_InternalParse(ptr, this);
if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
depth_++;
- if (!PopLimit(old)) return nullptr;
+ if (!PopLimit(std::move(old))) return nullptr;
return ptr;
}
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
index e5b13a0..0ddaa26 100644
--- a/src/google/protobuf/parse_context.h
+++ b/src/google/protobuf/parse_context.h
@@ -36,11 +36,13 @@
#include <string>
#include <type_traits>
+#include "absl/base/config.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/cord.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
#include "google/protobuf/arena.h"
#include "google/protobuf/arenastring.h"
#include "google/protobuf/endian.h"
@@ -131,8 +133,53 @@
if (count > 0) StreamBackUp(count);
}
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || defined(ABSL_HAVE_MEMORY_SANITIZER)
+ // In sanitizer mode we use an optional<int> to guarantee that:
+ // - We do not read an uninitialized token.
+ // - Every non-empty token is moved from and consumed.
+ class LimitToken {
+ public:
+ LimitToken() = default;
+ explicit LimitToken(int token) : token_(token) {}
+ LimitToken(LimitToken&& other) { *this = std::move(other); }
+ LimitToken& operator=(LimitToken&& other) {
+ token_ = std::exchange(other.token_, absl::nullopt);
+ return *this;
+ }
+
+ ~LimitToken() { ABSL_CHECK(!token_.has_value()); }
+
+ LimitToken(const LimitToken&) = delete;
+ LimitToken& operator=(const LimitToken&) = delete;
+
+ int token() && {
+ ABSL_CHECK(token_.has_value());
+ return *std::exchange(token_, absl::nullopt);
+ }
+
+ private:
+ absl::optional<int> token_;
+ };
+#else
+ class LimitToken {
+ public:
+ LimitToken() = default;
+ explicit LimitToken(int token) : token_(token) {}
+ LimitToken(LimitToken&&) = default;
+ LimitToken& operator=(LimitToken&&) = default;
+
+ LimitToken(const LimitToken&) = delete;
+ LimitToken& operator=(const LimitToken&) = delete;
+
+ int token() const { return token_; }
+
+ private:
+ int token_;
+ };
+#endif
+
// If return value is negative it's an error
- PROTOBUF_NODISCARD int PushLimit(const char* ptr, int limit) {
+ PROTOBUF_NODISCARD LimitToken PushLimit(const char* ptr, int limit) {
ABSL_DCHECK(limit >= 0 && limit <= INT_MAX - kSlopBytes);
// This add is safe due to the invariant above, because
// ptr - buffer_end_ <= kSlopBytes.
@@ -140,12 +187,14 @@
limit_end_ = buffer_end_ + (std::min)(0, limit);
auto old_limit = limit_;
limit_ = limit;
- return old_limit - limit;
+ return LimitToken(old_limit - limit);
}
- PROTOBUF_NODISCARD bool PopLimit(int delta) {
+ PROTOBUF_NODISCARD bool PopLimit(LimitToken delta) {
+ // We must update the limit first before the early return. Otherwise, we can
+ // end up with an invalid limit and it can lead to integer overflows.
+ limit_ = limit_ + std::move(delta).token();
if (PROTOBUF_PREDICT_FALSE(!EndedAtLimit())) return false;
- limit_ = limit_ + delta;
// TODO(gerbens) We could remove this line and hoist the code to
// DoneFallback. Study the perf/bin-size effects.
limit_end_ = buffer_end_ + (std::min)(0, limit_);
@@ -470,13 +519,14 @@
template <typename TcParser, typename Table>
PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char* ParseMessage(
MessageLite* msg, const char* ptr, const Table* table) {
- int old;
+ LimitToken old;
ptr = ReadSizeAndPushLimitAndDepthInlined(ptr, &old);
+ if (ptr == nullptr) return ptr;
auto old_depth = depth_;
- ptr = ptr ? TcParser::ParseLoop(msg, ptr, this, table) : nullptr;
+ ptr = TcParser::ParseLoop(msg, ptr, this, table);
if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
depth_++;
- if (!PopLimit(old)) return nullptr;
+ if (!PopLimit(std::move(old))) return nullptr;
return ptr;
}
@@ -518,20 +568,20 @@
private:
// Out-of-line routine to save space in ParseContext::ParseMessage<T>
- // int old;
+ // LimitToken old;
// ptr = ReadSizeAndPushLimitAndDepth(ptr, &old)
// is equivalent to:
// int size = ReadSize(&ptr);
// if (!ptr) return nullptr;
- // int old = PushLimit(ptr, size);
+ // LimitToken old = PushLimit(ptr, size);
// if (--depth_ < 0) return nullptr;
- PROTOBUF_NODISCARD const char* ReadSizeAndPushLimitAndDepth(const char* ptr,
- int* old_limit);
+ PROTOBUF_NODISCARD const char* ReadSizeAndPushLimitAndDepth(
+ const char* ptr, LimitToken* old_limit);
// As above, but fully inlined for the cases where we care about performance
// more than size. eg TcParser.
PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char*
- ReadSizeAndPushLimitAndDepthInlined(const char* ptr, int* old_limit);
+ ReadSizeAndPushLimitAndDepthInlined(const char* ptr, LimitToken* old_limit);
// The context keeps an internal stack to keep track of the recursive
// part of the parse state.
@@ -881,27 +931,25 @@
!std::is_base_of<MessageLite, T>::value, bool>::type>
PROTOBUF_NODISCARD const char* ParseContext::ParseMessage(T* msg,
const char* ptr) {
- int old;
+ LimitToken old;
ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
if (ptr == nullptr) return ptr;
auto old_depth = depth_;
ptr = msg->_InternalParse(ptr, this);
if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
depth_++;
- if (!PopLimit(old)) return nullptr;
+ if (!PopLimit(std::move(old))) return nullptr;
return ptr;
}
inline const char* ParseContext::ReadSizeAndPushLimitAndDepthInlined(
- const char* ptr, int* old_limit) {
+ const char* ptr, LimitToken* old_limit) {
int size = ReadSize(&ptr);
- if (PROTOBUF_PREDICT_FALSE(!ptr)) {
- // Make sure this isn't uninitialized even on error return
- *old_limit = 0;
+ if (PROTOBUF_PREDICT_FALSE(!ptr) || depth_ <= 0) {
return nullptr;
}
*old_limit = PushLimit(ptr, size);
- if (--depth_ < 0) return nullptr;
+ --depth_;
return ptr;
}
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index ef458ad..35df77a 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -856,6 +856,19 @@
// PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
#define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, data, table, hasbits
+// PROTOBUF_TC_PARAM_NO_DATA_DECL and PROTOBUF_TC_PARAM_NO_DATA_PASS provide the
+// exact same ABI as above, except that they don't name or pass the `data`
+// argument. Specific functions such as `Error() and `ToTagDispatch()` don't
+// use the `data` argument. By not passing `data` down the call stack, we free
+// up the register holding that value, which may matter in highly optimized
+// functions such as varint parsing.
+#define PROTOBUF_TC_PARAM_NO_DATA_DECL \
+ ::google::protobuf::MessageLite *msg, const char *ptr, \
+ ::google::protobuf::internal::ParseContext *ctx, ::google::protobuf::internal::TcFieldData, \
+ const ::google::protobuf::internal::TcParseTableBase *table, uint64_t hasbits
+#define PROTOBUF_TC_PARAM_NO_DATA_PASS \
+ msg, ptr, ctx, ::google::protobuf::internal::TcFieldData::DefaultInit(), table, hasbits
+
#ifdef PROTOBUF_UNUSED
#error PROTOBUF_UNUSED was previously defined
#endif
@@ -1014,6 +1027,13 @@
// int index = ...
// int value = vec[index];
#pragma GCC diagnostic ignored "-Wsign-conversion"
+#if __GNUC__ == 12 && __GNUC_MINOR__ < 4
+// Wrong warning emitted when assigning a single char c-string to a std::string
+// in c++20 mode and optimization on.
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329
+// Planned to be fixed by 12.3 but widen window to 12.4.
+#pragma GCC diagnostic ignored "-Wrestrict"
+#endif
#endif // __GNUC__
// Silence some MSVC warnings in all our code.
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index e723394..67b6b3d 100644
--- a/src/google/protobuf/unknown_field_set_unittest.cc
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -46,6 +46,7 @@
#include "google/protobuf/testing/googletest.h"
#include <gtest/gtest.h>
#include "absl/container/flat_hash_set.h"
+#include "absl/functional/bind_front.h"
#include "absl/strings/cord.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"