Commit graph

1104 commits

Author SHA1 Message Date
Protobuf Team Bot
94de7ab2b3 Introduce getMessageExtensionOrNull for extendable messages to avoid the code pattern of hasExtension() ? getExtension : null which takes an extra extension lookup.
PiperOrigin-RevId: 926787242
2026-06-04 11:17:43 -07:00
Protobuf Team Bot
791fbe2249 Support merging lazy fields with different default instances but equal descriptor types; e.g. DynamicMessage
Lazy field should only be applicable to full message, whose `mergeFrom(Message)` supports merging from a different message but with the same descriptor. Therefore, this change abandons the default instance check in the lazy field impl.

Also note that InternalLazyField currently belongs to the lite runtime, so direct access to descriptors is infeasible, thus depending on the mergeFrom overrides to invoke the full merging method.

PiperOrigin-RevId: 926112976
2026-06-03 10:15:18 -07:00
Protobuf Team Bot
50ac9feec5 Micro-optimize latin1Cat() to speed up protobuf descriptor initialization.
We have to break up the descriptors into multiple strings because of the 64k cap on string literals and then join them back up at runtime. This change we avoid building the intermediate joined string before extracting it back as byte[], and instead pre-allocate the total byte[] array first and turns each 64kb segment to byte[] and uses System.arraycopy to copy them directly.

This avoids some pointless work, but also removes garbage copies. Note that its a garbage copy that should be escape-analysis by the JVM and so should be very cheap, but still cheaper not to.

PiperOrigin-RevId: 925969602
2026-06-03 05:56:44 -07:00
Protobuf Team Bot
11f708e186 Shrink gencode parsePartialFrom() by pushing the exception wrapping to a helper.
By outlining the exception handling path, this notably shrinks this method to below 35 bytes in .class bytecode representation, which is one of the magic arbitrary limits that influences JIT inlining behaviors.

PiperOrigin-RevId: 925530732
2026-06-02 13:01:34 -07:00
Protobuf Team Bot
d1e6ad01ec Move the "same instance" check at mergeFrom(MessageLite) into GeneratedMessageLite.
In `AbstractMessageLite.Builder.mergeFrom(MessageLite)`, it either goes into (full runtime) `AbstractMessage` which supports merge from a different instance but the same *descriptor* type, or into the lite runtime path which should not support it in the absence of descriptors .e.g in case of `DynamicMessage`.

PiperOrigin-RevId: 924941126
2026-06-01 15:25:40 -07:00
Protobuf Team Bot
529daaa6e8 Micro-optimize fieldsSortedByNumber to just point an fields normally.
PiperOrigin-RevId: 924916713
2026-06-01 14:34:37 -07:00
Protobuf Team Bot
64d0bca8af Avoid always parsing all lazy extensions on equals()
Today, equals() causes all lazy extensions to be parsed before the equality check starts. After this change, equals() will try to avoid hitting lazy parsing if possible

Notably:
- When the count of extensions don't match, or if "which extensions are set" don't match, we can return false before looking at any extension values.

- When actually comparing extensions, it goes iteratively which means it'll only parse the extensions as it goes; if it finds any one ext which is not-equal it will will bail out and not parse any of the rest.

Note that when the case where two messages are equal, this unavoidably still cause all extensions to parse since it has to examine all fields.

To achieve this does require adding a protected `extensionsEquals()` method for the gencode to call, since the current base class API isn't otherwise powerful enough to do so.

PiperOrigin-RevId: 924903438
2026-06-01 14:12:34 -07:00
Protobuf Team Bot
547b9d505a Clean up remaining defunct experimental runtime JavaFull runtime schema classes.
These paths were in support of the experimental runtime and are not reachable by any exposed public APIs today.

PiperOrigin-RevId: 919828913
2026-05-22 13:21:43 -07:00
Protobuf Team Bot
710de9f91e Add clear error message if MessageSchema is reached in an environment without sun.misc.Unsafe.
This exception is put at the spot where we will typically first notice that we cannot continue due to being on Lite gencode flows and that sun.misc.Unsafe is unavailable.

Add corresponding note on lite.md that it requires sun.misc.Unsafe

PiperOrigin-RevId: 919813377
2026-05-22 12:49:21 -07:00
Protobuf Team Bot
6221a32e9b Delete defunct ExtensionSchemaFull paths.
These paths are 100% unreachable today via our public APIs (they're only reachable by our tests which pierce-the-veil of the package-protected api). The only entry point is via GeneratedMessageLite, and this code already checks for GeneratedMessageLite types and always uses the Lite types.

This behavior means that even if someone in OSS uses Lite gencode on Full runtime this path is never reachable today.

PiperOrigin-RevId: 917409414
2026-05-18 13:55:52 -07:00
Protobuf Team Bot
ec52338ef0 Remove experimental FieldOrder enum.
The only field order used in practice is ASCENDING. DESCENDING was added for the experimental JavaProto runtime which is now defunct.

PiperOrigin-RevId: 917271023
2026-05-18 09:20:02 -07:00
Protobuf Team Bot
2a4aa7b363 Remove unused SchemaFactory interface.
This relates to the defunct experimental runtime; today it is implemented exactly once and never otherwise named.

PiperOrigin-RevId: 917250284
2026-05-18 08:37:29 -07:00
Protobuf Team Bot
a37dbd6433 Optimize GeneratedMessage.ExtendableBuilder to avoid temporary allocations when merging empty extendable messages.
When toBuilder() is called on an immutable ExtendableMessage whose extensions field is the singleton FieldSet.emptySet(), generated code calls ExtendableBuilder.mergeExtensionFields(other).

Because other.extensions is FieldSet.emptySet() (which is not null), mergeExtensionFields previously invoked ensureExtensionsIsMutable(), which unnecessarily allocated a brand new temporary FieldSet.Builder and SmallSortedMap. Later, when build() executed, FieldSet.Builder.buildImpl recognized that the builder's map was empty and correctly returned the singleton FieldSet.emptySet().

By checking !other.extensions.isEmpty() before mutating the builder, we completely eliminate these wasted temporary allocations.

PiperOrigin-RevId: 916174058
2026-05-15 14:08:21 -07:00
Protobuf Team Bot
d3e5c57820 Small cleanup/micro-optimization of GeneratedMessage.java
PiperOrigin-RevId: 916113557
2026-05-15 11:55:09 -07:00
Protobuf Team Bot
5613198ab6 Refactor to shrink CodedInputStream.readMessage, to increase where it is inlined.
The refactor shrinks the method's bytecode to be below 35 bytes instead of above, and 35 bytes is one of the relevant default threshold conditions for inlining.

The theory behind this change is to improve a very hot case of:
- gencode always calls readMessage with the concrete builder types of fields
- That means readMessage itself is called with all reachable Builder types
- If readMessage is not inlined, it will be highly megamorphic (= too many different types for the JIT to try to monomorphize it), which makes it true dynamic dispatch at runtime. But if it is inlined instead, then it will trivially dispatch to one specific Builder type instead.

It isn't so easy to benchmark how much this will impact the fleet in reality, but since this change is otherwise very benign we can just make the change and then post-hoc see if it looks like it improved things.

PiperOrigin-RevId: 915625779
2026-05-14 14:46:01 -07:00
Protobuf Team Bot
4d47a27afe Optimize ArrayDecoder limit handling to reduce the amount of math it has to do.
This change also aims to make the interaction of the three 'limit' bools less confusing.

PiperOrigin-RevId: 915481259
2026-05-14 09:57:19 -07:00
Protobuf Team Bot
4d0c6a224d Tighten generic bounds of SmallSortedMap
PiperOrigin-RevId: 915464877
2026-05-14 09:22:12 -07:00
Protobuf Team Bot
4a437639e5 Make it so Utf8 UnsafeProcessor is not guarded by the runtime availability of sun.misc.Unsafe
The last usages of UnsafeUtil from the UnsafeProcessor were removed in a previous change.

The name 'UnsafeProcessor' was already a bit stale, and is now very stale. But not renaming it now to reduce churn if this has to be rolled back. After this sticks, we should come back and do a pass to rename them to 'StandardProcessor' versus 'AndroidOnDeviceProcessor'

PiperOrigin-RevId: 914424161
2026-05-12 12:42:24 -07:00
Protobuf Team Bot
1b3e08719e Remove UnsafeUtil usage from IterableByteBufferInputStream.
This use was somewhat buggy: it would have broken if used on a non-Direct Buffer, or if it was executed in a context where sun.misc.Unsafe was not available.

This path is empirically extremely rarely reached, and so we will just use the 'natural' API as part of getting off of the terminally deprecated sun.misc.Unsafe

PiperOrigin-RevId: 914423267
2026-05-12 12:38:18 -07:00
Protobuf Team Bot
fddc1b240a Remove Unsafe usage from CodedOutputStream.
This change effectively has the runtime behavior of hardcoding HAS_UNSAFE_ARRAY_OPERATIONS to false, which was measured as a net performance improvement after the recent loop unrolling changes.

This is one of the last steps towards no longer using the terminally deprecated sun.misc.Unsafe from JavaFull.

PiperOrigin-RevId: 914398839
2026-05-12 11:49:34 -07:00
Protobuf Team Bot
7174939dc2 Unroll the varint loops in CodedOutputStream
This change is in preparation for a subsequent change which will disable sun.misc.Unsafe usage. Simply turning off s.m.Unsafe would result in some small but measurably regressions; unrolling these loops by contrast provides a significant speedup, which should more than outweighs any regression we will get from the disabling Unsafe. This will make it easier for us to roll out the change to stop using Unsafe without problems from regression.

PiperOrigin-RevId: 913906295
2026-05-11 15:19:52 -07:00
Protobuf Team Bot
5b3b31d0b4 Optimize serializing of negative int32s.
Right now we delegate negative int32s to the int64 encoder, which has to still figure out how many bytes its going to take, which is wasted work since we already checked the top bit and know it will be exactly 10 byte varint.

PiperOrigin-RevId: 913824216
2026-05-11 12:23:05 -07:00
Protobuf Team Bot
be2c9d04f9 JavaProto: Unroll the Uint32 varint serialization.
This was changed in 2020 to an unrolled loop with Unsafe but was rolled back after external reports that it was a regression (https://github.com/protocolbuffers/protobuf/issues/6977). However, not only has JIT behavior evolved in that amount of time, the main external claim appears to have been that the `int position = this.position;` local variable optimization was lost at that time, with one the first comments on that issue noting that restoring that also fixed the regression.

Today, all available benchmarks suggest that this should be good change to make (with the local variable position optimization included), ~twice as fast for direct Uint32 writes usages.

PiperOrigin-RevId: 913780730
2026-05-11 10:59:27 -07:00
Protobuf Team Bot
890ffb9eeb Remove dead code for IsValidUtf8 in Utf8.java
This per-processor path static method implementation in a previous change.

This is incremental progress towards migrating off of sun.misc.Unsafe which is terminally deprecated.

PiperOrigin-RevId: 912643167
2026-05-08 12:37:43 -07:00
Protobuf Team Bot
79129d9e0e Remove unused ByteBufferWriter and its tests
ByteBufferWriter has no usages.

PiperOrigin-RevId: 912191309
2026-05-07 15:45:09 -07:00
Protobuf Team Bot
00b6ad443a Remove decodeUtf8Direct()
This path uses sun.misc.Unsafe which is terminally deprecated. Although it is theoretically 'good' that we can optimize a Direct buffer faster than the basic APIs, this is empirically never reached in all of Google's internal use. With sun.misc.Unsafe going away and no easy replacement, this is turning down the corner case optimization.

PiperOrigin-RevId: 912177627
2026-05-07 15:19:50 -07:00
Protobuf Team Bot
421d7451ef Stop using sun.misc.Unsafe in isValidUtf8 paths.
This is a step towards turning down Protobuf's use of sun.misc.Unsafe (which is terminally deprecated)

When benchmarking a new VarHandle based approach, the SafeProcessor path actually benchmarked fastest excepting on pure ascii data sets, so we will move to this.

Arrays:

| Distribution | Unsafe Before (ns/op) | Safe After (ns/op) | Delta |
| :--- | :--- | :--- | :--- |
| PURE_ASCII | 131597 | 394507 | +199.8% (Slower) |
| PURE_UTF16 | 3086719 | 2630915 | -14.8% (Faster) |
| GMM | 734551 | 381681 | -48.0% (Faster) |
| GSR | 1153690 | 846964 | -26.6% (Faster) |

ByteBuffers:

| Distribution | Unsafe Before (ns/op) | Safe After (ns/op) | Delta |
| :--- | :--- | :--- | :--- |
| PURE_ASCII | 92061 | 53868 | -41.5% (Faster) |
| PURE_UTF16 | 3091502 | 2512527 | -18.7% (Faster) |
| GMM | 712349 | 421433 | -40.8% (Faster) |
| GSR | 1157134 | 933073 | -19.4% (Faster) |

PiperOrigin-RevId: 912096277
2026-05-07 12:29:00 -07:00
Liam Miller-Cushon
efca121a66 Use String#encodedLength on JDK versions that support it
See https://bugs.openjdk.org/browse/JDK-8372353

PiperOrigin-RevId: 910554784
2026-05-05 03:08:31 -07:00
Protobuf Team Bot
5a1f2ac62e Improve behavior under the risk of an int overflow and negative lengths in JavaLite
PiperOrigin-RevId: 908845731
2026-05-01 12:27:08 -07:00
Protobuf Team Bot
a8896e84d6 Auto-generate files after cl/908404027 2026-04-30 22:31:44 +00:00
Protobuf Team Bot
44025909eb Partially parse bytes when lazy field is firstly initialized.
PiperOrigin-RevId: 908371173
2026-04-30 14:18:30 -07:00
Protobuf Team Bot
760418056a Let message parsing reads the in-memory data of CodedInputStream directly instead of parsing from input.readBytes which copies the data.
PiperOrigin-RevId: 905202710
2026-04-24 13:50:41 -07:00
Protobuf Team Bot
26569defeb Fix NPE when a message with parsed extension merges from bytes that contain extension data and when lazy mode is enabled.
PiperOrigin-RevId: 904139856
2026-04-22 17:42:01 -07:00
Protobuf Team Bot
b3d784c7b2 Make Java Protobuf runtime fully aware of lazy extension field.
PiperOrigin-RevId: 903933554
2026-04-22 10:57:26 -07:00
Protobuf Team Bot
30b067fd78 Auto-generate files after cl/903894356 2026-04-22 16:51:38 +00:00
Protobuf Team Bot
33e6ab172b Add comments to TextFormat documenting that its intended for human-in-the-loop usecases (not wire format).
In the cases where we historically didn't enforce a depth limit (C++ and Python) document that the default behavior having no depth limit is an intentional decision.

PiperOrigin-RevId: 903216142
2026-04-21 07:22:43 -07:00
Samuel Benzaquen
e6ee74af87 Updating version.json and repo version numbers to: 36.0-dev (#26991)
NOTE: This should be reviewed and imported via Copybara per the normal PR review process.

Closes #26991

PiperOrigin-RevId: 902788011
2026-04-20 13:14:04 -07:00
Protobuf Team Bot
4c7b62afc5 Improve unknown groups depth check in UnknownFieldSetLite.
PiperOrigin-RevId: 900677386
2026-04-16 05:42:31 -07:00
Protobuf Team Bot
87f20a9cf9 More cleary document that Lite is targeting mobile client rather than server use.
PiperOrigin-RevId: 900254126
2026-04-15 11:11:02 -07:00
Protobuf Team Bot
345b1784ef Improve InternalLazyField to support "merge" functions, and add a flag to control the laziness.
PiperOrigin-RevId: 899072326
2026-04-13 10:50:28 -07:00
Venkatesan
35371e7ac0 Fix unguarded recursion DoS in Protobuf Lite skipField (#26670)
## Fix unguarded recursion DoS in Protobuf Lite skipField

This PR addresses a missing recursion depth limit check in `ArrayDecoders.skipField()` that causes a `StackOverflowError` and subsequent Denial of Service.

### Vulnerability Context
The initial patch for CVE-2024-7254 correctly added recursion limits to the standard `CodedInputStream` and `decodeUnknownField` in the Lite fast-path array decoders. However, `ArrayDecoders.skipField()` handles the `WIRETYPE_START_GROUP` recursively without checking or incrementing `Registers.recursionDepth`.

This omission exposes any Protobuf Java Lite application that accepts unauthenticated binary input to a remote DoS via simple stack overflow payloads.

**The bug is reachable via two independent paths from Public APIs:**
1. **Legacy Vectors:** `message_set_wire_format`. A payload containing thousands of nested unknown groups inside a MessageSet forces `MessageSetSchema.mergeFrom` to invoke `skipField()`.
2. **Universal Vectors:** Standard Maps! `MessageSchema.decodeMapEntry` handles unrecognized tags inside a map entry by calling `ArrayDecoders.skipField()`. Nesting thousands of groups inside a standard map entry instantly crashes the JVM process.

### Fix
Added `registers.recursionDepth++` and `checkRecursionLimit()` to the `WIRETYPE_START_GROUP` branch in `skipField()`, aligning it securely with `decodeUnknownField()`.

### Issue Link
Additional discussion and reproduction code is documented internally at:
https://issuetracker.google.com/issues/498542124

Closes #26670

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/26670 from VenkatKwest:fix-unguarded-recursion-lite 3660dd6bce
PiperOrigin-RevId: 899005419
2026-04-13 08:36:19 -07:00
Protobuf Team Bot
32cdc7febb Introduce an internal-only InternalLazyField as the implementation details to replace LazyField, while still allowing users to construct their own LazyField and set to message with reflection.
PiperOrigin-RevId: 897159373
2026-04-09 09:45:16 -07:00
Protobuf Team Bot
1ffc1a2a22 Auto-generate files after cl/895988455 2026-04-07 18:09:27 +00:00
Protobuf Team Bot
44c2961be2 Automated rollback of commit 043a2e1b35.
PiperOrigin-RevId: 895402507
2026-04-06 10:57:58 -07:00
James Yuzawa
2812ead4d5 minor: optimize isInitialized() in DynamicMessage and MessageReflection (#25277)
these loops are quite hot, so do simple iteration. also skip the overhead of getFields(). this means we skip 1) creating a list from the internal fields array, 2) creating an unmodifiable list 3) creating an iterator for that list 4) the overhead of calling the iterator's hasNext() and next() methods (which in turn have to call the wrapped iterator). i skipped doing the same in GeneratedMessage since the generated messages have optimized isInitialized implementations already.

here is a screenshot from a cpu flamechart (i believe this change would remove all of the pink and then some):

<img width="1612" height="478" alt="image" src="https://github.com/user-attachments/assets/73ce5629-ecce-4f0b-a7de-4906fcd68533" />

here is an excerpt from the memory flamechart:

<img width="1614" height="397" alt="image" src="https://github.com/user-attachments/assets/7e3fa66a-a2c8-420f-a3d4-a84788af65ad" />

background: i am using kafka connect to process a lot of protobuf messages and that uses their schema registry which uses protobuf's DynamicMessage.

Closes #25277

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/25277 from yuzawa-san:dynamic-message-is-initialized fa1e1f7c17
PiperOrigin-RevId: 893693587
2026-04-02 14:09:32 -07:00
Sandy Zhang
78dd531ff4 Add test assertions for not linked in option_deps now that we've dropped support for Bazel 7.
PiperOrigin-RevId: 891938475
2026-03-30 15:23:16 -07:00
Protobuf Team Bot
da6d5b688c Add comments to TypeRegistry about the duplicates behavior.
PiperOrigin-RevId: 891862890
2026-03-30 12:56:29 -07:00
Mark Hansen
06f6808811 Extract throwing exception into @DoNotInline method
Exception throwing is expensive: it increases inlining cost and
generates lots of assembly. If we can hide it away in its own function,
that makes the other functions in here more tempting for Android's
inliner; e.g. `set` might be small enough to inline now.

PiperOrigin-RevId: 888897688
2026-03-24 15:57:18 -07:00
Mark Hansen
f2de306d95 Tag AbstractProtobufList.ensureIsMutable as final
This communicates to readers that it's not for overriding.

This method is hot; it indicates to the compiler that it can inline or
optimise this further.

In practice, R8 will turn all not-overriden methods to be final, so this will only improve performance in unoptimised dev builds.

PiperOrigin-RevId: 888885902
2026-03-24 15:31:13 -07:00
Protobuf Team Bot
bf85e91065 internal changes
PiperOrigin-RevId: 888851908
2026-03-24 14:20:00 -07:00