Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6dd82b3cc45d
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 471b9c9e9501
Choose a head ref
  • 2 commits
  • 9 files changed
  • 1 contributor

Commits on Oct 12, 2017

  1. Fixes to reduce access warnings on Java 9.

    * Our own trySetAccessible that only works on fully-open modules.
      This will evolve to use module visibility more accurately.
    * Move inaccessible fields in FilenoUtil to inner class, to make
      their use lazier.
    * Add a flag on by default that assumes 0,1,2 for stdio when JRuby
      is the "main" for this JVM. Avoids the need to reflectively dig
      out the descriptor on Java 9.
    headius committed Oct 12, 2017
    1
    Copy the full SHA
    404fdc9 View commit details
  2. Copy the full SHA
    471b9c9 View commit details
4 changes: 2 additions & 2 deletions core/pom.rb
Original file line number Diff line number Diff line change
@@ -46,9 +46,9 @@
jar 'com.github.jnr:jnr-enxio:0.16', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-x86asm:1.0.2', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-unixsocket:0.17', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-posix:3.0.41', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-posix:3.0.42', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-constants:0.9.9', :exclusions => ['com.github.jnr:jnr-ffi']
jar 'com.github.jnr:jnr-ffi:2.1.6'
jar 'com.github.jnr:jnr-ffi:2.1.7'
jar 'com.github.jnr:jffi:${jffi.version}'
jar 'com.github.jnr:jffi:${jffi.version}:native'

4 changes: 2 additions & 2 deletions core/pom.xml
Original file line number Diff line number Diff line change
@@ -135,7 +135,7 @@ DO NOT MODIFIY - GENERATED CODE
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-posix</artifactId>
<version>3.0.41</version>
<version>3.0.42</version>
<exclusions>
<exclusion>
<artifactId>jnr-ffi</artifactId>
@@ -157,7 +157,7 @@ DO NOT MODIFIY - GENERATED CODE
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-ffi</artifactId>
<version>2.1.6</version>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>com.github.jnr</groupId>
25 changes: 19 additions & 6 deletions core/src/main/java/org/jruby/RubyGlobal.java
Original file line number Diff line number Diff line change
@@ -56,6 +56,7 @@
import org.jruby.util.KCode;
import org.jruby.util.OSEnvironment;
import org.jruby.util.RegexpOptions;
import org.jruby.util.cli.Options;
import org.jruby.util.cli.OutputStrings;
import org.jruby.util.io.ChannelHelper;
import org.jruby.util.io.EncodingUtils;
@@ -275,12 +276,24 @@ public static void createGlobals(ThreadContext context, Ruby runtime) {
}

public static void initSTDIO(Ruby runtime, GlobalVariables globals) {
RubyIO stdin = RubyIO.prepStdio(
runtime, runtime.getIn(), prepareStdioChannel(runtime, STDIO.IN, runtime.getIn()), OpenFile.READABLE, runtime.getIO(), "<STDIN>");
RubyIO stdout = RubyIO.prepStdio(
runtime, runtime.getOut(), prepareStdioChannel(runtime, STDIO.OUT, runtime.getOut()), OpenFile.WRITABLE, runtime.getIO(), "<STDOUT>");
RubyIO stderr = RubyIO.prepStdio(
runtime, runtime.getErr(), prepareStdioChannel(runtime, STDIO.ERR, runtime.getErr()), OpenFile.WRITABLE | OpenFile.SYNC, runtime.getIO(), "<STDERR>");
RubyIO stdin, stdout, stderr;

// If we're the main for the process and native stdio is enabled, use default descriptors
if (runtime.getInstanceConfig().isHardExit() && Options.NATIVE_STDIO.load()) {
stdin = RubyIO.prepStdio(
runtime, runtime.getIn(), new NativeDeviceChannel(0), OpenFile.READABLE, runtime.getIO(), "<STDIN>");
stdout = RubyIO.prepStdio(
runtime, runtime.getOut(), new NativeDeviceChannel(1), OpenFile.WRITABLE, runtime.getIO(), "<STDOUT>");
stderr = RubyIO.prepStdio(
runtime, runtime.getErr(), new NativeDeviceChannel(2), OpenFile.WRITABLE | OpenFile.SYNC, runtime.getIO(), "<STDERR>");
} else {
stdin = RubyIO.prepStdio(
runtime, runtime.getIn(), prepareStdioChannel(runtime, STDIO.IN, runtime.getIn()), OpenFile.READABLE, runtime.getIO(), "<STDIN>");
stdout = RubyIO.prepStdio(
runtime, runtime.getOut(), prepareStdioChannel(runtime, STDIO.OUT, runtime.getOut()), OpenFile.WRITABLE, runtime.getIO(), "<STDOUT>");
stderr = RubyIO.prepStdio(
runtime, runtime.getErr(), prepareStdioChannel(runtime, STDIO.ERR, runtime.getErr()), OpenFile.WRITABLE | OpenFile.SYNC, runtime.getIO(), "<STDERR>");
}

if (runtime.getObject().getConstantFromNoConstMissing("STDIN") == null) {
runtime.defineVariable(new InputGlobalVariable(runtime, "$stdin", stdin), GLOBAL);
17 changes: 17 additions & 0 deletions core/src/main/java/org/jruby/ext/api/array.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.jruby.ext.api;

import org.jruby.runtime.builtin.IRubyObject;

public class array {
// public static IRubyObject rb_ary_aref(int argc, IRubyObject[] argv, IRubyObject ary);
//
// public static rb_ary_entry(IRubyObject ary, long offset)
//
// public static rb_ary_store(IRubyObject ary, long offset, IRubyObject obj)
//
// public static rb_ary_subseq(IRubyObject ary, long beg, long len)
//
// public static rb_ary_push(IRubyObject ary, IRubyObject val)
//
// public static rb_ary_pop(IRubyObject ary)
}
19 changes: 16 additions & 3 deletions core/src/main/java/org/jruby/java/invokers/RubyToJavaInvoker.java
Original file line number Diff line number Diff line change
@@ -45,8 +45,10 @@
import org.jruby.javasupport.JavaConstructor;
import org.jruby.javasupport.ParameterTypes;
import org.jruby.runtime.Arity;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.cli.Options;
import org.jruby.util.collections.IntHashMap;
import org.jruby.util.collections.NonBlockingHashMapLong;

@@ -340,9 +342,12 @@ static JavaProxy castJavaProxy(final IRubyObject self) {
}

static <T extends AccessibleObject> T setAccessible(T accessible) {
// TODO: Replace flag that's false on 9 with proper module checks
if (!accessible.isAccessible() &&
!Ruby.isSecurityRestricted() ) {
try { accessible.setAccessible(true); }
!Ruby.isSecurityRestricted() &&
Options.JI_SETACCESSIBLE.load() &&
accessible instanceof Member) {
try { Helpers.trySetAccessible((Member) accessible); }
catch (SecurityException e) {}
catch (RuntimeException re) {
rethrowIfNotInaccessibleObject(re);
@@ -362,8 +367,11 @@ private static void rethrowIfNotInaccessibleObject(RuntimeException re) {
}

static <T extends AccessibleObject> T[] setAccessible(T[] accessibles) {
// TODO: Replace flag that's false on 9 with proper module checks
if (!allAreAccessible(accessibles) &&
!Ruby.isSecurityRestricted() ) {
!Ruby.isSecurityRestricted() &&
Options.JI_SETACCESSIBLE.load() &&
allAreMember(accessibles)) {
try { AccessibleObject.setAccessible(accessibles, true); }
catch (SecurityException e) {}
catch (RuntimeException re) {
@@ -378,6 +386,11 @@ private static <T extends AccessibleObject> boolean allAreAccessible(T[] accessi
return true;
}

private static <T extends AccessibleObject> boolean allAreMember(T[] accessibles) {
for (T accessible : accessibles) if (!(accessible instanceof Member)) return false;
return true;
}

protected T findCallable(IRubyObject self, String name, IRubyObject[] args, final int arity) {
switch (arity) {
case 0:
54 changes: 54 additions & 0 deletions core/src/main/java/org/jruby/runtime/Helpers.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package org.jruby.runtime;

import java.io.IOException;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.nio.channels.ClosedChannelException;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -2575,4 +2579,54 @@ public static boolean respondsToMethod(DynamicMethod method, boolean checkVisibi
return !(checkVisibility &&
(method.getVisibility() == PRIVATE || method.getVisibility() == PROTECTED));
}

/**
* When running on Java 9 this method will use module openness to do setAccessible, if possible.
*
* @param member the method, field, or constructor to attempt to setAccessible
* @return whether the setAccessible was successful
*/
public static boolean trySetAccessible(Member member) {
if (!(member instanceof AccessibleObject)) return false;

AccessibleObject ao = (AccessibleObject) member;

if (ao.isAccessible()) return true;

if (getModule != null) {
try {
Class<?> declaringClass = member.getDeclaringClass();
Object module = getModule.invoke(declaringClass);
if ((Boolean) isOpen.invoke(module, declaringClass.getPackage().getName())) {
ao.setAccessible(true);
return true;
}
return false;
} catch (Exception e) {
return false;
}
} else {
try {
ao.setAccessible(true);
return true;
} catch (Exception e) {
return false;
}
}
}

private static final Method getModule;
private static final Method isOpen;
static {
Method _getModule = null;
Method _isOpen = null;
try {
_getModule = Class.class.getMethod("getModule");
Class module = Class.forName("java.lang.Module");
_isOpen = module.getMethod("isOpen", String.class);
} catch (Exception e) {
}
getModule = _getModule;
isOpen = _isOpen;
}
}
2 changes: 2 additions & 0 deletions core/src/main/java/org/jruby/util/cli/Options.java
Original file line number Diff line number Diff line change
@@ -136,6 +136,7 @@ public class Options {
public static final Option<Integer> FFI_COMPILE_THRESHOLD = integer(NATIVE, "ffi.compile.threshold", 100, "Number of FFI invocations before generating a bytecode stub.");
public static final Option<Boolean> FFI_COMPILE_INVOKEDYNAMIC = bool(NATIVE, "ffi.compile.invokedynamic", false, "Use invokedynamic to bind FFI invocations.");
public static final Option<Boolean> FFI_COMPILE_REIFY = bool(NATIVE, "ffi.compile.reify", false, "Reify FFI compiled classes.");
public static final Option<Boolean> NATIVE_STDIO = bool(NATIVE, "native.stdio", true, "Use native wrappers around the default stdio descriptors.");

public static final Option<Integer> THREADPOOL_MIN = integer(THREADPOOL, "thread.pool.min", 0, "The minimum number of threads to keep alive in the pool.");
public static final Option<Integer> THREADPOOL_MAX = integer(THREADPOOL, "thread.pool.max", Integer.MAX_VALUE, "The maximum number of threads to allow in the pool.");
@@ -189,6 +190,7 @@ public class Options {
public static final Option<Boolean> DUMP_INSTANCE_VARS = bool(DEBUG, "dump.variables", false, "Dump class + instance var names on first new of Object subclasses.");
public static final Option<Boolean> REWRITE_JAVA_TRACE = bool(DEBUG, "rewrite.java.trace", true, "Rewrite stack traces from exceptions raised in Java calls.");

// TODO: Replace flag that's false on 9 with proper module checks
public static final Option<Boolean> JI_SETACCESSIBLE = bool(JAVA_INTEGRATION, "ji.setAccessible", calculateSetAccessibleDefault(), "Try to set inaccessible Java methods to be accessible.");
public static final Option<Boolean> JI_LOGCANSETACCESSIBLE = bool(JAVA_INTEGRATION, "ji.logCanSetAccessible", false, "Log whether setAccessible is working.");
public static final Option<Boolean> JI_UPPER_CASE_PACKAGE_NAME_ALLOWED = bool(JAVA_INTEGRATION, "ji.upper.case.package.name.allowed", false, "Allow Capitalized Java package names.");
20 changes: 12 additions & 8 deletions core/src/main/java/org/jruby/util/io/ChannelHelper.java
Original file line number Diff line number Diff line change
@@ -12,12 +12,14 @@

import jnr.posix.util.FieldAccess;
import org.jruby.RubyInstanceConfig;
import org.jruby.runtime.Helpers;

import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
@@ -93,9 +95,9 @@ public static InputStream unwrapBufferedStream(InputStream filteredStream) {
public static OutputStream unwrapFilterOutputStream(OutputStream filteredStream) {
while (filteredStream instanceof FilterOutputStream) {
try {
OutputStream tmpStream = (OutputStream)
FieldAccess.getProtectedFieldValue(FilterOutputStream.class,
"out", filteredStream);
Field out = FilterInputStream.class.getDeclaredField("out");
OutputStream tmpStream =
Helpers.trySetAccessible(out) ? (OutputStream) out.get(filteredStream) : null;

// try to unwrap as a Drip stream
if (!(tmpStream instanceof FilterOutputStream)) {
@@ -131,9 +133,9 @@ public static OutputStream unwrapFilterOutputStream(OutputStream filteredStream)
public static InputStream unwrapFilterInputStream(InputStream filteredStream) {
while (filteredStream instanceof FilterInputStream) {
try {
InputStream tmpStream = (InputStream)
FieldAccess.getProtectedFieldValue(FilterInputStream.class,
"in", filteredStream);
Field in = FilterInputStream.class.getDeclaredField("in");
InputStream tmpStream =
Helpers.trySetAccessible(in) ? (InputStream) in.get(filteredStream) : null;

// could not acquire
if (tmpStream == null) break;
@@ -161,7 +163,8 @@ public static InputStream unwrapFilterInputStream(InputStream filteredStream) {
private static OutputStream unwrapDripStream(OutputStream stream) {
if (isDripSwitchable(stream)) {
try {
return (OutputStream) FieldAccess.getProtectedFieldValue(stream.getClass(), "out", stream);
Field out = stream.getClass().getDeclaredField("out");
return Helpers.trySetAccessible(out) ? (OutputStream) out.get(stream) : null;
} catch (Exception e) {
}
}
@@ -171,7 +174,8 @@ private static OutputStream unwrapDripStream(OutputStream stream) {
private static InputStream unwrapDripStream(InputStream stream) {
if (isDripSwitchable(stream)) {
try {
return (InputStream) FieldAccess.getProtectedFieldValue(stream.getClass(), "in", stream);
Field in = stream.getClass().getDeclaredField("in");
return Helpers.trySetAccessible(in) ? (InputStream) in.get(stream) : null;
} catch (Exception e) {
}
}
Loading