Skip to content

HiddenClassDefiner incorrectly assumes Unsafe.staticFieldBase(Field) returns a real Object #1672

Closed

Description

The combination of Google Guice 5.1.0 and the Azul Prime JVM is causing a VM crash. I've reached out to Azul support about this and they believe that the root cause is that the class com.google.inject.internal.aop.HiddenClassDefiner treats a klassOop as though it were an Object.

HiddenClassDefiner defines TRUSTED_LOOKUP_BASE like this:

private static final Object TRUSTED_LOOKUP_BASE;

And its value is obtained like this:

Method baseMethod = unsafeType.getMethod("staticFieldBase", Field.class);
TRUSTED_LOOKUP_BASE = baseMethod.invoke(THE_UNSAFE, trustedLookupField);

So TRUSTED_LOOKUP_BASE, nominally a private static final Object, is obtained by calling Unsafe.staticFieldBase() via reflection.

Here's how it's used in Guice:

public Class<?> define(Class<?> hostClass, byte[] bytecode) throws Exception {
    Lookup trustedLookup =
        (Lookup) GET_OBJECT_METHOD.invoke(THE_UNSAFE, TRUSTED_LOOKUP_BASE, TRUSTED_LOOKUP_OFFSET);

Which calls Unsafe.getObject((Object)TRUSTED_LOOKUP_BASE, (long)TRUSTED_LOOKUP_OFFSET).

This use of TRUSTED_LOOKUP_BASE ignores the admonitions of Unsafe.staticFieldBase(), which says the value is not guaranteed to be a real Object:

/**
 * Reports the location of a given static field, in conjunction with {@link
 * #staticFieldOffset}.
 * <p>Fetch the base "Object", if any, with which static fields of the
 * given class can be accessed via methods like {@link #getInt(Object,
 * long)}.  This value may be null.  This value may refer to an object
 * which is a "cookie", not guaranteed to be a real Object, and it should
 * not be used in any way except as argument to the get and put routines in
 * this class.
 */
@ForceInline
public Object staticFieldBase(Field f) {

Now, a lot of reflection code is generated on the fly at runtime and inlined. I'm also told the Prime VM emits a checkcast bytecode, which does what it says and checks the reference to be returned by getObject is, in fact, an Object, which a klassOop isn't. Hence the attempt to throw a ClassCastException in a place where the VM shouldn't.

Here is the hs_err file for the crash: hs_err_pid12.log.gz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions