Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JRuby fails to load FFI support with obscure error when /tmp is not writable #1302

Closed
qerub opened this issue Dec 4, 2013 · 15 comments
Closed
Milestone

Comments

@qerub
Copy link
Contributor

qerub commented Dec 4, 2013

$ sudo chmod 1775 /tmp
$ java -Djruby.native.verbose=true -jar jruby-complete.jar -rffi -e :ok
Failed to load native POSIX impl; falling back on Java impl. Stacktrace follows.
java.lang.UnsatisfiedLinkError: could not load FFI provider jnr.ffi.provider.jffi.Provider
        at jnr.ffi.provider.InvalidProvider$1.loadLibrary(InvalidProvider.java:30)
        at jnr.ffi.LibraryLoader.load(LibraryLoader.java:228)
        at jnr.ffi.Library.loadLibrary(Library.java:123)
        at jnr.posix.POSIXFactory$DefaultLibCProvider$SingletonHolder.<clinit>(POSIXFactory.java:219)
        at jnr.posix.POSIXFactory$DefaultLibCProvider.getLibC(POSIXFactory.java:223)
        at jnr.posix.BaseNativePOSIX.<init>(BaseNativePOSIX.java:37)
        at jnr.posix.LinuxPOSIX.<init>(LinuxPOSIX.java:20)
        at jnr.posix.POSIXFactory.loadLinuxPOSIX(POSIXFactory.java:95)
        at jnr.posix.POSIXFactory.loadNativePOSIX(POSIXFactory.java:69)
        at jnr.posix.POSIXFactory.loadPOSIX(POSIXFactory.java:38)
        at jnr.posix.LazyPOSIX.loadPOSIX(LazyPOSIX.java:33)
        at jnr.posix.LazyPOSIX.posix(LazyPOSIX.java:29)
        at jnr.posix.LazyPOSIX.isatty(LazyPOSIX.java:183)
        at org.jruby.Main.handleRaiseException(Main.java:509)
        at org.jruby.Main.main(Main.java:202)
Caused by: java.lang.ExceptionInInitializerError
        at jnr.ffi.provider.jffi.NativeRuntime.getInstance(NativeRuntime.java:49)
        at jnr.ffi.provider.jffi.Provider.<init>(Provider.java:29)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
        at java.lang.Class.newInstance0(Class.java:374)
        at java.lang.Class.newInstance(Class.java:327)
        at jnr.ffi.provider.FFIProvider$SystemProviderSingletonHolder.getInstance(FFIProvider.java:60)
        at jnr.ffi.provider.FFIProvider$SystemProviderSingletonHolder.<clinit>(FFIProvider.java:49)
        at jnr.ffi.provider.FFIProvider.getSystemProvider(FFIProvider.java:35)
        at jnr.ffi.Runtime$SingletonHolder.<clinit>(Runtime.java:85)
        at jnr.ffi.Runtime.getSystemRuntime(Runtime.java:70)
        at jnr.posix.NativePOSIX.<init>(NativePOSIX.java:9)
        at jnr.posix.BaseNativePOSIX.<init>(BaseNativePOSIX.java:35)
        ... 9 more
Caused by: java.lang.IllegalStateException: Can't overwrite cause
        at java.lang.Throwable.initCause(Throwable.java:337)
        at com.kenai.jffi.Type$Builtin.lookupTypeInfo(Type.java:252)
        at com.kenai.jffi.Type$Builtin.getTypeInfo(Type.java:237)
        at com.kenai.jffi.Type.resolveSize(Type.java:155)
        at com.kenai.jffi.Type.size(Type.java:138)
        at jnr.ffi.provider.jffi.NativeRuntime$TypeDelegate.size(NativeRuntime.java:178)
        at jnr.ffi.provider.AbstractRuntime.<init>(AbstractRuntime.java:48)
        at jnr.ffi.provider.jffi.NativeRuntime.<init>(NativeRuntime.java:57)
        at jnr.ffi.provider.jffi.NativeRuntime.<init>(NativeRuntime.java:41)
        at jnr.ffi.provider.jffi.NativeRuntime$SingletonHolder.<clinit>(NativeRuntime.java:53)
        ... 24 more
LoadError: Could not load FFI Provider: (NotImplementedError) FFI not available: null
 See http://jira.codehaus.org/browse/JRUBY-4583
  require at org/jruby/RubyKernel.java:1084
  require at jar:file:/tmp/jruby-sandbox/vendor/jruby-complete-with-bundler.jar!/META-INF/jruby.home/lib/ruby/shared/rubygems/core_ext/kernel_require.rb:55
   (root) at jar:file:/tmp/jruby-sandbox/vendor/jruby-complete-with-bundler.jar!/META-INF/jruby.home/lib/ruby/shared/ffi/ffi.rb:69
  require at org/jruby/RubyKernel.java:1084
   (root) at jar:file:/tmp/jruby-sandbox/vendor/jruby-complete-with-bundler.jar!/META-INF/jruby.home/lib/ruby/shared/rubygems/core_ext/kernel_require.rb:1
  require at jar:file:/tmp/jruby-sandbox/vendor/jruby-complete-with-bundler.jar!/META-INF/jruby.home/lib/ruby/shared/rubygems/core_ext/kernel_require.rb:55
  require at org/jruby/RubyKernel.java:1084
   (root) at jar:file:/tmp/jruby-sandbox/vendor/jruby-complete-with-bundler.jar!/META-INF/jruby.home/lib/ruby/shared/ffi.rb:1
$ sudo chmod 1777 /tmp
$ java -Djruby.native.verbose=true -jar jruby-complete.jar -rffi -e :ok
Successfully loaded native POSIX impl.

I noticed this when I accidentally changed permissions for /tmp. A more informative message would be helpful. :)

@blendmaster
Copy link

blendmaster commented Oct 27, 2014

I just ran into this issue, can this error message be made better somehow? 😞

@jkraemer
Copy link

jkraemer commented Dec 18, 2015

Much better would be a fix for the problem - how can I get around this issue if making /tmp writable is not an option?

@mkristian
Copy link
Member

mkristian commented Dec 18, 2015

@jkraemer you can set java.io.tmpdir property:

java -Djruby.native.verbose=true  -Djava.io.tmpdir=jruby-temp-dir -jar jruby-complete.jar -rffi -e :ok

@ranjankumar03
Copy link

ranjankumar03 commented Sep 1, 2017

Anyone aware of this?

datastax.driver.core.Native:113 -Could not load JNR C Library, native system calls through this library will not be available
java.lang.UnsatisfiedLinkError: could not load FFI provider jnr.ffi.provider.jffi.Provider
at jnr.ffi.provider.InvalidProvider$1.loadLibrary(InvalidProvider.java:48)
at jnr.ffi.LibraryLoader.load(LibraryLoader.java:290)
at jnr.ffi.LibraryLoader.load(LibraryLoader.java:269)
at com.datastax.driver.core.Native$LibCLoader.(Native.java:108)
at com.datastax.driver.core.Native.isGettimeofdayAvailable(Native.java:190)
at com.datastax.driver.core.ClockFactory.newInstance(Clock.java:51)
at com.datastax.driver.core.AbstractMonotonicTimestampGenerator.(AbstractMonotonicTimestampGenerator.java:43)
at com.datastax.driver.core.LoggingMonotonicTimestampGenerator.(LoggingMonotonicTimestampGenerator.java:49)
at com.datastax.driver.core.AtomicMonotonicTimestampGenerator.(AtomicMonotonicTimestampGenerator.java:50)
at com.datastax.driver.core.AtomicMonotonicTimestampGenerator.(AtomicMonotonicTimestampGenerator.java:37)
at com.datastax.driver.core.policies.Policies.defaultTimestampGenerator(Policies.java:121)
at com.datastax.driver.core.policies.Policies$Builder.build(Policies.java:286)
at com.datastax.driver.core.Cluster$Builder.getConfiguration(Cluster.java:1317)
at com.datastax.driver.core.Cluster.(Cluster.java:113)
at com.datastax.driver.core.Cluster.buildFrom(Cluster.java:178)
at com.datastax.driver.core.Cluster$Builder.build(Cluster.java:1335)

@rdp
Copy link
Contributor

rdp commented Sep 10, 2019

Just ran into this, (CentOS 7 some distros have /tmp non-writable by default :( ). For google followers, the error messages now look like this:

 java -jar jruby-complete-9.2.8.0.jar -S irb
NotImplementedError: fstat unimplemented unsupported or native support failed to load; see https://github.com/jruby/jruby/wiki/Native-Libraries
  initialize at org/jruby/RubyIO.java:1015
        open at org/jruby/RubyIO.java:1156
  initialize at uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/irb/input-method.rb:141
  initialize at uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/irb/context.rb:70
  initialize at uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/irb.rb:410
       start at uri:classloader:/META-INF/jruby.home/lib/ruby/stdlib/irb.rb:381
      <main> at uri:classloader:/META-INF/jruby.home/bin/jirb:13

and

 java -Djruby.native.verbose=true -jar jruby-complete-9.2.8.0.jar  -S irb
Failed to load native POSIX impl; falling back on Java impl. Stacktrace follows.
java.lang.UnsatisfiedLinkError: could not load FFI provider jnr.ffi.provider.jffi.Provider
	at jnr.ffi.provider.InvalidProvider$1.loadLibrary(InvalidProvider.java:48)
	at jnr.ffi.LibraryLoader.load(LibraryLoader.java:325)
	at jnr.ffi.Library.loadLibrary(Library.java:127)
	at jnr.posix.POSIXFactory$DefaultLibCProvider$SingletonHolder.<clinit>(POSIXFactory.java:289)
	at jnr.posix.POSIXFactory$DefaultLibCProvider.getLibC(POSIXFactory.java:318)
	at jnr.posix.BaseNativePOSIX.<init>(BaseNativePOSIX.java:38)
	at jnr.posix.LinuxPOSIX.<init>(LinuxPOSIX.java:19)
	at jnr.posix.POSIXFactory.loadLinuxPOSIX(POSIXFactory.java:149)
	at jnr.posix.POSIXFactory.loadNativePOSIX(POSIXFactory.java:124)
	at jnr.posix.POSIXFactory.loadPOSIX(POSIXFactory.java:93)
	at jnr.posix.LazyPOSIX.loadPOSIX(LazyPOSIX.java:38)
	at jnr.posix.LazyPOSIX.posix(LazyPOSIX.java:32)
	at jnr.posix.LazyPOSIX.isNative(LazyPOSIX.java:402)
	at org.jruby.util.io.FilenoUtil.<init>(FilenoUtil.java:32)
	at org.jruby.Ruby.<init>(Ruby.java:318)
	at org.jruby.Ruby.newInstance(Ruby.java:367)
	at org.jruby.Main.internalRun(Main.java:273)
	at org.jruby.Main.run(Main.java:234)
	at org.jruby.Main.main(Main.java:206)
Caused by: java.lang.UnsatisfiedLinkError: could not get native definition for type: POINTER
	at com.kenai.jffi.Type$Builtin.lookupTypeInfo(Type.java:251)
	at com.kenai.jffi.Type$Builtin.getTypeInfo(Type.java:237)
	at com.kenai.jffi.Type.resolveSize(Type.java:155)
	at com.kenai.jffi.Type.size(Type.java:138)
	at jnr.ffi.provider.jffi.NativeRuntime$TypeDelegate.size(NativeRuntime.java:178)
	at jnr.ffi.provider.AbstractRuntime.<init>(AbstractRuntime.java:48)
	at jnr.ffi.provider.jffi.NativeRuntime.<init>(NativeRuntime.java:57)
	at jnr.ffi.provider.jffi.NativeRuntime.<init>(NativeRuntime.java:41)
	at jnr.ffi.provider.jffi.NativeRuntime$SingletonHolder.<clinit>(NativeRuntime.java:53)
	at jnr.ffi.provider.jffi.NativeRuntime.getInstance(NativeRuntime.java:49)
	at jnr.ffi.provider.jffi.Provider.<init>(Provider.java:29)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at jnr.ffi.provider.FFIProvider$SystemProviderSingletonHolder.getInstance(FFIProvider.java:68)
	at jnr.ffi.provider.FFIProvider$SystemProviderSingletonHolder.<clinit>(FFIProvider.java:57)
	at jnr.ffi.provider.FFIProvider.getSystemProvider(FFIProvider.java:35)
	at jnr.ffi.Library.loadLibrary(Library.java:114)
	... 16 more
Caused by: java.lang.UnsatisfiedLinkError: java.lang.UnsatisfiedLinkError: /tmp/jffi7684241648010829190.so: /tmp/jffi7684241648010829190.so: failed to map segment from shared object: Operation not permitted
	at java.lang.ClassLoader$NativeLibrary.load(Native Method)
	at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
	at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
	at java.lang.Runtime.load0(Runtime.java:809)
	at java.lang.System.load(System.java:1086)
	at com.kenai.jffi.internal.StubLoader.loadFromJar(StubLoader.java:380)
	at com.kenai.jffi.internal.StubLoader.load(StubLoader.java:262)
	at com.kenai.jffi.internal.StubLoader.<clinit>(StubLoader.java:453)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:348)
	at com.kenai.jffi.Init.load(Init.java:68)
	at com.kenai.jffi.Foreign$InstanceHolder.getInstanceHolder(Foreign.java:49)
	at com.kenai.jffi.Foreign$InstanceHolder.<clinit>(Foreign.java:45)
	at com.kenai.jffi.Foreign.getInstance(Foreign.java:103)
	at com.kenai.jffi.Type$Builtin.lookupTypeInfo(Type.java:242)
	at com.kenai.jffi.Type$Builtin.getTypeInfo(Type.java:237)
	at com.kenai.jffi.Type.resolveSize(Type.java:155)
	at com.kenai.jffi.Type.size(Type.java:138)
	at jnr.ffi.provider.jffi.NativeRuntime$TypeDelegate.size(NativeRuntime.java:178)
	at jnr.ffi.provider.AbstractRuntime.<init>(AbstractRuntime.java:48)
	at jnr.ffi.provider.jffi.NativeRuntime.<init>(NativeRuntime.java:57)
	at jnr.ffi.provider.jffi.NativeRuntime.<init>(NativeRuntime.java:41)
	at jnr.ffi.provider.jffi.NativeRuntime$SingletonHolder.<clinit>(NativeRuntime.java:53)
	at jnr.ffi.provider.jffi.NativeRuntime.getInstance(NativeRuntime.java:49)
	at jnr.ffi.provider.jffi.Provider.<init>(Provider.java:29)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
	at java.lang.Class.newInstance(Class.java:442)
	at jnr.ffi.provider.FFIProvider$SystemProviderSingletonHolder.getInstance(FFIProvider.java:68)
	at jnr.ffi.provider.FFIProvider$SystemProviderSingletonHolder.<clinit>(FFIProvider.java:57)
	at jnr.ffi.provider.FFIProvider.getSystemProvider(FFIProvider.java:35)
	at jnr.ffi.Library.loadLibrary(Library.java:114)
	at jnr.posix.POSIXFactory$DefaultLibCProvider$SingletonHolder.<clinit>(POSIXFactory.java:289)
	at jnr.posix.POSIXFactory$DefaultLibCProvider.getLibC(POSIXFactory.java:318)
	at jnr.posix.BaseNativePOSIX.<init>(BaseNativePOSIX.java:38)
	at jnr.posix.LinuxPOSIX.<init>(LinuxPOSIX.java:19)
	at jnr.posix.POSIXFactory.loadLinuxPOSIX(POSIXFactory.java:149)
	at jnr.posix.POSIXFactory.loadNativePOSIX(POSIXFactory.java:124)
	at jnr.posix.POSIXFactory.loadPOSIX(POSIXFactory.java:93)
	at jnr.posix.LazyPOSIX.loadPOSIX(LazyPOSIX.java:38)
	at jnr.posix.LazyPOSIX.posix(LazyPOSIX.java:32)
	at jnr.posix.LazyPOSIX.isNative(LazyPOSIX.java:402)
	at org.jruby.util.io.FilenoUtil.<init>(FilenoUtil.java:32)
	at org.jruby.Ruby.<init>(Ruby.java:318)
	at org.jruby.Ruby.newInstance(Ruby.java:367)
	at org.jruby.Main.internalRun(Main.java:273)
	at org.jruby.Main.run(Main.java:234)
	at org.jruby.Main.main(Main.java:206)

	at com.kenai.jffi.Foreign.newLoadError(Foreign.java:72)
	at com.kenai.jffi.Foreign.access$300(Foreign.java:42)
	at com.kenai.jffi.Foreign$InValidInstanceHolder.getForeign(Foreign.java:98)
	at com.kenai.jffi.Foreign.getInstance(Foreign.java:103)
	at com.kenai.jffi.Type$Builtin.lookupTypeInfo(Type.java:242)
	... 35 more

suggestion/feature request: if /tmp not executable, fallback to ~/.jruby-cache or something. Cheers!..

@headius
Copy link
Member

headius commented Sep 11, 2019

Hmm I suppose we could fall back, but I don't like the thought that we'd now dumping binaries into an even more unexpected location. The error should definitely be clearer though.

How can a system work with a read-only /tmp? Are we not paying attention to some user TMP variable or something?

@rdp
Copy link
Contributor

rdp commented Sep 12, 2019

@headius
Copy link
Member

headius commented Sep 25, 2019

@rdp I think the issue you have there is that it's actually disallowing executables from /tmp, which is a feature of some "secure" Linux distributions. I believe if you set your own TMP or TEMP or whatever, it will work. Can you confirm?

headius added a commit to jnr/jffi that referenced this issue Oct 8, 2019
In jruby/jruby#1302 we see that attempting to load FFI type defs
when the jffi stub can't be loaded results in
IllegalStateException being raised when we try to initCause on an
UnsatisfiedLinkError. It appears that (sometimes?) simply
constructing this exception initializes its cause, which can only
be done once. Our attempt to initialize it again triggers the
error.

Since ULE does not have a constructor that accepts a cause, the
only option here is to include the message from the triggering
exception.
headius added a commit that referenced this issue Oct 8, 2019
@headius headius added this to the JRuby 9.2.9.0 milestone Oct 8, 2019
@headius
Copy link
Member

headius commented Oct 8, 2019

The original weirdness of this error was due to JFFI attempting to initCause on an UnsatisfiedLinkError that appears to get its own cause (sometimes? always?). I have fixed that in jffi and added better error messages (see #5900) that should help folks diagnose this problem in the future.

Note that you will still have to set the appropriate property or flag for verbose native loading in order to see the updated error, but it now explains that we need a writable, exec-able temp location.

@headius headius closed this as completed Oct 8, 2019
@headius
Copy link
Member

headius commented Oct 8, 2019

Also FWIW, JRuby should be attempting to fall back on the current directory for this temporary library, which isn't great but it's the behavior we have in place.

@rdp
Copy link
Contributor

rdp commented Oct 17, 2019

Sweet. With 9.2.8.0 it was failing but with 9.2.9.0-SNAPSHOT seems to be working great, even if the CWD isn't executable, sweet!

@rdp
Copy link
Contributor

rdp commented May 13, 2021

For me (using the jruby-complete-jar) setting TEMPDIR et al. doesn't seem to work. It works "just fine" when running jruby-9.2.17.0/bin/jruby (the executable), but not when using the jar, then it needs java -Djava.io.tmpdir=... -jar to point at an executable directory (or to run it from a directory you have executable+write permission to, or to have a /tmp that has executable permission). Now it works :)

@headius
Copy link
Member

headius commented May 13, 2021

@rdp Based on this SO post, it seems like the default temp dir on non-Windows is always /tmp unless specified via the property, and no env vars are looked at. Windows, however, will look at TMP and possibly other places (registry?).

https://stackoverflow.com/questions/1924136/environment-variable-to-control-java-io-tmpdir

I have not confirmed this myself, but it is a bit of a surprise; I was under the impression that java.io.tmpdir would default to whatever the environment's TEMP env or similar are set to.

As it stands, it would be inappropriate for us to change the value of java.io.tmpdir from JRuby or jffi, so the only option to me would be for JRuby to use "proper" enviroment-variable logic to give jffi a location (or we just document that it will use the java.io.tmpdir location or whatever location you set via jffi's jffi.extract.dir and jffi.extract.name properties and leave it at that).

@rdp
Copy link
Contributor

rdp commented May 16, 2021

@headius
Copy link
Member

headius commented May 17, 2021

I updated the wiki page, at least it'll give more clues for followers now :)

@rdp Thanks! Let me know if you think there's more we can do to make this clear (or if you come up with an idea for making it honor temp locations without diverging too much from java.io.tmpdir behavior).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants