Skip to content

Commit

Permalink
Rework sun.misc.Unsafe usages so that we directly refer to sun.misc.U…
Browse files Browse the repository at this point in the history
…nsafe, and call getObject on it natively instead of through reflection.

Calling getObject through reflection breaks Azul JVMs, because the staticFieldBase is a funny "not object", but when passed through reflection it tries to become an Object and fails.

Retrieval of the unsafe is based on how other google open source projects do it, see for example [AbstractFuture](https://github.com/google/guava/blob/d4bd0c5ffa913104283e61aeb2c41bac641af042/guava/src/com/google/common/util/concurrent/AbstractFuture.java#L1340-L1365), [UnsignedBytes](https://github.com/google/guava/blob/6405852bbf453b14d097b8ec3bcae494334b357d/guava/src/com/google/common/primitives/UnsignedBytes.java#L341-L366), and [protobufs](https://github.com/protocolbuffers/protobuf/blob/520c601c99012101c816b6ccc89e8d6fc28fdbb8/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java#L289-L315).

Fixes #1719, and properly fixes #1672.

(Note that this change also bumps the Github Action's bazel version from 4.2.2 to 6.1.2, because somewhere along the way from 4.2.2->6.1.2, Bazel fixed the `--javacopts="--release 8"` option to also allow `sun.misc.Unsafe`.)

PiperOrigin-RevId: 529465570
  • Loading branch information
sameb authored and Guice Team committed May 4, 2023
1 parent 3bb74d7 commit 95a2fbb
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Expand Up @@ -2,7 +2,7 @@
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
name: continuous-integration
env:
USE_BAZEL_VERSION: '4.2.2'
USE_BAZEL_VERSION: '6.1.2'
USE_JAVA_DISTRIBUTION: 'zulu'
USE_JAVA_VERSION: '11'

Expand Down
Expand Up @@ -16,7 +16,6 @@

package com.google.inject.internal.aop;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
Expand All @@ -26,17 +25,16 @@
*/
final class AnonymousClassDefiner implements ClassDefiner {

private static final Object THE_UNSAFE;
private static final sun.misc.Unsafe THE_UNSAFE;
private static final Method ANONYMOUS_DEFINE_METHOD;

static {
try {
Class<?> unsafeType = Class.forName("sun.misc.Unsafe");
Field theUnsafeField = unsafeType.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
THE_UNSAFE = theUnsafeField.get(null);
THE_UNSAFE = UnsafeGetter.getUnsafe();
// defineAnonymousClass was removed in JDK17, so we must refer to it reflectively.
ANONYMOUS_DEFINE_METHOD =
unsafeType.getMethod("defineAnonymousClass", Class.class, byte[].class, Object[].class);
sun.misc.Unsafe.class.getMethod(
"defineAnonymousClass", Class.class, byte[].class, Object[].class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
Expand Down
18 changes: 7 additions & 11 deletions core/src/com/google/inject/internal/aop/HiddenClassDefiner.java
Expand Up @@ -28,22 +28,18 @@
*/
final class HiddenClassDefiner implements ClassDefiner {

private static final Object THE_UNSAFE;
private static final Object TRUSTED_LOOKUP_OFFSET;
private static final Method GET_OBJECT_METHOD;
private static final sun.misc.Unsafe THE_UNSAFE;
private static final Object TRUSTED_LOOKUP_BASE;
private static final long TRUSTED_LOOKUP_OFFSET;
private static final Object HIDDEN_CLASS_OPTIONS;
private static final Method HIDDEN_DEFINE_METHOD;

static {
try {
Class<?> unsafeType = Class.forName("sun.misc.Unsafe");
Field theUnsafeField = unsafeType.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
THE_UNSAFE = theUnsafeField.get(null);
THE_UNSAFE = UnsafeGetter.getUnsafe();
Field trustedLookupField = Lookup.class.getDeclaredField("IMPL_LOOKUP");
Method offsetMethod = unsafeType.getMethod("staticFieldOffset", Field.class);
TRUSTED_LOOKUP_OFFSET = offsetMethod.invoke(THE_UNSAFE, trustedLookupField);
GET_OBJECT_METHOD = unsafeType.getMethod("getObject", Object.class, long.class);
TRUSTED_LOOKUP_BASE = THE_UNSAFE.staticFieldBase(trustedLookupField);
TRUSTED_LOOKUP_OFFSET = THE_UNSAFE.staticFieldOffset(trustedLookupField);
HIDDEN_CLASS_OPTIONS = classOptions("NESTMATE");
HIDDEN_DEFINE_METHOD =
Lookup.class.getMethod(
Expand All @@ -56,7 +52,7 @@ final class HiddenClassDefiner implements ClassDefiner {
@Override
public Class<?> define(Class<?> hostClass, byte[] bytecode) throws Exception {
Lookup trustedLookup =
(Lookup) GET_OBJECT_METHOD.invoke(THE_UNSAFE, Lookup.class, TRUSTED_LOOKUP_OFFSET);
(Lookup) THE_UNSAFE.getObject(TRUSTED_LOOKUP_BASE, TRUSTED_LOOKUP_OFFSET);
Lookup definedLookup =
(Lookup)
HIDDEN_DEFINE_METHOD.invoke(
Expand Down
40 changes: 40 additions & 0 deletions core/src/com/google/inject/internal/aop/UnsafeGetter.java
@@ -0,0 +1,40 @@
/*
* Copyright (C) 2023 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.inject.internal.aop;

final class UnsafeGetter {

private UnsafeGetter() {}

static sun.misc.Unsafe getUnsafe() throws ReflectiveOperationException {
try {
return sun.misc.Unsafe.getUnsafe();
} catch (SecurityException unusedFallbackToReflection) {
}
// Note that we do not do this in a privileged action because we expect we're already in a
// privileged block (from UnsafeClassDefiner).
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
for (java.lang.reflect.Field f : k.getDeclaredFields()) {
f.setAccessible(true);
Object x = f.get(null);
if (k.isInstance(x)) {
return k.cast(x);
}
}
throw new NoSuchFieldError("the Unsafe");
}
}

0 comments on commit 95a2fbb

Please sign in to comment.