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

NullPointerException in Helpers.invokedynamic #3608

Closed
jmiettinen opened this issue Jan 20, 2016 · 4 comments
Closed

NullPointerException in Helpers.invokedynamic #3608

jmiettinen opened this issue Jan 20, 2016 · 4 comments

Comments

@jmiettinen
Copy link
Contributor

We have a Rails application running on Tomcat. From time to time, after a restart, loading some views will always fail with the following error:

Java::JavaLang::NullPointerException ():
  org.jruby.runtime.Helpers.invokedynamic(Helpers.java:2805)
  org.jruby.RubyObject.equalInternal(RubyObject.java:477)
  org.jruby.RubyArray.includes(RubyArray.java:655)
  org.jruby.RubyArray.include_p(RubyArray.java:1303)
  org.jruby.RubyArray$INVOKER$i$1$0$include_p.call(RubyArray$INVOKER$i$1$0$include_p.gen)
  org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:168)
  org.jruby.ast.CallOneArgNode.interpret(CallOneArgNode.java:57)

As restarting usually helps and I haven't been able to reproduce this, I am guessing this is some kind of concurrency problem. Can RubyArray have nulls in it as a result of concurrent access to it from the application code?

The line numbers are for version 1.7.23.

@kares
Copy link
Member

kares commented Jan 20, 2016

would be interesting to know some context (if you have) around the piece of .rb code this comes from.

@headius
Copy link
Member

headius commented Jan 21, 2016

Recapping a bit from the actual code...

The line in question is here:

    public static IRubyObject invokedynamic(ThreadContext context, IRubyObject self, MethodNames method, IRubyObject arg0) {
        RubyClass metaclass = self.getMetaClass(); <<<<<
        String name = method.realName();
        return getMethodCached(context, metaclass, method.ordinal(), name).call(context, self, metaclass, name, arg0);
    }

The only way we'd have a NPE at this point would be if self were null, which is a serious bug somewhere.

As you have seen, the self value here ultimately is coming out of an array during an Array#includes call:

    public boolean includes(ThreadContext context, IRubyObject item) {
        int myBegin = this.begin;
        int end = myBegin + realLength;
        IRubyObject[] values = this.values;
        for (int i = myBegin; i < end; i++) {
            final IRubyObject value = safeArrayRef(values, i);
            if (equalInternal(context, value, item)) return true; <<<<<
        }

        return false;
    }

In order for there to be a loose null in an Array, one of two things would have to happen:

  • A bug elsewhere that inserted a null or cleared an entry without replacing it with nil.
  • Two thread concurrently accessing the array.

I agree with your assessment, and my guess is that there's a concurrency problem here. Unfortunately it's hard to find these issues when there's a bunch of interpreter frames mixed in.

If you have a system where this shows up, you might add some exception handling around that line and re-raise a Ruby exception like this:

try {
    // that line that NPEs
} catch (NullPointerException npe) {
    throw context.runtime.newRuntimeError("NPE!!!");
}

Throwing a Ruby error will propagate out better and include a Ruby backtrace that should help figure out where this is happening.

Sorry we can't be more help, but we really need to know where the concurrent access is happening. Without that information, and since this seems likely to be a concurrency issue within your application (or the libraries it uses) I'm going to close this for now.

Please, please reopen if you are able to provide more information, or if the error becomes easily reproducible. We want to help!

@headius headius closed this as completed Jan 21, 2016
@headius headius added this to the Invalid or Duplicate milestone Jan 21, 2016
@jmiettinen
Copy link
Contributor Author

I went through the same code as headius, to no avail.

But, luckily later on when this problem happened again, we got a nice error in the form Detected invalid array contents due to unsynchronized modifications with concurrent users. So someone was structurally modifying a global array 😒.

So this is probably solved and thanks.

@headius
Copy link
Member

headius commented Feb 14, 2016

@jmiettinen In the future we will hopefully be able to explore an Array impl that's more robust under concurrency, but for now I'm glad you got a proper error instead of an NPE. Good to see you again at Jfokus!

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

No branches or pull requests

3 participants