-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this 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."); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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<>(); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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
- don't need to split it up into the separate "Feature", "Errors", and "Plugins" classes
- you don't need to register a separate singleton because the instance of
SystemPropertyFeature
is automatically available as an image singleton
There was a problem hiding this comment.
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 = { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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() { |
There was a problem hiding this comment.
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 + "'"); | |||
} | |||
} | |||
} |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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?
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 |
4928fa8
to
350a1ec
Compare
There was a problem hiding this 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++) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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())); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 = { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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."); |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2020
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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?
350a1ec
to
2382af5
Compare
There was a problem hiding this 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<>( |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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
System Property Differences
Here lists the detailed differences between traditional and native image version on JDK11.
Legends:
System.getProperty
with corresponding property name results null.The contents in this table are from the result of running following code:
Limitation
This patch can only check the calling of
System.getProperty()
with string literals. Calling with string variables is missed.