Skip to content

Report warning for unsupported system properties #2834

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ziyilin
Copy link
Collaborator

@ziyilin ziyilin commented Sep 8, 2020

Overview

The Java system properties are not consistent between traditional JDK version and native image version. Some system properties are missing and some are different. User may expect the same behavior between traditional and native image, or at least explicit message to warn them about the change. This patch checks the usage of such system properties and reports warning at both native image build time and run time. This patch can fix issue #2835.

Features

  • Check the usage of the missing system properties at native image build time and report warning messages as follows before writing image.
    image
  • Report using missing system property exception at run time

System Property Differences

Here lists the detailed differences between traditional and native image version on JDK11.

Property Name Traditional JDK value Native Image value
awt.toolkit sun.awt.X11.XToolkit N/A
file.encoding UTF-8 UTF-8
file.separator / /
java.awt.graphicsenv sun.awt.X11GraphicsEnvironment N/A
java.awt.printerjob sun.print.PSPrinterJob N/A
java.class.path bin EMPTY
java.class.version 55 55
java.home /home/cengfeng.lzy/tools/labsjdk-ce-11.0.8-jvmci-20.2-b03 N/A
java.io.tmpdir /tmp /tmp
java.library.path /usr/java/packages/lib:/usr/lib64:/lib64:/lib:/usr/lib EMPTY
java.runtime.name OpenJDK Runtime Environment N/A
java.runtime.version 11.0.8+10-jvmci-20.2-b03 N/A
java.specification.name Java Platform API Specification Java Platform API Specification
java.specification.vendor Oracle Corporation Oracle Corporation
java.specification.version 11 11
java.vendor GraalVM Community Oracle Corporation
java.vendor.url https://www.graalvm.org/ https://www.graalvm.org/
java.vendor.url.bug https://github.com/oracle/graal/issues N/A
java.version 11.0.8 11.0.8
java.version.date 2020/7/14 N/A
java.vm.compressedOopsMode Zero based N/A
java.vm.info mixed mode N/A
java.vm.name OpenJDK 64-Bit Server VM Substrate VM
java.vm.specification.name Java Virtual Machine Specification Java Virtual Machine Specification
java.vm.specification.vendor Oracle Corporation Oracle Corporation
java.vm.specification.version 11 11
java.vm.vendor GraalVM Community Oracle Corporation
java.vm.version 11.0.8+10-jvmci-20.2-b03 GraalVM dev Java 11
jdk.debug release N/A
line.separator \r\n \r\n
os.arch amd64 amd64
os.name Linux Linux
os.version 3.10.0-327.ali2012.alios7.x86_64 3.10.0-327.ali2012.alios7.x86_64
path.separator : :
sun.arch.data.model 64 64
sun.boot.library.path /home/cengfeng.lzy/tools/labsjdk-ce-11.0.8-jvmci-20.2-b03/lib N/A
sun.cpu.endian little N/A
sun.cpu.isalist EMPTY N/A
sun.io.unicode.encoding UnicodeLittle N/A
sun.java.command PrintAllProperties N/A
sun.java.launcher SUN_STANDARD N/A
sun.jnu.encoding UTF-8 UTF-8
sun.management.compiler HotSpot 64-Bit Tiered Compilers N/A
sun.os.patch.level unknown N/A
user.country US N/A
user.dir /home/cengfeng.lzy/svmTestsForCommunity/systemPropertyTest /home/cengfeng.lzy/svmTestsForCommunity/systemPropertyTest
user.home /home/cengfeng.lzy /home/cengfeng.lzy
user.language en N/A
user.name cengfeng.lzy cengfeng.lzy
user.timezone EMPTY N/A

Legends:

  • EMPTY stands for empty string
  • N/A means not supported, calling System.getProperty with corresponding property name results null.

The contents in this table are from the result of running following code:

 public static void main(String[] args) {
        Properties p = System.getProperties();
        Enumeration keys = p.keys();
        while (keys.hasMoreElements()) {
            String key = (String) keys.nextElement();
            String value = (String) p.get(key);
            if(value.length()==0) value = "EMPTY";
            System.out.println(key + "=" + value);
        }
    }

Limitation

This patch can only check the calling of System.getProperty() with string literals. Calling with string variables is missed.

Copy link

@christianwimmer christianwimmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this is an interesting idea. Printing warning messages at image build time sounds helpful. It only works when System.getProperties is called, with a constant string argument. But that is probably a common use case.

I don't see a way to print a warning message at run time. A VM does not produce output on its own. One possibility would be to make a separate "report at run time option" that the user can manually turn on. In that case, the full stack trace should be printed too - just a warning message without any context information is not actionable.

return properties.getProperty(key);
String ret = properties.getProperty(key);
if (ret == null && isNotSupported(key)) {
System.out.println("Java system property " + key + " is not available in native image. Please explicitly assign the expected value via -D" + key + "=, or avoid using this property.");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The VM must never itself print any unsolicited output. So I don't see a way to print a warning message like this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed by using exception here

}

public static boolean isNotSupported(String key) {
return Arrays.stream(UNSUPPORTED_PROPERTIES).anyMatch(s -> s.equals(key));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

General comment: core parts of SVM cannot use streams, because that makes so much of the JDK reachable that the size of a "hello world" explodes.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

import java.util.Set;

public class UnsupportedSystemPropertyErrors {
private final Set<String> systemPropertyCalls = new HashSet<>();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be a data structure that is thread safe, like ConcurrentHashMap

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


public class SystemPropertyPlugin {
@SuppressWarnings("unused")
public static void registerInvocationPlugins(ImageClassLoader imageClassLoader, SnippetReflectionProvider snippetReflection, AnnotationSubstitutionProcessor annotationSubstitutions,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you pass in all these parameters such as AnnotationSubstitutionProcessor and SVMHost?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need them, removed.

private AnnotationSubstitutionProcessor annotationSubstitutions;

public SystemPropertyFeature() {
ImageSingletons.add(UnsupportedSystemPropertyErrors.class, new UnsupportedSystemPropertyErrors());

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since all of this checking code is running only during image generation, you

  1. don't need to split it up into the separate "Feature", "Errors", and "Plugins" classes
  2. you don't need to register a separate singleton because the instance of SystemPropertyFeature is automatically available as an image singleton

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged UnsupportedSystemPropertyErrors and SystemPropertyPlugin classes into SystemPropertyFeature.

/**
* System properties are unsupported by default.
*/
private static final String[] UNSUPPORTED_PROPERTIES = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"unsupported" is in general the wrong term for all of this PR. They are of course supported (since you can manually set them), they just are not set currently by default.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed by changing to INCOMPATIBLE_PROPERTIES

}

@Override
public boolean isDecorator() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this, since the apply method always returns false

@@ -71,4 +71,4 @@ protected static boolean asBoolean(Object value, String propertyName) {
}
throw new JSONParserException("Invalid boolean value '" + value + "' for element '" + propertyName + "'");
}
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary change (and also a checkstyle violation)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverted

"java.vm.info",
"sun.boot.class.path",
"sun.boot.library.path",
"sun.cpu.endian",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that sounds like a property that can be inherited from image build time. Maybe some other too?

@ziyilin
Copy link
Collaborator Author

ziyilin commented Sep 11, 2020

It's necessary to explicitly report the using of incompatible system property, otherwise user may get confused and it's difficult to debug the native image. Proper exception message will help the user to locate the problem.

I add a new option -R:+ReportIncompatibleSystemPropertyError to throw com.oracle.svm.core.jdk.IncompatibleSystemPropertyException when a system property is null. User can manually turn it on.

Copy link

@christianwimmer christianwimmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the cleanups, the code looks pretty good now. I added a few more comments.

}

public static boolean isIncompatible(String key) {
for (int i = 0; i < INCOMPATIBLE_PROPERTIES.length; i++) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The INCOMPATIBLE_PROPERTIES list is not super-long, but still it is very easy to prepare a Set<String> instead of the String[] array. You just need a new HashSet<>(Arrays.asList(...)) in the INCOMPATIBLE_PROPERTIES definition above.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

if (name.isConstant()) {
String propertyKey = snippetReflection.asObject(String.class, name.asJavaConstant());
if (SystemPropertiesSupport.isIncompatible(propertyKey)) {
systemPropertyCalls.add("Incompatible property:" + propertyKey + " is used at " + b.getCode().asStackTraceElement(b.bci()));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: missing space after : in the message

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

/**
* System properties are unsupported by default.
*/
private static final String[] INCOMPATIBLE_PROPERTIES = {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking about the name for a while, my suggestion is to call it UNDEFINED_PROPERTIES (with the appropriate changes of the option and classes, fields, ...). That name avoids all sorts of legal hassles.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@@ -0,0 +1,7 @@
package com.oracle.svm.core.jdk;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

License header missing on this file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could also just use the UnsupportedFeatureError class that we already have.

@@ -48,6 +50,11 @@
*/
public abstract class SystemPropertiesSupport {

public static class SystemPropertyFeatureOptions{
@Option(help = "Report the usage of incompatible property as exception when it is not explicitly set)")//
public static final RuntimeOptionKey<Boolean> ReportIncompatibleSystemPropertyError = new RuntimeOptionKey<>(false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would name it ReportUnsupportedSystemPropertyErrors.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking about the name for a while, my suggestion is to call it UNDEFINED_PROPERTIES (with the appropriate changes of the option and classes, fields, ...). That name avoids all sorts of legal hassles.

As Chris suggested, I think "undefined" would be a better name.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, please use undefined

return properties.getProperty(key);
String ret = properties.getProperty(key);
if (ret == null && isIncompatible(key) && SystemPropertyFeatureOptions.ReportIncompatibleSystemPropertyError.getValue()) {
throw new IncompatibleSystemPropertyException("Java system property " + key + " is incompatible in native image. Please explicitly assign the expected value via -D" + key + "=, or avoid using this property.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here as well. I would use UnsupportedSystemPropertyException.

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2020

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

private static final String[] INCOMPATIBLE_PROPERTIES = {
"awt.toolkit",
"file.encoding.pkg",
"java.awt.graphicsenv",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arodionov we should make sure to enable these once AWT is complete.

"java.runtime.name",
"java.runtime.version",
"java.vendor.url.bug",
"java.vm.info",
Copy link
Member

@vjovanov vjovanov Sep 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put native image, native, or AOT here?

Copy link

@christianwimmer christianwimmer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, did not notice when you pushed the latest version. I think we are getting too complicated now, with the "added" / "removed" properties. Simplifying that is a bit of a refactoring of the existing code, but I think worth it.

"user.timezone"};

/** Properties are removed or added since JDK8*/
private static final List<PropertyInfo> CHANGED_PROPERTIES_SINCE_8 = new ArrayList<>(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this "delta" list, since it is difficult to maintain in the long run. Instead, we should change the whole mechansim we have right now (HOSTED_PROPERTIES and initializeProperty()) to a PropertyInfo like you introduced - without the need for "added" and "deleted" but instead with a predicate onlyWith where you can specify the existing classes like JDK8OrEarlier or JDK11OrLater.
Note also that we do not need to support only JDK 8, 11, and 15 - and not any versions in between.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note also that we do not need to support only JDK 8, 11, and 15 - and not any versions in between.

Do you mean only support 8, 11 and 15, or all the versions in between? I think it should be the later. For example, java.vm.compressedOopsMode is introduced in JDK 9, its onlyWith should be JDK9OrLater.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean "only support 8, 11 and 15". Many parts of native image don't support any of the versions in between already. Sticking to the long term support versions plus "latest" keeps the code base manageable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored.

Many system properties are undefined in native image. Getting such
properties with System.getProperty returns null. It may result
unexpected behaviors.

This patch checks the usage of such properties at native image build, and
throw exception at run time if -R:+ReportUndefinedSystemPropertyError
option is set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants