Skip to content

Commit

Permalink
Rework visibility checks for Java integration
Browse files Browse the repository at this point in the history
In jruby#8061 we found that Gradle is opening several core JDK packages
to support the needs of Groovy. Unfortunately this causes some
normally-inaccessible methods to be accessible to JRuby's Java
integration layer. In the case of HashSet, a package-private
`map` method gets bound that conflicts with the Ruby version,
leading to the bug reported in jruby#8061.

Gradle's behavior is unsanitary, but ultimately the fix we have
settled on here is to never try to set package-private methods
accessible since they are truly not intended for consumption
outside the package. That fixes this issue without addressing the
larger problem of Gradle opening up core JDK packages.

Fixes jruby#8061
  • Loading branch information
headius committed Feb 7, 2024
1 parent 15afb12 commit de5aa75
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 37 deletions.
30 changes: 2 additions & 28 deletions core/src/main/java/org/jruby/ext/ffi/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ public class Platform {
protected final int addressSize, longSize;
private final long addressMask;
protected final Pattern libPattern;
private int javaVersionMajor = -1;

public enum OS_TYPE {
DARWIN,
Expand Down Expand Up @@ -276,34 +275,9 @@ public final CPU_TYPE getCPU() {
return CPU;
}

/**
* Gets the version of the Java Virtual Machine (JVM) jffi is running on.
*
* @return A number representing the java version. e.g. 8 for java 1.8, 9 for java 9
*/
@Deprecated
public final int getJavaMajorVersion() {
if (javaVersionMajor != -1) return javaVersionMajor;

int version = 5;
try {
String versionString = SafePropertyAccessor.getProperty("java.version");
if (versionString != null) {
// remove additional version identifiers, e.g. -ea
versionString = versionString.split("-|\\+")[0];
String[] v = versionString.split("\\.");
if (v[0].equals("1")) {
// Pre Java 9, 1.x style
version = Integer.valueOf(v[1]);
} else {
// Java 9+, x.y.z style
version = Integer.valueOf(v[0]);
}
}
} catch (Exception ex) {
version = 0;
}

return javaVersionMajor = version;
return org.jruby.platform.Platform.JAVA_VERSION;
}
public final boolean isBSD() {
return OS == OS.FREEBSD || OS == OS.OPENBSD || OS == OS.NETBSD || OS == OS.DARWIN || OS == OS.DRAGONFLYBSD;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.jruby.java.util.ClassUtils;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaSupportImpl;
import org.jruby.platform.Platform;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
Expand Down Expand Up @@ -717,17 +718,28 @@ private static class PartitionedMethods {
}

private static boolean filterAccessible(Method method, int mod) {
// Skip private methods, since they may mess with dispatch
if (Modifier.isPrivate(mod)) return false;

// Skip protected methods if we can't set accessible
if (!Modifier.isPublic(mod) && !Java.trySetAccessible(method)) return false;

// ignore bridge methods because we'd rather directly call methods that this method
// is bridging (and such methods are by definition always available.)
// Exclude bridge methods
if ((mod & ACC_BRIDGE) != 0) return false;

return true;
if (Modifier.isPublic(mod)) {
// Include public
return true;
} else if (Modifier.isPrivate(mod)) {
// Exclude private
return false;
} else if (Modifier.isProtected(mod)) {
// Include protected if they can be set accessible
return Java.trySetAccessible(method);
} else {
// We split this on 17 because at that level unopened non-public functions are inaccessible
if (Platform.JAVA_VERSION < 17) {
// Include package-private if they can be set accessible on Java 16 and earlier
return Java.trySetAccessible(method);
} else {
// Exclude package-private on Java 17 and later
return false;
}
}
}
}
}
31 changes: 31 additions & 0 deletions core/src/main/java/org/jruby/platform/Platform.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,41 @@ private static String initArchitecture() {
return arch;
}


/**
* Gets the version of the Java platform that JRuby is running on.
*/
private static int initJavaVersion() {
int version = 5;
try {
String versionString = SafePropertyAccessor.getProperty("java.version");
if (versionString != null) {
// remove additional version identifiers, e.g. -ea
versionString = versionString.split("-|\\+")[0];
String[] v = versionString.split("\\.");
if (v[0].equals("1")) {
// Pre Java 9, 1.x style
version = Integer.valueOf(v[1]);
} else {
// Java 9+, x.y.z style
version = Integer.valueOf(v[0]);
}
}
} catch (Exception ex) {
version = 0;
}

return version;
}

public static final String ARCH = initArchitecture();
public static final String OS = initOperatingSystem();
public static final String JVM = getProperty("java.vm.name", "unknown");
public static final String OS_VERSION = getProperty("os.version", "unknown");
/**
* An integer value representing the major Java/JDK release, e.g. 8 for java 1.8, 9 for java 9.
*/
public static final int JAVA_VERSION = initJavaVersion();

public static final boolean IS_WINDOWS = OS.equals(WINDOWS);

Expand Down

0 comments on commit de5aa75

Please sign in to comment.