From 35149013bfce328da702fee003fff9e69c9e3ba4 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Tue, 25 Nov 2025 10:04:56 -0800 Subject: [PATCH] Add check if sun.misc.Unsafe is present but throws on use, to use the preexisting no-Unsafe paths if it does. JavaProto is already robust in the absence of sun.misc.Unsafe, and checks for its existence via reflection to use as a performance optimization. As part of the planned removal of sun.misc.Unsafe, a future JDK will have Unsafe available but most of the methods will throw by default, which would break JavaProto. This creates an odd situation that if it was removed we wouldn't break, but the intermediate turndown state does break us. By adding a usage of one method to see if it throws an UnsupportedOperationException, we avoid breaking users if they use Protobuf in this intermediate turndown state of the API (which will become the default state in a future JDK release). It is still TBD whether a future release of Protobuf may stop using sun.misc.Unsafe always, or if we may keep this code alive for users running old JDKs; that detail is still TBD depending on performance implications. https://github.com/protocolbuffers/protobuf/issues/20760 PiperOrigin-RevId: 836715451 --- .../java/com/google/protobuf/UnsafeUtil.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java index 98608a577133e..c9dec67c95446 100644 --- a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java +++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java @@ -284,7 +284,30 @@ public sun.misc.Unsafe run() throws Exception { // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError // for Unsafe. } - return unsafe; + + if (unsafe == null) { + return null; + } + + // Unsafe is terminally deprecated and will be removed in a future version. Our runtime is + // anyway compatible with environments where Unsafe is not available, but as part of the removal + // some environments will have Unsafe available but throw on use, which would break us. To check + // if the JDK is in this state, simply try using a method and see if it does throw. + try { + int unused = unsafe.arrayBaseOffset(byte[].class); + return unsafe; + } catch (Exception unused) { + Logger.getLogger(UnsafeUtil.class.getName()) + .log( + Level.WARNING, + "As part of the planned removal, sun.misc.Unsafe is available in the current" + + " environment but configured to throw on use. Protobuf will continue without" + + " using it, but with slightly reduced performance." + + " --sun-misc-unsafe-memory-access=allow is likely available to opt back in if" + + " desired. A later Protobuf version release will stop using sun.misc.Unsafe" + + " entirely."); + return null; + } } /** Get a {@link MemoryAccessor} appropriate for the platform, or null if not supported. */