Commit graph

1576 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
ae1faeedfd Use natural String comparison instead of UTF-8 ByteString comparison for sorting map keys in JsonFormat.
This only changes the sort order in an obscure edge case of map-keys which sort differently in Utf8 and Utf16, meaning a mix of certain characters that are "very high code point but still single char" and "utf16 surrogate pairs".

PiperOrigin-RevId: 922768203
2026-05-28 07:45:14 -07:00
Protobuf Team Bot
61dfcbc7cf Optimize JsonFormat by handling the newline pretty printing better.
PiperOrigin-RevId: 922127998
2026-05-27 07:56:12 -07:00
Protobuf Team Bot
bca685147b Optimize JavaProto JSON string escaping handling.
PiperOrigin-RevId: 921615825
2026-05-26 12:27:10 -07:00
Protobuf Team Bot
40825a1df7 Add option to enable strict JSON parsing in Protobuf Java JsonFormat.
JsonFormat used 'reader.setLenient(false)' to try to get spec JSON behavior out of GSON. However, this mode was still not actually spec JSON. In ~2024 GSON deprecated setLenient(), made that behavior LEGACY_STRICT and added a new level STRICT which is intended to be spec.

Switching unilaterally would be a breaking change for Protobuf: this change just adds the option for users to ask us to use GSON in strict mode. At a later date we will consider flipping the default of this (letting people opt into LEGACY_STRICT if they want to).

PiperOrigin-RevId: 921432331
2026-05-26 06:39:41 -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
Mindflare
25e7005814 java: limit numeric string length before BigDecimal parsing (#26908)
## Summary

`BigDecimal(String)` has O(N²) time complexity for N-digit strings on JDK versions before 18 ([JDK-8291514](https://bugs.openjdk.org/browse/JDK-8291514)). Five JSON parser methods — `parseInt32`, `parseInt64`, `parseUint32`, `parseUint64`, and `parseDouble` — pass user-controlled strings directly to `new BigDecimal()` without length validation.

A single JSON numeric value with 1,000,000 digits takes ~13 seconds to parse on JDK 17. This can be used to DoS any service that parses protobuf JSON messages with numeric fields from untrusted input.

### Benchmark (JDK 17, x86-64 Linux)

| Digits | BigDecimal construction time |
|--------|-----|
| 1,000 | 1.8 ms |
| 10,000 | 6.3 ms |
| 100,000 | 133 ms |
| 1,000,000 | **13.1 seconds** |

### Fix

Added a `parseBigDecimal()` helper that rejects strings longer than 1000 characters before constructing `BigDecimal`. This is generous — valid protobuf numeric values never exceed ~350 characters (Double.MAX_VALUE in non-scientific notation is ~309 digits).

### Affected JDK versions

- JDK 8, 11, 17 (all current LTS releases): **Vulnerable** — no built-in string length limit in BigDecimal
- JDK 18+: JDK itself limits BigDecimal string input to 1100 characters by default (JDK-8291514), but the protobuf-level check is still worthwhile as defense-in-depth

### Test

Added `testParserRejectOverlyLongNumericStrings` covering all 5 affected field types.

Closes #26908

COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/26908 from MindflareX:fix/java-bigdecimal-length-check a461d0edc6
PiperOrigin-RevId: 904988136
2026-04-24 06:12:50 -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
34cb33b197 Improve FieldMaskTree behavior in the face of extremely 'long' field paths (ones with a large number of periods)
PiperOrigin-RevId: 898950610
2026-04-13 06:00:20 -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