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

[GR-49770] Safe Composition of Metadata #5173

Closed
vjovanov opened this issue Oct 6, 2022 · 4 comments
Closed

[GR-49770] Safe Composition of Metadata #5173

vjovanov opened this issue Oct 6, 2022 · 4 comments
Assignees
Labels

Comments

@vjovanov
Copy link
Member

vjovanov commented Oct 6, 2022

TL;DR

To make usage of third-party reachability metadata safe we must guarantee that metadata addition can't break existing programs.
This is currently not the case:

  1. For reflective methods such as java.lang.Class#getDeclaredMethods that return values based on reachability of other reflective elements.
    Because of this adding new metadata makes more elements reachable and can change program functionality in undesirable ways.

    We must require that all reflective methods on java.lang.Class require a metadata entry and that they: either return all elements when the metadata entry is present, or throw a missing-metadata exception when there is no metadata entry.

  2. For resource metadata that can currently contain exclude patterns. An added exclude pattern can accidentally remove resources from the image and break the functionality of a working program.

    We must require that exclude patterns are regarded only within the scope of a single resource-config.json file.

Safe Composition of Reflection Metadata

In Native Image, adding new metadata can break user programs because methods such as java.lang.Class#getDeclaredMethods return the set of currently reachable elements.
In the following snippet

if (AClass.class.getMethods().size > 5) {
    System.exit(1);
}

adding a metadata entry for a method from AClass can cause the System.exit(1) to be reached.
Furthermore, this can happen by simply using methods from AClass anywhere in the code as this makes new methods reachable.

To allow safe composition of metadata we need to make sure that every reflective call on java.lang.Class requires a metadata entry.
The following tables show metadata entries for all of those methods:

Method Existing Metadata Entry
java.lang.Class#getDeclaredMethods "queryAllDeclaredMethods": true
java.lang.Class#getDeclaredConstructors "queryAllDeclaredConstructors": true
java.lang.Class#getMethods "queryAllPublicMethods": true
java.lang.Class#getConstructors "queryAllPublicConstructors": true
java.lang.Class#getFields "allPublicFields": true
java.lang.Class#getDeclaredFields "allDeclaredFields": true
Newly Tracked Method New Metadata Entry
java.lang.Class#getClasses "queryAllPublicClasses": true
java.lang.Class#getDeclaredClasses "queryAllDeclaredClasses": true
java.lang.Class#getPermittedSubclasses "queryAllPermittedSubclasses": true
java.lang.Class#getNestMembers "queryAllNestMembers": true

All methods above would return all elements when metadata entry is present, or throw a missing-metadata exception if the metadata entry is not present.
All methods above and corresponding metadata entries would be tracked by the Native Image agent.

Safe Composition of Resource Metadata

Resource metadata allows for include patterns such as

{
  "resources": {
    "includes":[{
      "pattern": "assets/.*"
    }]
  }
}

and exclude patterns

{
  "resources": {
    "excludes":[{
      "pattern": "assets/.*.png"
    }]
  }
}

This allows metadata from third-party jars to remove a resource by accident. The second example above removes all png files from assets of another library.

To allow safe composition, exclude patterns must apply only to resources that were matched by the include patterns in the same file. With this change the above
example would still include all files from assets as the exclude pattern doesn't have a corresponding include pattern.
To remove png files from assets the file would have to be specified as:

{
  "resources": {
    "includes":[{
      "pattern": "assets/.*"
    }],
    "excludes":[{
      "pattern": "assets/.*.png"
    }]
  }
}

Note that composing all examples above would still include all resources from assets as the first file doesn't have an exclude pattern.

@JnRouvignac
Copy link

Hello! Release notes seem to say this issue is fixed, and yet, the issue is still open here. Who is right? :D

@vjovanov
Copy link
Member Author

vjovanov commented Oct 9, 2023

The reflection part is fixed but marked as experimental. When you use -H:ThrowMissingRegistrationErrors=<your_package> the reflection will be safely composable.
The reason for -H:ThrowMissingRegistrationErrors=<your_package> being experimental is that we are waiting for the frameworks (e.g., Spring Boot) to adopt the new behavior.

This feature will become available as non-experimental in the next release (GraalVM for Java 22), and will be promoted to the default behavior as the community adopts it.

The composability of the resource patterns is tracked at #7487

@vjovanov
Copy link
Member Author

vjovanov commented Dec 7, 2023

This item is now mostly complete when the -H:ThrowMissingRegistrationErrors= is set. To be complete it still depends on #7487

@spavlusieva spavlusieva changed the title Safe Composition of Metadata [GR-49770] Safe Composition of Metadata Apr 29, 2024
@vjovanov
Copy link
Member Author

This item is now complete as we have finished: #7487

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Released
Status: Done
Development

No branches or pull requests

4 participants