Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8224980

FLAG_SET_ERGO silently ignores invalid values

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P4
    • 21
    • 13
    • hotspot
    • b11

    Description

      If code tries to set a flag with a value that violates its constraint, the setting will be ignored and no warning is reported.

      This can be seen by applying the following patch:
      diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp
      --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp
      +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp
      @@ -1444,7 +1444,7 @@
       }
       
       void JVMFlag::printError(bool verbose, const char* msg, ...) {
      - if (verbose) {
      + if (true) {
           va_list listPointer;
           va_start(listPointer, msg);
           jio_vfprintf(defaultStream::error_stream(), msg, listPointer);

      And running:
      test/hotspot/jtreg/runtime/CommandLine/OptionsValidation

      The failing test shows that with the following command line:
      $ ../build/release/images/jdk/bin/java -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=TestOptionsWithRanges.jsa -Xshare:dump -XX:SharedBaseAddress=0

      We try to set NonNMethodCodeHeapSize to 0:
      uintx NonNMethodCodeHeapSize=0 is outside the allowed range [ 4096 ... 18446744073709551615 ]

      And if we check -XX:+PrintFlagsFinal | grep NonNMethodCodeHeapSize we see that the flag has not been set:
      uintx NonNMethodCodeHeapSize=0 is outside the allowed range [ 4096 ... 18446744073709551615 ]
          uintx NonNMethodCodeHeapSize = 5242880 {pd product} {default}

      The code that tries to set the flag to a value outside its range is here:
        if (SegmentedCodeCache) {
          // Use multiple code heaps
          initialize_heaps();
        } else {
          // Use a single code heap
          FLAG_SET_ERGO(NonNMethodCodeHeapSize, 0);
          FLAG_SET_ERGO(ProfiledCodeHeapSize, 0);
          FLAG_SET_ERGO(NonProfiledCodeHeapSize, 0);
          ReservedCodeSpace rs = reserve_heap_memory(ReservedCodeCacheSize);
          add_heap(rs, "CodeCache", CodeBlobType::All);
        }

      The code that swallows the warning is here:
      static JVMFlag::Error apply_constraint_and_check_range_size_t(const JVMFlag* flag, size_t new_value, bool verbose) {
        JVMFlag::Error status = JVMFlag::SUCCESS;
        JVMFlagRange* range = JVMFlagRangeList::find(flag);
        if (range != NULL) {
          status = range->check_size_t(new_value, verbose);
        }
        if (status == JVMFlag::SUCCESS) {
          JVMFlagConstraint* constraint = JVMFlagConstraintList::find_if_needs_check(flag);
          if (constraint != NULL) {
            status = constraint->apply_size_t(new_value, verbose);
          }
        }
        return status;
      }


      JVMFlag::Error JVMFlag::size_tAtPut(JVMFlag* flag, size_t* value, JVMFlag::Flags origin) {
        if (flag == NULL) return JVMFlag::INVALID_FLAG;
        if (!flag->is_size_t()) return JVMFlag::WRONG_FORMAT;
        JVMFlag::Error check = apply_constraint_and_check_range_size_t(flag, *value, !JVMFlagConstraintList::validated_after_ergo());
        if (check != JVMFlag::SUCCESS) return check;
        size_t old_value = flag->get_size_t();
        trace_flag_changed<EventUnsignedLongFlagChanged, u8>(flag, old_value, *value, origin);
        check = flag->set_size_t(*value);
        *value = old_value;
        flag->set_origin(origin);
        return check;
      }

      !JVMFlagConstraintList::validated_after_ergo() starts to return false in the middle of the JVM initialization. This value is passed to the verbose parameter, and check_size_t(...) calls printError(...) with verbose set to false

      void JVMFlag::printError(bool verbose, const char* msg, ...) {
        if (verbose) {
          va_list listPointer;
          va_start(listPointer, msg);
          jio_vfprintf(defaultStream::error_stream(), msg, listPointer);
          va_end(listPointer);
        }
      }

      Since the check returned an error size_tAtPut returns at this line:
        if (check != JVMFlag::SUCCESS) return check;

      and the setting of the flag is silently ignored.

      If found one problematic instance of this, maybe there are more?

      Attachments

        Issue Links

          Activity

            People

              iklam Ioi Lam
              stefank Stefan Karlsson
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: