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

FLAG_SET_ERGO silently ignores invalid values

XMLWordPrintable

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

      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?

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

              Created:
              Updated:
              Resolved: