JDK-8059557 : JEP 245: Validate JVM Command-Line Flag Arguments
  • Type: JEP
  • Component: hotspot
  • Sub-Component: runtime
  • Priority: P1
  • Status: Closed
  • Resolution: Delivered
  • Fix Versions: 9
  • Submitted: 2014-10-01
  • Updated: 2018-04-23
  • Resolved: 2016-03-09
Related Reports
Blocks :  
Blocks :  
Blocks :  
Blocks :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Sub Tasks
JDK-8078554 :  
JDK-8078555 :  
JDK-8078556 :  
JDK-8134995 :  
Description
Summary
-------

Validate the arguments to all JVM command-line flags so as to avoid
crashes, and ensure that appropriate error messages are displayed when
they are invalid.


Non-goals
---------

 - We will not validate arguments to flags that are not processed by
   the JVM.

 - We will not attempt to adjust arguments to fall within allowed
   ranges; we will only detect incorrect arguments, not correct them.


Success Metrics
---------------

Any JVM flag that takes a value and is provided an out-of-range value is
shown to not cause a JVM crash but rather issue an informative error
message.  This will be done for JVM flags whether they are set
ergonomically (e.g., in include files), set on the command line, set via
tool input, or set via APIs (e.g., `attachListener`/`jcmd`, or
`java.lang.management`).


Description
-----------

Any interface, whether it be programmatic or user-visible, must provide
adequate capability to validate input values.  In the case of command
lines, it is critical to implement range checks for arguments which
require a user-specified value.  The `globals.hpp` source file contains
the origin of the flag value and rudimentary range checking.  Expanding
and completing this can provide correct coverage.

In addition, we should define a framework to make it very easy for
someone adding a new JVM command-line flag to take advantage of this
validity checking.  The framework should be flexible, allowing for checks
of a single value, being between a minimum and maximum value, or being
within a set of values, etc.

We will implement this feature by expanding existing macro tables (e.g.,
`RUNTIME_FLAGS`) to add optional `range(min, max)` and
`constraint(function_pointer)` entries.  Current range-checking and other
ad-hoc validation code will be ported over and then removed.

The range and constraints checks are done every time a flag changes, as
well as late in the JVM initialization routine (i.e., in `init_globals()`
after `stubRoutines_init2()`) at the time when all flags have their final
values set.  We will continue to check the manageable flags as long as
the JVM runs.

For those flags that depend on others that might not be set at the time
of setting the flag in question, we will provide a mechanism in form of
an API (`CommandLineFlags::finishedInitializing()`) to let constraint
functions know when all flags have their final values set and change
their behavior from NOP to error as needed.

Intercepting flag value changes is done at a low level in
`CommandLineFlags::xxxxAtPut` setters to guarantee that manageable flags
are checked for their ranges and constraints (e.g., flags set via
`jcmd`).  For example, using `jcmd PID VM.set_flag MinHeapFreeRatio 101`,
which is outside the allowed range, will print out

    PID:
    MinHeapFreeRatio error: must have value in range [0...100]

in the `jcmd` output.

The range checks do not impose any behavioral changes upon the JVM
initialization process.  In particular they do not terminate the JVM, but
instead they propagate their status up to the code that uses them.  The
constraint functions can terminate the JVM to match existing custom
behavior as needed.

The range/constraint checks are non-verbose by default, to inhibit their
messages from being printed out.  Range checks do print error messages on
the error stream during JVM initialization, in order to match current
behavior.  Printing to the error stream for manageable flags is
inhibited; any error status will, rather, be handled by the
`WriteableFlags` code to provide verbose status into the provided
`FormatBuffer` so that it can be then printed by `jcmd` process itself
instead of by the target process.

In the event of range-check failure during JVM initialization, an error
message is printed by default in the following form:

    uintx UnguardOnExecutionViolation = 3 is outside the allowed range [ 0 ... 2 ]

We are not, however, committing to any particular format at this
time.  Existing tests that expect a certain message format will have to
be modified to allow the new format.

The existing behavior is not changed with respect to clamping flags to
fit within a specified range (i.e., we do not clamp), even though we have
that capability.  We conform to the existing behavior during error
detection while initializing the JVM (i.e., we terminate the process).


Alternatives
------------

Variadic macros offered a slightly different, and possibly a cleaner, way
to define ranges and constraints, but a "trailing comma with empty args"
issue in the Solaris C++ compiler prevented the adoption of this
approach.

Comments
Feature passes JPRT (-testset hotspot, ie. JTREG) and UTE (vm.quick.testlist)
23-04-2015

Only variadic macros with "trailing comma with empty args" is a problem (on Solaris). Variadic macros themselves are fine. Also, I found that when using an IDE (in my case Xcode) I can expand the macros by using a "Preprocessor menu" command, which alleviates to some extend the issues working with macros.
26-03-2015

Updated JEP to reflect Staffan Larsen concerns that jcmd error should appear in jcmd process, not the target process.
26-03-2015

But Risks talks about variadic macros being a problem. Will that be fixed by a compiler upgrade?
25-03-2015

Re 1) I do agree that at the moment the exception is not very meaningful Re 2) It was mentioned to me that we could consider C++ templates to replace macros, but after I experimented with the variadic macros, they seemed to offer an easy implementation with the least code changes required, which was desirable. Perhaps we can file a task to tackle changing macros to C++ templates or another solution?
25-03-2015

1) Does the com.sun.tools.attach.AttachOperationFailedException thrown by the tool contain any additional information to why it failed? That exception alone is not very useful to the user. 2) Is there any possibility to get rid of the macros at all? They are really annoying mostly because IDEs cannot deal very well with these definitions.
25-03-2015

Re jinfo (or jcmd): my current snapshot of jdk9 doesn't in fact report anything at all when I try to modify a manageable flag to be outside allowed range (ex. jinfo -flag CMSTriggerInterval=10 PID), and allows the PID to continue, so I am probably comparing against too old implementation. I will compare to TOT jdk9 that has the new vm_setflag feature.
25-03-2015

Perhaps this is clear but you may want to add to the non-goals that this work does not change any flags to made them valid. That this work is to detect invalid flags only. I mention this because the setting of some GC flags cause others to be set ergonomically. That type of ergonomic changes should not leak into this work.
23-03-2015

When jinfo (or jcmd) is used to modify a flag in an incorrect way, the error message should be printed by the jinfo (or jcmd) process, not by the PID process. I believe that is what the implementation looks like after the introduction of WriteableFlags.
23-03-2015

Updated as requested based on your and my notes.
12-03-2015

Gerard, this looks really good. Thank you so much. Agree with exiting on error rather than clamping behavior - so you can add a small note to the description but take this out of open issues please. Please add a brief description of when you check the flags (and whether you intend to handle flag X requires flag Y is set or not - or maybe only at the end of command-line setting but not on each setting?) how you are handling consistent error messages how you will handle jcmd vs. command-line how you are not changing the choice or vm exit on error Also - we are not committing to the exact output strings on validation errors. For non-goals - you might clarify - e.g. this does not handle command-line options parsed by the launcher. Under Description: "use visible" -> "user visible". Please add dev tasks for gc, serviceability and compiler (work with Mary). many thanks, Karen
12-03-2015

Yes, the JEP in fact specifies that dynamically setting the flags via jcmd and other API should be covered.
13-02-2015

I was glad to see that validation of manageable flags (those set by attach, JMX or jcmd) was also considered in this JEP. At least that is how I interpret the following sentence: "This validation applies for VM options ... set via tool input or set via APIs (e.g. attachListener/jcmd, java.lang.management via management.cpp)." But then the comment above seems to indicate that this was not the case? Please clarify. Note that manageable flags will soon be handled by the new file writableFlags.cpp (http://mail.openjdk.java.net/pipermail/serviceability-dev/2015-February/016598.html).
12-02-2015

I believe this JEP only covers the values passed in via command line options - ie. it does not cover changing the values later after the VM has been already initialized, for example: via jcmd. Though there probably should be another JEP filed to address just that. The issue of what happens when a value outside of specified range is passed is a good and outstanding question yet to be addressed.
11-02-2015

Should there be a statement about what happens when an invalid value is passed in? For example, if from the command line an error message will be emitted and the JVM will exit. If sent from a tool (jcmd) an error message and ignored? There are flags that cannot be changed after JVM initialization (max heap size, for example). Is the action of the JVM covered by this JEP? Command line flags send by Java API's are included. Are changes to those API's covered by this JEP?
11-02-2015