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

AsmClassLoader cannot load class when jnr itself is not loaded by the system class loader #55

Closed
wks opened this issue Nov 27, 2015 · 2 comments
Assignees

Comments

@wks
Copy link

wks commented Nov 27, 2015

Version: com.github.jnr:jnr-ffi:2.0.7 found on Maven repository

AsmClassLoader throws java.lang.ClassNotFoundException: jnr.ffi.provider.jffi.NativeClosureProxy when it is about to define a class but jnr-ffi classes are not loaded by the ClassLoader.getSystemClassLoader. This is usually triggered by creating closures from jnr-ffi.

One reason for jnr-ffi not being loaded by the system class loader is because it is part of a ScalaTest test case, in which case ScalaTest seems to have its own class loader that loads both jnr-ffi and the class being tested. Because of this, the same application works fine when run stand-alone, but fails when tested by ScalaTest.

The reason, I think, is that AsmClassLoader is created in NativeRuntime, when an AsmClassLoader is created with ClassLoader.getSystemClassLoader() as its parent. The problem here is that NativeRuntime itself may not be loaded by the system class loader.

The following program can reproduce this problem. But if the test body is copied to a stand-alone application, no exceptions will be thrown.

package jnr.ffi.provider.jffi

import org.scalatest.FlatSpec
import org.scalatest.Matchers

import jnr.ffi.Runtime
import junk.jnr.rpncalc.ClosureType1

class AsmClassLoaderTest extends FlatSpec with Matchers {
  "AsmClassLoader" should "load jnr-ffi-related classes" in {
    val rt = Runtime.getSystemRuntime().asInstanceOf[NativeRuntime]
    val cm = rt.getClosureManager()

    val clos = new ClosureType1 {
      override def invoke(x: Int, y: Int): Double = (x + y).toDouble
    }

    try {
      val ptr = cm.getClosurePointer(classOf[ClosureType1], clos)
    } catch {
      case e: RuntimeException => println(s"Caught exception from getClosurePointer: ${e.getClass}: ${e.getMessage}")
    }

    val thisl = this.getClass.getClassLoader
    val rtl = rt.getClass.getClassLoader
    val cml = cm.getClass.getClassLoader
    val acl = new AsmClassLoader(ClassLoader.getSystemClassLoader)
    val acl2 = new AsmClassLoader(rtl)
    val syscl = ClassLoader.getSystemClassLoader

    println("Point1")
    println(s"thisl=${thisl}")
    println(s"rtl=${rtl}")
    println(s"cml=${cml}")
    println(s"acl=${acl}")
    println(s"acl.getParent=${acl.getParent}")
    println(s"acl2=${acl2}")
    println(s"acl2.getParent=${acl2.getParent}")

    val clsName = "jnr.ffi.provider.jffi.NativeClosureProxy"
    val cls1 = rtl.loadClass(clsName)
    println(s"cls1=${cls1}")
    try {
      val cls2 = acl.loadClass(clsName)
      println(s"cls2=${cls2}")
    } catch {
      case e: ClassNotFoundException => println(s"Caught exception from AsmClassLoader: ${e.getClass}: ${e.getMessage}")
    }
    val cls3 = acl2.loadClass(clsName)
    println(s"cls3=${cls3}")
    try {
      val cls4 = syscl.loadClass(clsName)
      println(s"cls4=${cls4}")
    } catch {
      case e: ClassNotFoundException => println(s"Caught exception from system class loader: ${e.getClass}: ${e.getMessage}")
    }

    println("Point2")
  }
}

When run with ScalaTest, the output is:

Run starting. Expected test count is: 1
AsmClassLoaderTest:
AsmClassLoader
Caught exception from getClosurePointer: class java.lang.RuntimeException: java.lang.NoClassDefFoundError: jnr/ffi/provider/jffi/NativeClosureProxy
Point1
syscl=sun.misc.Launcher$AppClassLoader@33909752
thisl=java.net.URLClassLoader@33c7353a
rtl=java.net.URLClassLoader@33c7353a
cml=java.net.URLClassLoader@33c7353a
acl=jnr.ffi.provider.jffi.AsmClassLoader@2de8284b
acl.getParent=sun.misc.Launcher$AppClassLoader@33909752
acl2=jnr.ffi.provider.jffi.AsmClassLoader@396e2f39
acl2.getParent=java.net.URLClassLoader@33c7353a
cls1=class jnr.ffi.provider.jffi.NativeClosureProxy
Caught exception from AsmClassLoader: class java.lang.ClassNotFoundException: jnr.ffi.provider.jffi.NativeClosureProxy
cls3=class jnr.ffi.provider.jffi.NativeClosureProxy
Caught exception from system class loader: class java.lang.ClassNotFoundException: jnr.ffi.provider.jffi.NativeClosureProxy
Point2
- should load jnr-ffi-related classes
Run completed in 461 milliseconds.
Total number of tests run: 1
Suites: completed 1, aborted 0
Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
All tests passed.

Stack trace of AsmClassLoader.loadClass:

java.lang.ClassNotFoundException: jnr.ffi.provider.jffi.NativeClosureProxy
    at java.lang.ClassLoader.findClass(ClassLoader.java:530)
    at jnr.ffi.provider.jffi.AsmClassLoader.findClass(AsmClassLoader.java:51)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at jnr.ffi.provider.jffi.AsmClassLoaderTest$$anonfun$1.apply$mcV$sp(AsmClassLoaderTest.scala:45)
    at jnr.ffi.provider.jffi.AsmClassLoaderTest$$anonfun$1.apply(AsmClassLoaderTest.scala:11)
    at jnr.ffi.provider.jffi.AsmClassLoaderTest$$anonfun$1.apply(AsmClassLoaderTest.scala:11)
    at org.scalatest.Transformer$$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
    at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
    at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
    at org.scalatest.Transformer.apply(Transformer.scala:22)
    at org.scalatest.Transformer.apply(Transformer.scala:20)
    at org.scalatest.FlatSpecLike$$anon$1.apply(FlatSpecLike.scala:1647)
    at org.scalatest.Suite$class.withFixture(Suite.scala:1122)
    at org.scalatest.FlatSpec.withFixture(FlatSpec.scala:1683)
    at org.scalatest.FlatSpecLike$class.invokeWithFixture$1(FlatSpecLike.scala:1644)
    at org.scalatest.FlatSpecLike$$anonfun$runTest$1.apply(FlatSpecLike.scala:1656)
    at org.scalatest.FlatSpecLike$$anonfun$runTest$1.apply(FlatSpecLike.scala:1656)
    at org.scalatest.SuperEngine.runTestImpl(Engine.scala:306)
    at org.scalatest.FlatSpecLike$class.runTest(FlatSpecLike.scala:1656)
    at org.scalatest.FlatSpec.runTest(FlatSpec.scala:1683)
    at org.scalatest.FlatSpecLike$$anonfun$runTests$1.apply(FlatSpecLike.scala:1714)
    at org.scalatest.FlatSpecLike$$anonfun$runTests$1.apply(FlatSpecLike.scala:1714)
    at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:413)
    at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
    at scala.collection.immutable.List.foreach(List.scala:381)
    at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
    at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:390)
    at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:427)
    at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:401)
    at scala.collection.immutable.List.foreach(List.scala:381)
    at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:401)
    at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:396)
    at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:483)
    at org.scalatest.FlatSpecLike$class.runTests(FlatSpecLike.scala:1714)
    at org.scalatest.FlatSpec.runTests(FlatSpec.scala:1683)
    at org.scalatest.Suite$class.run(Suite.scala:1424)
    at org.scalatest.FlatSpec.org$scalatest$FlatSpecLike$$super$run(FlatSpec.scala:1683)
    at org.scalatest.FlatSpecLike$$anonfun$run$1.apply(FlatSpecLike.scala:1760)
    at org.scalatest.FlatSpecLike$$anonfun$run$1.apply(FlatSpecLike.scala:1760)
    at org.scalatest.SuperEngine.runImpl(Engine.scala:545)
    at org.scalatest.FlatSpecLike$class.run(FlatSpecLike.scala:1760)
    at org.scalatest.FlatSpec.run(FlatSpec.scala:1683)
    at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:55)
    at org.scalatest.tools.Runner$$anonfun$doRunRunRunDaDoRunRun$3.apply(Runner.scala:2563)
    at org.scalatest.tools.Runner$$anonfun$doRunRunRunDaDoRunRun$3.apply(Runner.scala:2557)
    at scala.collection.immutable.List.foreach(List.scala:381)
    at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:2557)
    at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:1044)
    at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:1043)
    at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:2722)
    at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:1043)
    at org.scalatest.tools.Runner$.main(Runner.scala:860)
    at org.scalatest.tools.Runner.main(Runner.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at scala.tools.eclipse.scalatest.launching.ScalaTestLauncher$.main(ScalaTestLauncher.scala:20)
    at scala.tools.eclipse.scalatest.launching.ScalaTestLauncher.main(ScalaTestLauncher.scala)

I copied the test body to a standalone Scala App, run it again, and output is:

Point1
syscl=sun.misc.Launcher$AppClassLoader@659e0bfd
thisl=sun.misc.Launcher$AppClassLoader@659e0bfd
rtl=sun.misc.Launcher$AppClassLoader@659e0bfd
cml=sun.misc.Launcher$AppClassLoader@659e0bfd
acl=jnr.ffi.provider.jffi.AsmClassLoader@7cef4e59
acl.getParent=sun.misc.Launcher$AppClassLoader@659e0bfd
acl2=jnr.ffi.provider.jffi.AsmClassLoader@64b8f8f4
acl2.getParent=sun.misc.Launcher$AppClassLoader@659e0bfd
cls1=class jnr.ffi.provider.jffi.NativeClosureProxy
cls2=class jnr.ffi.provider.jffi.NativeClosureProxy
cls3=class jnr.ffi.provider.jffi.NativeClosureProxy
cls4=class jnr.ffi.provider.jffi.NativeClosureProxy
Point2
@mkristian mkristian self-assigned this Nov 27, 2015
@mkristian
Copy link
Contributor

thanks for the test-case. for me this is duplicate of #51

@headius
Copy link
Member

headius commented Sep 26, 2016

Close as duplicate of #51.

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

3 participants