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

Native image agent configuration filtering not working well for resources configuration #8417

Open
galderz opened this issue Feb 21, 2024 · 3 comments

Comments

@galderz
Copy link
Contributor

galderz commented Feb 21, 2024

The native image agent configuration filters don't work well with resource configuration.

For example, say you have this call I want to filter out (coming from resources-origins.txt generated using experimental-configuration-with-origins) option:

├── org.apache.maven.surefire.booter.ForkedBooter#main(java.lang.String[])
│   └── org.apache.maven.surefire.booter.ForkedBooter#run(org.apache.maven.surefire.booter.ForkedBooter,java.lang.String[])
│       ├── org.apache.maven.surefire.booter.ForkedBooter#setupBooter(java.lang.String,java.lang.String,java.lang.String,java.lang.String)
│       │   └── org.apache.maven.surefire.booter.ForkedBooter#lookupDecoderFactory(java.lang.String)
│       │       └── java.util.ServiceLoader$3#hasNext()
│       │           └── java.util.ServiceLoader$2#hasNext()
│       │               └── java.util.ServiceLoader$LazyClassPathLookupIterator#hasNext()
│       │                   └── java.util.ServiceLoader$LazyClassPathLookupIterator#hasNextService()
│       │                       └── java.util.ServiceLoader$LazyClassPathLookupIterator#nextProviderClass()
│       │                           └── java.lang.ClassLoader#getResources(java.lang.String) - {   "resources":{   "includes":[{     "pattern":"\\QMETA-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory\\E"   }]},   "bundles":[] }
│       │                               └── java.lang.ClassLoader#getResources(java.lang.String) - {   "resources":{   "includes":[{     "pattern":"\\QMETA-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory\\E"   }]},   "bundles":[] }

When you look at the trace-output JSON file it says:

{"tracer":"reflect", "function":"getResources", "class":"jdk.internal.loader.ClassLoaders$AppClassLoader", "caller_class":"java.util.ServiceLoader$LazyClassPathLookupIterator", "result":"true", "args":["META-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory"]},

The problem is that one cannot really filter java.util.ServiceLoader because that would filter out all service loader calls. What you want to filter is service loader calls coming from org.apache.maven.surefire package. Setting to exclude that package doesn't work because the caller does not match that package.

Here's the filter I used (set on both access-based and caller-based) filtes:

{
  "rules": [
    {
      "excludeClasses": "org.apache.maven.surefire.**"
    }]
}

The resulting resources configuration contains:

{
  "resources":{
    "includes":[{
      "pattern":"\\QMETA-INF/services/org.apache.maven.surefire.spi.MasterProcessChannelProcessorFactory\\E"
    }]
  }
}

This is not limited to just service loader, other JDK calls are also affected, e.g. ClassLoader.getResourceAsStream:

│                       │   │       └── io.quarkus.arc.processor.ClientProxyGenerator#generate(io.quarkus.arc.processor.BeanInfo,java.lang.String,java.util.function.Consumer,boolean)
│                       │   │           └── io.quarkus.arc.processor.Types#resolvedTypeVariables(org.jboss.jandex.ClassInfo,io.quarkus.arc.processor.BeanDeployment)
│                       │   │               └── io.quarkus.arc.processor.Types#getTypeClosure(org.jboss.jandex.ClassInfo,org.jboss.jandex.AnnotationTarget,java.util.Map,io.quarkus.arc.processor.BeanDeployment,java.util.function.BiConsumer,java.util.Set)
│                       │   │                   └── io.quarkus.arc.processor.Types#getTypeClosure(org.jboss.jandex.ClassInfo,org.jboss.jandex.AnnotationTarget,boolean,java.util.Map,io.quarkus.arc.processor.BeanDeployment,java.util.function.BiConsumer,java.util.Set,boolean)
│                       │   │                       └── io.quarkus.arc.processor.Types#getTypeClosure(org.jboss.jandex.ClassInfo,org.jboss.jandex.AnnotationTarget,boolean,java.util.Map,io.quarkus.arc.processor.BeanDeployment,java.util.function.BiConsumer,java.util.Set,boolean)
│                       │   │                           └── io.quarkus.arc.processor.Types#getTypeClosure(org.jboss.jandex.ClassInfo,org.jboss.jandex.AnnotationTarget,boolean,java.util.Map,io.quarkus.arc.processor.BeanDeployment,java.util.function.BiConsumer,java.util.Set,boolean)
│                       │   │                               └── io.quarkus.arc.processor.IndexClassLookupUtils#getClassByName(org.jboss.jandex.IndexView,org.jboss.jandex.DotName)
│                       │   │                                   └── io.quarkus.arc.processor.IndexClassLookupUtils#getClassByName(org.jboss.jandex.IndexView,org.jboss.jandex.DotName,boolean)
│                       │   │                                       └── io.quarkus.arc.processor.BeanArchives$IndexWrapper#getClassByName(org.jboss.jandex.DotName)
│                       │   │                                           └── java.util.concurrent.ConcurrentHashMap#computeIfAbsent(java.lang.Object,java.util.function.Function)
│                       │   │                                               └── io.quarkus.arc.processor.BeanArchives$IndexWrapper$$Lambda/0x0000000801479b78#apply(java.lang.Object)
│                       │   │                                                   └── io.quarkus.arc.processor.BeanArchives$IndexWrapper#computeAdditional(org.jboss.jandex.DotName)
│                       │   │                                                       └── io.quarkus.arc.processor.BeanArchives#index(org.jboss.jandex.Indexer,java.lang.String,java.lang.ClassLoader)
│                       │   │                                                           └── io.quarkus.bootstrap.classloading.QuarkusClassLoader#getResourceAsStream(java.lang.String)
│                       │   │                                                               └── io.quarkus.bootstrap.classloading.QuarkusClassLoader#getResourceAsStream(java.lang.String)
│                       │   │                                                                   └── java.lang.ClassLoader#getResourceAsStream(java.lang.String)
│                       │   │                                                                       └── java.lang.ClassLoader#getResource(java.lang.String) - {   "resources":{   "includes":[{     "pattern":"\\Qjava/lang/AutoCloseable.class\\E"   }, {     "pattern":"\\Qjava/util/concurrent/Executor.class\\E"   }]},   "bundles":[] }
│                       │   │                                                                           └── java.lang.ClassLoader#getResource(java.lang.String) - {   "resources":{   "includes":[{     "pattern":"\\Qjava/lang/AutoCloseable.class\\E"   }, {     "pattern":"\\Qjava/util/concurrent/Executor.class\\E"   }]},   "bundles":[] }
│                       │   │                                                                               └── jdk.internal.loader.BootLoader#findResource(java.lang.String)
│                       │   │                                                                                   └── jdk.internal.loader.BuiltinClassLoader#findResource(java.lang.String)
│                       │   │                                                                                       └── jdk.internal.loader.BuiltinClassLoader#findResource(java.lang.String,java.lang.String) - {   "resources":{   "includes":[{     "pattern":"java.base:\\Qjava/lang/AutoCloseable.class\\E"   }, {     "pattern":"java.base:\\Qjava/util/concurrent/Executor.class\\E"   }]},   "bundles":[] }

I have a filter in place for io.quarkus.** but the resources configuration file still contains a registration for AutoCloseable:

    "pattern":"java.base:\\Qjava/lang/AutoCloseable.class\\E"

If you look at the trace output it shows:

{"tracer":"reflect", "function":"getResource", "class":"jdk.internal.loader.ClassLoaders$AppClassLoader", "caller_class":"java.lang.ClassLoader", "result":"true", "args":["java/lang/AutoCloseable.class"]},
{"tracer":"reflect", "function":"getResource", "class":"jdk.internal.loader.ClassLoaders$PlatformClassLoader", "caller_class":"java.lang.ClassLoader", "result":"true", "args":["java/lang/AutoCloseable.class"]},
{"tracer":"reflect", "function":"findResource", "caller_class":"jdk.internal.loader.BuiltinClassLoader", "result":"true", "args":["java.base","java/lang/AutoCloseable.class"]},
@kassifar
Copy link

Hi @galderz , thank you for suggesting this feature for GraalVM.

@kassifar
Copy link

Hello @fniephaus, should I create a GR for this?

@fniephaus
Copy link
Member

Yes, please.

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