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

[aarch64] Bug in MacroAssembler::klass_decode_mode()

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 24
    • 11, 17, 21, 24
    • hotspot
    • b27
    • aarch64

      In `MacroAssembler::klass_decode_mode()`, there is a subtle (I think day zero) bug in the part that determines whether we can use XOR.

      ```
        if (operand_valid_for_logical_immediate(
              /*is32*/false, (uint64_t)CompressedKlassPointers::base())) {
      (1) const size_t range = CompressedKlassPointers::klass_range_end() - CompressedKlassPointers::base();
      (2) const uint64_t range_mask = (1ULL << log2i(range)) - 1;
      (3) if (((uint64_t)CompressedKlassPointers::base() & range_mask) == 0) {
            log_debug(metaspace)("MacroAssembler::klass_decode_mode xor");
            return (_klass_decode_mode = KlassDecodeXor);
          }
        }
      ```

      We first determine if the encoding base is encodable as immediate. If it is, then we check if it intersects with the value range of a narrow Klass ID.

      (Note: the code ignores encoding shift since the XOR will be applied to the pre-shifted narrow Klass value later.)

      The test is done by
      1) calculating the range the encoding needs to cover
      2) calculating a corresponding bit mask
      3) checking that this mask does not intersect with the encoding base.

      (2) contains an error: `range_mask = (1ULL << log2i(range)) - 1` . log2i returns the largest log2 value *smaller* than range. So, for range values that are not a pow2 value, the resulting mask will be one bit short at the upper end. That means that the code may erroneously accept encoding base values that cannot be xor'ed losslessly with large narrow Klass IDs.

      Example:

      Let range be 80MB (`-XX:CompressedClassSpaceSize=80m -Xshare:off`).

      Then, range_mask = `1 << log2i(80m) - 1` => `(1 << 26) - 1` => `0x3ff_ffff`

      The largest possible nKlass value, however, sits just below 80MB => `0x500_0000`. As we see, the mask does not cover the full extent of the narrow Klass ID value range (bit 26 is not covered).

      Hence, if we have a base with a `1` in bit 26, and is > 32bit (to avoid zero-based encoding and enter the xor calculation), its bit 26 intersects a possible bit 26 in high-value narrow Klass ID. The xor would not be lossless.


      The error is very unlikely because
      - we reserve the klass range at hand-picked addresses that are guaranteed not to intersect with the narrow Klass range. That this fails is exceedingly rare. Only then we get, as a fallback, whatever "random" address the OS gives us.
      - The class space is rarely filled so high that the highest bit of a narrowKlass ID is `1`.

      That could explain why this never caused an issue.


      Reproduce:

      ```
      java -XX:CompressedClassSpaceBaseAddress=0x1Fc000000 -XX:CompressedClassSpaceSize=80m -Xlog:metaspace* -Xshare:off
      ```

      it does not reproduce an error, but causes the JVM to start in XOR mode with an encoding base of `0x1fc000000` and a narrow Klass ID range of `[0 .. 0x5000000)` - bit 26 interleaves.

            stuefe Thomas Stuefe
            stuefe Thomas Stuefe
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: