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

Patching of C1 compiled code relies on undefined behavior

    Details

    • Type: Bug
    • Status: Open
    • Priority: P3
    • Resolution: Unresolved
    • Affects Version/s: 8u212, 9, 10, 11, 12, 13
    • Fix Version/s: 15
    • Component/s: hotspot

      Description

      "The act of one processor writing data into the currently executing code segment of a second processor with the intent of having the second processor execute that data as code is called cross-modifying code." [1]

      There are several places in Hotspot where we perform cross-modification of code in an *unsychronized* fashion (listed by John in JDK-8081782):
      (1) Updating of Inline Caches
      (2) Patching verified entry when converting nmethod to non-entrant
      (3) Patching C1 compiled code

      For above cases it's okay if some other threads still see unpatched values. For example, when hitting an uncommon trap: While the nmethod might still be executed by other threads, we atomically patch the entry point such that it points to `SharedRuntime::get_handle_wrong_method_stub()` (see `nmethod::make_not_entrant_or_zombie()`). It's fine for other threads to miss that update and continue execution, they will eventually hit the uncommon trap as well. However, this assumes that although the update might be missed by other threads, it's still safe, i.e., a thread either sees the old value or the new value.

      Now several (also recent) Intel processors are affected by an issue named "Unsynchronized Cross-Modifying Code Operations Can Cause Unexpected Instruction Execution Results" that can lead to "unexpected or unpredictable execution behavior" [2]. This means that (1) - (3) can lead to undefined behavior and this is what happens in the case reported by this bug: we crash due to unsychronized nmethod entry patching (2).

      Cases (1) and (2) will be addressed by the "New Invoke Bindings" JEP (JDK-8221828). The problem with case (3) should be addressed by this bug.

      The suggested workaround by Intel is to "use the XMC synchronization algorithm as detailed in the Intel Architecture Software Developer's Manual Volume 3: System Programming Guide, Section: Handling Self- and Cross-Modifying Code." (see 8.1.3 in [1]) which is basically a stop-the-world (i.e. only patch at safepoints) approach.

      So the obvious solution would be to only patch at safepoints or implement patching similar to what is done on AARCH64 (see `DEOPTIMIZE_WHEN_PATCHING`, JDK-8219993) but that will have a potentially huge performance impact.

      [1] https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-3a-part-1-manual.pdf
      [2] Some examples of affected processors:
      - Intel Xeon Phi x200 family, see "KNL9"
       https://www.intel.co.uk/content/dam/www/public/us/en/documents/specification-updates/xeon-phi-processor-specification-update.pdf
      - N-series Intel Pentium and Intel Celeron, see "CHP15"
       https://www.intel.com/content/dam/www/public/us/en/documents/specification-updates/pentium-celeron-n-series-spec-update.pdf
      - Intel Core 2 duo E7000/E8000, see "AW75"
       http://download.intel.com/design/processor/specupdt/318733.pdf
      - Intel Core 2 Extreme X6800/E4000/E6000, see "AI33"
       http://download.intel.com/design/processor/specupdt/313279.pdf

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                thartmann Tobias Hartmann
                Reporter:
                thartmann Tobias Hartmann
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated: