diff mbox series

[meta-java,kirkstone] openjdk-8: Fix CVE-2024-20919 & CVE-2024-20921

Message ID 20240628044013.4771-1-hprajapati@mvista.com
State New
Headers show
Series [meta-java,kirkstone] openjdk-8: Fix CVE-2024-20919 & CVE-2024-20921 | expand

Commit Message

Hitendra Prajapati June 28, 2024, 4:40 a.m. UTC
Backport fixes for:

* CVE-2024-20919 - Upstream-Status: Backport from https://github.com/openjdk/jdk8u/commit/77d38b78e4993381ddb113d012b30ab2d7cd9215
* CVE-2024-20921 - Upstream-Status: Backport from https://github.com/openjdk/jdk8u/commit/f7cb28de01117f598ecf48ad58e277c3a4590436

Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
 .../openjdk/openjdk-8-release-common.inc      |   2 +
 .../patches-openjdk-8/CVE-2024-20919.patch    | 126 ++++
 .../patches-openjdk-8/CVE-2024-20921.patch    | 657 ++++++++++++++++++
 3 files changed, 785 insertions(+)
 create mode 100644 recipes-core/openjdk/patches-openjdk-8/CVE-2024-20919.patch
 create mode 100644 recipes-core/openjdk/patches-openjdk-8/CVE-2024-20921.patch

Comments

Tim Orling June 28, 2024, 4:47 a.m. UTC | #1
Pretty sure we need all of these CVEs fixed on master first before we back
port to a stable branch.

On Thu, Jun 27, 2024 at 9:40 PM Hitendra Prajapati via
lists.openembedded.org <hprajapati=mvista.com@lists.openembedded.org> wrote:

> Backport fixes for:
>
> * CVE-2024-20919 - Upstream-Status: Backport from
> https://github.com/openjdk/jdk8u/commit/77d38b78e4993381ddb113d012b30ab2d7cd9215
> * CVE-2024-20921 - Upstream-Status: Backport from
> https://github.com/openjdk/jdk8u/commit/f7cb28de01117f598ecf48ad58e277c3a4590436
>
> Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
> ---
>  .../openjdk/openjdk-8-release-common.inc      |   2 +
>  .../patches-openjdk-8/CVE-2024-20919.patch    | 126 ++++
>  .../patches-openjdk-8/CVE-2024-20921.patch    | 657 ++++++++++++++++++
>  3 files changed, 785 insertions(+)
>  create mode 100644
> recipes-core/openjdk/patches-openjdk-8/CVE-2024-20919.patch
>  create mode 100644
> recipes-core/openjdk/patches-openjdk-8/CVE-2024-20921.patch
>
> diff --git a/recipes-core/openjdk/openjdk-8-release-common.inc
> b/recipes-core/openjdk/openjdk-8-release-common.inc
> index c977c96..985d0d7 100644
> --- a/recipes-core/openjdk/openjdk-8-release-common.inc
> +++ b/recipes-core/openjdk/openjdk-8-release-common.inc
> @@ -22,6 +22,8 @@ PATCHES_URI = "\
>      file://2008-jdk-no-unused-deps.patch \
>
>  file://2009-jdk-make-use-gcc-instead-of-ld-for-genSocketOptionRe.patch \
>      file://CVE-2022-40433.patch \
> +    file://CVE-2024-20919.patch \
> +    file://CVE-2024-20921.patch \
>  "
>  HOTSPOT_UB_PATCH = "\
>      file://1001-hotspot-fix-crash-on-JNI_CreateJavaVM.patch \
> diff --git a/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20919.patch
> b/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20919.patch
> new file mode 100644
> index 0000000..566e01c
> --- /dev/null
> +++ b/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20919.patch
> @@ -0,0 +1,126 @@
> +From 77d38b78e4993381ddb113d012b30ab2d7cd9215 Mon Sep 17 00:00:00 2001
> +From: Martin Balao <mbalao@openjdk.org>
> +Date: Fri, 29 Sep 2023 13:01:13 +0000
> +Subject: [PATCH] 8314295: Enhance verification of verifier
> +
> +Reviewed-by: yan, andrew
> +Backport-of: 08980a0a60bc48c17eacd57fd2d7065ac2d986a8
> +
> +Upstream-Status: Backport [
> https://github.com/openjdk/jdk8u/commit/77d38b78e4993381ddb113d012b30ab2d7cd9215
> ]
> +CVE: CVE-2024-20919
> +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
> +---
> + hotspot/src/share/vm/classfile/verifier.cpp   |  5 +++--
> + .../src/share/vm/interpreter/bytecodes.cpp    | 22 ++++++++++++++-----
> + jdk/src/share/native/common/check_code.c      | 11 ++++++----
> + 3 files changed, 26 insertions(+), 12 deletions(-)
> +
> +diff --git a/hotspot/src/share/vm/classfile/verifier.cpp
> b/hotspot/src/share/vm/classfile/verifier.cpp
> +index 2a572058..3a3e04ba 100644
> +--- a/hotspot/src/share/vm/classfile/verifier.cpp
> ++++ b/hotspot/src/share/vm/classfile/verifier.cpp
> +@@ -2078,11 +2078,12 @@ void ClassVerifier::verify_switch(
> +           "low must be less than or equal to high in tableswitch");
> +       return;
> +     }
> +-    keys = high - low + 1;
> +-    if (keys < 0) {
> ++    int64_t keys64 = ((int64_t)high - low) + 1;
> ++    if (keys64 > 65535) {  // Max code length
> +       verify_error(ErrorContext::bad_code(bci), "too many keys in
> tableswitch");
> +       return;
> +     }
> ++    keys = (int)keys64;
> +     delta = 1;
> +   } else {
> +     keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize);
> +diff --git a/hotspot/src/share/vm/interpreter/bytecodes.cpp
> b/hotspot/src/share/vm/interpreter/bytecodes.cpp
> +index 24adc4d9..f0753735 100644
> +--- a/hotspot/src/share/vm/interpreter/bytecodes.cpp
> ++++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp
> +@@ -111,12 +111,18 @@ int Bytecodes::special_length_at(Bytecodes::Code
> code, address bcp, address end)
> +       if (end != NULL && aligned_bcp + 3*jintSize >= end) {
> +         return -1; // don't read past end of code buffer
> +       }
> ++      // Promote calculation to signed 64 bits to do range checks, used
> by the verifier.
> +       jlong lo = (jint)Bytes::get_Java_u4(aligned_bcp + 1*jintSize);
> +       jlong hi = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
> +       jlong len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize;
> +-      // only return len if it can be represented as a positive int;
> +-      // return -1 otherwise
> +-      return (len > 0 && len == (int)len) ? len : -1;
> ++      // Only return len if it can be represented as a positive int and
> lo <= hi.
> ++      // The caller checks for bytecode stream overflow.
> ++      if (lo <= hi && len == (int)len) {
> ++        assert(len > 0, "must be");
> ++        return (int)len;
> ++      } else {
> ++        return -1;
> ++      }
> +     }
> +
> +   case _lookupswitch:      // fall through
> +@@ -128,9 +134,13 @@ int Bytecodes::special_length_at(Bytecodes::Code
> code, address bcp, address end)
> +       }
> +       jlong npairs = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
> +       jlong len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize;
> +-      // only return len if it can be represented as a positive int;
> +-      // return -1 otherwise
> +-      return (len > 0 && len == (int)len) ? len : -1;
> ++      // Only return len if it can be represented as a positive int and
> npairs >= 0.
> ++      if (npairs >= 0 && len == (int)len) {
> ++        assert(len > 0, "must be");
> ++        return (int)len;
> ++      } else {
> ++        return -1;
> ++      }
> +     }
> +   }
> +   // Note: Length functions must return <=0 for invalid bytecodes.
> +diff --git a/jdk/src/share/native/common/check_code.c
> b/jdk/src/share/native/common/check_code.c
> +index 96091720..491b95cd 100644
> +--- a/jdk/src/share/native/common/check_code.c
> ++++ b/jdk/src/share/native/common/check_code.c
> +@@ -1,5 +1,5 @@
> + /*
> +- * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights
> reserved.
> ++ * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights
> reserved.
> +  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
> +  *
> +  * This code is free software; you can redistribute it and/or modify it
> +@@ -84,6 +84,7 @@
> + #include <assert.h>
> + #include <limits.h>
> + #include <stdlib.h>
> ++#include <stdint.h>
> +
> + #include "jni.h"
> + #include "jvm.h"
> +@@ -1202,7 +1203,7 @@ verify_opcode_operands(context_type *context,
> unsigned int inumber, int offset)
> +             }
> +         }
> +         if (opcode == JVM_OPC_tableswitch) {
> +-            keys = _ck_ntohl(lpc[2]) -  _ck_ntohl(lpc[1]) + 1;
> ++            keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1;
> +             delta = 1;
> +         } else {
> +             keys = _ck_ntohl(lpc[1]); /* number of pairs */
> +@@ -1682,11 +1683,13 @@ static int instruction_length(unsigned char
> *iptr, unsigned char *end)
> +     switch (instruction) {
> +         case JVM_OPC_tableswitch: {
> +             int *lpc = (int *)UCALIGN(iptr + 1);
> +-            int index;
> +             if (lpc + 2 >= (int *)end) {
> +                 return -1; /* do not read pass the end */
> +             }
> +-            index = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]);
> ++            int64_t low  = _ck_ntohl(lpc[1]);
> ++            int64_t high = _ck_ntohl(lpc[2]);
> ++            int64_t index = high - low;
> ++            // The value of low must be less than or equal to high -
> i.e. index >= 0
> +             if ((index < 0) || (index > 65535)) {
> +                 return -1;      /* illegal */
> +             } else {
> +--
> +2.25.1
> +
> diff --git a/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20921.patch
> b/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20921.patch
> new file mode 100644
> index 0000000..edce6f0
> --- /dev/null
> +++ b/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20921.patch
> @@ -0,0 +1,657 @@
> +From f7cb28de01117f598ecf48ad58e277c3a4590436 Mon Sep 17 00:00:00 2001
> +From: Roland Westrelin <rwestrel@redhat.com>
> +Date: Tue, 7 Nov 2023 11:08:30 +0000
> +Subject: [PATCH] 8314307: Improve loop handling
> +
> +Reviewed-by: mbalao, fferrari, andrew
> +Backport-of: 62ac93d145ca9fa1ab0c040533c62c42c202703a
> +
> +Upstream-Status: Backport [
> https://github.com/openjdk/jdk8u/commit/f7cb28de01117f598ecf48ad58e277c3a4590436
> ]
> +CVE: CVE-2024-20921
> +Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
> +---
> + hotspot/src/share/vm/opto/ifnode.cpp   |  59 +++-
> + hotspot/src/share/vm/opto/loopnode.cpp | 422 ++++++++++++++++++++-----
> + hotspot/src/share/vm/opto/loopnode.hpp |   4 +
> + hotspot/src/share/vm/opto/phaseX.hpp   |   6 +-
> + 4 files changed, 404 insertions(+), 87 deletions(-)
> +
> +diff --git a/hotspot/src/share/vm/opto/ifnode.cpp
> b/hotspot/src/share/vm/opto/ifnode.cpp
> +index 68f068d0..51579032 100644
> +--- a/hotspot/src/share/vm/opto/ifnode.cpp
> ++++ b/hotspot/src/share/vm/opto/ifnode.cpp
> +@@ -882,6 +882,46 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool
> can_reshape) {
> +     // then we are guaranteed to fail, so just start interpreting there.
> +     // We 'expand' the top 3 range checks to include all post-dominating
> +     // checks.
> ++    //
> ++    // Example:
> ++    // a[i+x] // (1) 1 < x < 6
> ++    // a[i+3] // (2)
> ++    // a[i+4] // (3)
> ++    // a[i+6] // max = max of all constants
> ++    // a[i+2]
> ++    // a[i+1] // min = min of all constants
> ++    //
> ++    // If x < 3:
> ++    //   (1) a[i+x]: Leave unchanged
> ++    //   (2) a[i+3]: Replace with a[i+max] = a[i+6]: i+x < i+3 <= i+6
> -> (2) is covered
> ++    //   (3) a[i+4]: Replace with a[i+min] = a[i+1]: i+1 < i+4 <= i+6
> -> (3) and all following checks are covered
> ++    //   Remove all other a[i+c] checks
> ++    //
> ++    // If x >= 3:
> ++    //   (1) a[i+x]: Leave unchanged
> ++    //   (2) a[i+3]: Replace with a[i+min] = a[i+1]: i+1 < i+3 <= i+x
> -> (2) is covered
> ++    //   (3) a[i+4]: Replace with a[i+max] = a[i+6]: i+1 < i+4 <= i+6
> -> (3) and all following checks are covered
> ++    //   Remove all other a[i+c] checks
> ++    //
> ++    // We only need the top 2 range checks if x is the min or max of all
> constants.
> ++    //
> ++    // This, however, only works if the interval [i+min,i+max] is not
> larger than max_int (i.e. abs(max - min) < max_int):
> ++    // The theoretical max size of an array is max_int with:
> ++    // - Valid index space: [0,max_int-1]
> ++    // - Invalid index space: [max_int,-1] // max_int, min_int, min_int
> - 1 ..., -1
> ++    //
> ++    // The size of the consecutive valid index space is smaller than the
> size of the consecutive invalid index space.
> ++    // If we choose min and max in such a way that:
> ++    // - abs(max - min) < max_int
> ++    // - i+max and i+min are inside the valid index space
> ++    // then all indices [i+min,i+max] must be in the valid index space.
> Otherwise, the invalid index space must be
> ++    // smaller than the valid index space which is never the case for
> any array size.
> ++    //
> ++    // Choosing a smaller array size only makes the valid index space
> smaller and the invalid index space larger and
> ++    // the argument above still holds.
> ++    //
> ++    // Note that the same optimization with the same maximal accepted
> interval size can also be found in C1.
> ++    const jlong maximum_number_of_min_max_interval_indices =
> (jlong)max_jint;
> +
> +     // The top 3 range checks seen
> +     const int NRC =3;
> +@@ -915,13 +955,18 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool
> can_reshape) {
> +             found_immediate_dominator = true;
> +             break;
> +           }
> +-          // Gather expanded bounds
> +-          off_lo = MIN2(off_lo,offset2);
> +-          off_hi = MAX2(off_hi,offset2);
> +-          // Record top NRC range checks
> +-          prev_checks[nb_checks%NRC].ctl = prev_dom;
> +-          prev_checks[nb_checks%NRC].off = offset2;
> +-          nb_checks++;
> ++
> ++          // "x - y" -> must add one to the difference for number of
> elements in [x,y]
> ++          const jlong diff = (jlong)MIN2(offset2, off_lo) -
> (jlong)MAX2(offset2, off_hi);
> ++          if (ABS(diff) < maximum_number_of_min_max_interval_indices) {
> ++            // Gather expanded bounds
> ++            off_lo = MIN2(off_lo, offset2);
> ++            off_hi = MAX2(off_hi, offset2);
> ++            // Record top NRC range checks
> ++            prev_checks[nb_checks % NRC].ctl = prev_dom;
> ++            prev_checks[nb_checks % NRC].off = offset2;
> ++            nb_checks++;
> ++          }
> +         }
> +       }
> +       prev_dom = dom;
> +diff --git a/hotspot/src/share/vm/opto/loopnode.cpp
> b/hotspot/src/share/vm/opto/loopnode.cpp
> +index b2d5dccd..8bc9dd29 100644
> +--- a/hotspot/src/share/vm/opto/loopnode.cpp
> ++++ b/hotspot/src/share/vm/opto/loopnode.cpp
> +@@ -260,6 +260,49 @@ void PhaseIdealLoop::set_subtree_ctrl( Node *n ) {
> +   set_early_ctrl( n );
> + }
> +
> ++void PhaseIdealLoop::insert_loop_limit_check(ProjNode* limit_check_proj,
> Node* cmp_limit, Node* bol) {
> ++  Node* new_predicate_proj =
> create_new_if_for_predicate(limit_check_proj, NULL,
> ++
>  Deoptimization::Reason_loop_limit_check);
> ++  Node* iff = new_predicate_proj->in(0);
> ++  assert(iff->Opcode() == Op_If, "bad graph shape");
> ++  Node* conv = iff->in(1);
> ++  assert(conv->Opcode() == Op_Conv2B, "bad graph shape");
> ++  Node* opaq = conv->in(1);
> ++  assert(opaq->Opcode() == Op_Opaque1, "bad graph shape");
> ++  cmp_limit = _igvn.register_new_node_with_optimizer(cmp_limit);
> ++  bol = _igvn.register_new_node_with_optimizer(bol);
> ++  set_subtree_ctrl(bol);
> ++  _igvn.replace_input_of(iff, 1, bol);
> ++
> ++#ifndef PRODUCT
> ++  // report that the loop predication has been actually performed
> ++  // for this loop
> ++  if (TraceLoopLimitCheck) {
> ++    tty->print_cr("Counted Loop Limit Check generated:");
> ++    debug_only( bol->dump(2); )
> ++  }
> ++#endif
> ++}
> ++
> ++static int check_stride_overflow(jlong final_correction, const TypeInt*
> limit_t) {
> ++  if (final_correction > 0) {
> ++    if (limit_t->_lo > (max_jint - final_correction)) {
> ++      return -1;
> ++    }
> ++    if (limit_t->_hi > (max_jint - final_correction)) {
> ++      return 1;
> ++    }
> ++  } else {
> ++    if (limit_t->_hi < (min_jint - final_correction)) {
> ++      return -1;
> ++    }
> ++    if (limit_t->_lo < (min_jint - final_correction)) {
> ++      return 1;
> ++    }
> ++  }
> ++  return 0;
> ++}
> ++
> +
> //------------------------------is_counted_loop--------------------------------
> + bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
> +   PhaseGVN *gvn = &_igvn;
> +@@ -463,51 +506,256 @@ bool PhaseIdealLoop::is_counted_loop( Node *x,
> IdealLoopTree *loop ) {
> +   assert(x->Opcode() == Op_Loop, "regular loops only");
> +   C->print_method(PHASE_BEFORE_CLOOPS, 3);
> +
> +-  Node *hook = new (C) Node(6);
> ++  Node* adjusted_limit = limit;
> +
> +   if (LoopLimitCheck) {
> +
> +   // ===================================================
> +-  // Generate loop limit check to avoid integer overflow
> +-  // in cases like next (cyclic loops):
> ++  // We can only convert this loop to a counted loop if we can guarantee
> that the iv phi will never overflow at runtime.
> ++  // This is an implicit assumption taken by some loop optimizations. We
> therefore must ensure this property at all cost.
> ++  // At this point, we've already excluded some trivial cases where an
> overflow could have been proven statically.
> ++  // But even though we cannot prove that an overflow will *not* happen,
> we still want to speculatively convert this loop
> ++  // to a counted loop. This can be achieved by adding additional iv phi
> overflow checks before the loop. If they fail,
> ++  // we trap and resume execution before the loop without having
> executed any iteration of the loop, yet.
> +   //
> +-  // for (i=0; i <= max_jint; i++) {}
> +-  // for (i=0; i <  max_jint; i+=2) {}
> ++  // These additional iv phi overflow checks can be inserted as Loop
> Limit Check Predicates above the Loop Limit Check
> ++  // Parse Predicate which captures a JVM state just before the entry of
> the loop. If there is no such Parse Predicate,
> ++  // we cannot generate a Loop Limit Check Predicate and thus cannot
> speculatively convert the loop to a counted loop.
> +   //
> ++  // In the following, we only focus on int loops with stride > 0 to
> keep things simple. The argumentation and proof
> ++  // for stride < 0 is analogously. For long loops, we would replace
> max_int with max_long.
> +   //
> +-  // Limit check predicate depends on the loop test:
> +   //
> +-  // for(;i != limit; i++)       --> limit <= (max_jint)
> +-  // for(;i <  limit; i+=stride) --> limit <= (max_jint - stride + 1)
> +-  // for(;i <= limit; i+=stride) --> limit <= (max_jint - stride    )
> ++  // The loop to be converted does not always need to have the often
> used shape:
> +   //
> ++  //                                                 i = init
> ++  //     i = init                                loop:
> ++  //     do {                                        ...
> ++  //         // ...               equivalent         i+=stride
> ++  //         i+=stride               <==>            if (i < limit)
> ++  //     } while (i < limit);                          goto loop
> ++  //                                             exit:
> ++  //                                                 ...
> ++  //
> ++  // where the loop exit check uses the post-incremented iv phi and a
> '<'-operator.
> ++  //
> ++  // We could also have '<='-operator (or '>='-operator for negative
> strides) or use the pre-incremented iv phi value
> ++  // in the loop exit check:
> ++  //
> ++  //         i = init
> ++  //     loop:
> ++  //         ...
> ++  //         if (i <= limit)
> ++  //             i+=stride
> ++  //             goto loop
> ++  //     exit:
> ++  //         ...
> ++  //
> ++  // Let's define the following terms:
> ++  // - iv_pre_i: The pre-incremented iv phi before the i-th iteration.
> ++  // - iv_post_i: The post-incremented iv phi after the i-th iteration.
> ++  //
> ++  // The iv_pre_i and iv_post_i have the following relation:
> ++  //      iv_pre_i + stride = iv_post_i
> ++  //
> ++  // When converting a loop to a counted loop, we want to have a
> canonicalized loop exit check of the form:
> ++  //     iv_post_i < adjusted_limit
> ++  //
> ++  // If that is not the case, we need to canonicalize the loop exit
> check by using different values for adjusted_limit:
> ++  // (LE1) iv_post_i < limit: Already canonicalized. We can directly use
> limit as adjusted_limit.
> ++  //           -> adjusted_limit = limit.
> ++  // (LE2) iv_post_i <= limit:
> ++  //           iv_post_i < limit + 1
> ++  //           -> adjusted limit = limit + 1
> ++  // (LE3) iv_pre_i < limit:
> ++  //           iv_pre_i + stride < limit + stride
> ++  //           iv_post_i < limit + stride
> ++  //           -> adjusted_limit = limit + stride
> ++  // (LE4) iv_pre_i <= limit:
> ++  //           iv_pre_i < limit + 1
> ++  //           iv_pre_i + stride < limit + stride + 1
> ++  //           iv_post_i < limit + stride + 1
> ++  //           -> adjusted_limit = limit + stride + 1
> ++  //
> ++  // Note that:
> ++  //     (AL) limit <= adjusted_limit.
> ++  //
> ++  // The following loop invariant has to hold for counted loops with n
> iterations (i.e. loop exit check true after n-th
> ++  // loop iteration) and a canonicalized loop exit check to guarantee
> that no iv_post_i over- or underflows:
> ++  // (INV) For i = 1..n, min_int <= iv_post_i <= max_int
> ++  //
> ++  // To prove (INV), we require the following two conditions/assumptions:
> ++  // (i): adjusted_limit - 1 + stride <= max_int
> ++  // (ii): init < limit
> ++  //
> ++  // If we can prove (INV), we know that there can be no over- or
> underflow of any iv phi value. We prove (INV) by
> ++  // induction by assuming (i) and (ii).
> ++  //
> ++  // Proof by Induction
> ++  // ------------------
> ++  // > Base case (i = 1): We show that (INV) holds after the first
> iteration:
> ++  //     min_int <= iv_post_1 = init + stride <= max_int
> ++  // Proof:
> ++  //     First, we note that (ii) implies
> ++  //         (iii) init <= limit - 1
> ++  //     max_int >= adjusted_limit - 1 + stride   [using (i)]
> ++  //             >= limit - 1 + stride            [using (AL)]
> ++  //             >= init + stride                 [using (iii)]
> ++  //             >= min_int                       [using stride > 0, no
> underflow]
> ++  // Thus, no overflow happens after the first iteration and (INV) holds
> for i = 1.
> ++  //
> ++  // Note that to prove the base case we need (i) and (ii).
> ++  //
> ++  // > Induction Hypothesis (i = j, j > 1): Assume that (INV) holds
> after the j-th iteration:
> ++  //     min_int <= iv_post_j <= max_int
> ++  // > Step case (i = j + 1): We show that (INV) also holds after the
> j+1-th iteration:
> ++  //     min_int <= iv_post_{j+1} = iv_post_j + stride <= max_int
> ++  // Proof:
> ++  // If iv_post_j >= adjusted_limit:
> ++  //     We exit the loop after the j-th iteration, and we don't execute
> the j+1-th iteration anymore. Thus, there is
> ++  //     also no iv_{j+1}. Since (INV) holds for iv_j, there is nothing
> left to prove.
> ++  // If iv_post_j < adjusted_limit:
> ++  //     First, we note that:
> ++  //         (iv) iv_post_j <= adjusted_limit - 1
> ++  //     max_int >= adjusted_limit - 1 + stride    [using (i)]
> ++  //             >= iv_post_j + stride             [using (iv)]
> ++  //             >= min_int                        [using stride > 0, no
> underflow]
> ++  //
> ++  // Note that to prove the step case we only need (i).
> ++  //
> ++  // Thus, by assuming (i) and (ii), we proved (INV).
> ++  //
> ++  //
> ++  // It is therefore enough to add the following two Loop Limit Check
> Predicates to check assumptions (i) and (ii):
> ++  //
> ++  // (1) Loop Limit Check Predicate for (i):
> ++  //     Using (i): adjusted_limit - 1 + stride <= max_int
> ++  //
> ++  //     This condition is now restated to use limit instead of
> adjusted_limit:
> ++  //
> ++  //     To prevent an overflow of adjusted_limit -1 + stride itself, we
> rewrite this check to
> ++  //         max_int - stride + 1 >= adjusted_limit
> ++  //     We can merge the two constants into
> ++  //         canonicalized_correction = stride - 1
> ++  //     which gives us
> ++  //        max_int - canonicalized_correction >= adjusted_limit
> ++  //
> ++  //     To directly use limit instead of adjusted_limit in the
> predicate condition, we split adjusted_limit into:
> ++  //         adjusted_limit = limit + limit_correction
> ++  //     Since stride > 0 and limit_correction <= stride + 1, we can
> restate this with no over- or underflow into:
> ++  //         max_int - canonicalized_correction - limit_correction >=
> limit
> ++  //     Since canonicalized_correction and limit_correction are both
> constants, we can replace them with a new constant:
> ++  //         final_correction = canonicalized_correction +
> limit_correction
> ++  //     which gives us:
> ++  //
> ++  //     Final predicate condition:
> ++  //         max_int - final_correction >= limit
> ++  //
> ++  // (2) Loop Limit Check Predicate for (ii):
> ++  //     Using (ii): init < limit
> ++  //
> ++  //     This Loop Limit Check Predicate is not required if we can prove
> at compile time that either:
> ++  //        (2.1) type(init) < type(limit)
> ++  //             In this case, we know:
> ++  //                 all possible values of init < all possible values
> of limit
> ++  //             and we can skip the predicate.
> ++  //
> ++  //        (2.2) init < limit is already checked before (i.e. found as
> a dominating check)
> ++  //            In this case, we do not need to re-check the condition
> and can skip the predicate.
> ++  //            This is often found for while- and for-loops which have
> the following shape:
> ++  //
> ++  //                if (init < limit) { // Dominating test. Do not need
> the Loop Limit Check Predicate below.
> ++  //                    i = init;
> ++  //                    if (init >= limit) { trap(); } // Here we would
> insert the Loop Limit Check Predicate
> ++  //                    do {
> ++  //                        i += stride;
> ++  //                    } while (i < limit);
> ++  //                }
> ++  //
> ++  //        (2.3) init + stride <= max_int
> ++  //            In this case, there is no overflow of the iv phi after
> the first loop iteration.
> ++  //            In the proof of the base case above we showed that init
> + stride <= max_int by using assumption (ii):
> ++  //                init < limit
> ++  //            In the proof of the step case above, we did not need
> (ii) anymore. Therefore, if we already know at
> ++  //            compile time that init + stride <= max_int then we have
> trivially proven the base case and that
> ++  //            there is no overflow of the iv phi after the first
> iteration. In this case, we don't need to check (ii)
> ++  //            again and can skip the predicate.
> ++
> ++
> ++  // Accounting for (LE3) and (LE4) where we use pre-incremented phis in
> the loop exit check.
> ++  const jlong limit_correction_for_pre_iv_exit_check = (phi_incr !=
> NULL) ? stride_con : 0;
> ++
> ++  // Accounting for (LE2) and (LE4) where we use <= or >= in the loop
> exit check.
> ++  const bool includes_limit = (bt == BoolTest::le || bt == BoolTest::ge);
> ++  const jlong limit_correction_for_le_ge_exit_check = (includes_limit ?
> (stride_con > 0 ? 1 : -1) : 0);
> ++
> ++  const jlong limit_correction = limit_correction_for_pre_iv_exit_check
> + limit_correction_for_le_ge_exit_check;
> ++  const jlong canonicalized_correction = stride_con + (stride_con > 0 ?
> -1 : 1);
> ++  const jlong final_correction = canonicalized_correction +
> limit_correction;
> ++
> ++  int sov = check_stride_overflow(final_correction, limit_t);
> ++
> ++  // If sov==0, limit's type always satisfies the condition, for
> ++  // example, when it is an array length.
> ++  if (sov != 0) {
> ++    if (sov < 0) {
> ++      return false;  // Bailout: integer overflow is certain.
> ++    }
> ++    // (1) Loop Limit Check Predicate is required because we could not
> statically prove that
> ++    //     limit + final_correction = adjusted_limit - 1 + stride <=
> max_int
> ++    ProjNode *limit_check_proj =
> find_predicate_insertion_point(init_control,
> Deoptimization::Reason_loop_limit_check);
> ++    if (!limit_check_proj) {
> ++      // The Loop Limit Check Parse Predicate is not generated if this
> method trapped here before.
> ++#ifdef ASSERT
> ++      if (TraceLoopLimitCheck) {
> ++        tty->print("missing loop limit check:");
> ++        loop->dump_head();
> ++        x->dump(1);
> ++      }
> ++#endif
> ++      return false;
> ++    }
> +
> +-  // Check if limit is excluded to do more precise int overflow check.
> +-  bool incl_limit = (bt == BoolTest::le || bt == BoolTest::ge);
> +-  int stride_m  = stride_con - (incl_limit ? 0 : (stride_con > 0 ? 1 :
> -1));
> +-
> +-  // If compare points directly to the phi we need to adjust
> +-  // the compare so that it points to the incr. Limit have
> +-  // to be adjusted to keep trip count the same and the
> +-  // adjusted limit should be checked for int overflow.
> +-  if (phi_incr != NULL) {
> +-    stride_m  += stride_con;
> +-  }
> ++    IfNode* check_iff = limit_check_proj->in(0)->as_If();
> +
> +-  if (limit->is_Con()) {
> +-    int limit_con = limit->get_int();
> +-    if ((stride_con > 0 && limit_con > (max_jint - stride_m)) ||
> +-        (stride_con < 0 && limit_con < (min_jint - stride_m))) {
> +-      // Bailout: it could be integer overflow.
> ++    if (!is_dominator(get_ctrl(limit), check_iff->in(0))) {
> +       return false;
> +     }
> +-  } else if ((stride_con > 0 && limit_t->_hi <= (max_jint - stride_m)) ||
> +-             (stride_con < 0 && limit_t->_lo >= (min_jint - stride_m))) {
> +-      // Limit's type may satisfy the condition, for example,
> +-      // when it is an array length.
> +-  } else {
> +-    // Generate loop's limit check.
> +-    // Loop limit check predicate should be near the loop.
> ++
> ++    Node* cmp_limit;
> ++    Node* bol;
> ++
> ++    if (stride_con > 0) {
> ++      cmp_limit = new (C) CmpINode(limit, _igvn.intcon(max_jint -
> final_correction));
> ++      bol = new (C) BoolNode(cmp_limit, BoolTest::le);
> ++    } else {
> ++      cmp_limit = new (C) CmpINode(limit, _igvn.intcon(min_jint -
> final_correction));
> ++      bol = new (C) BoolNode(cmp_limit, BoolTest::ge);
> ++    }
> ++
> ++    insert_loop_limit_check(limit_check_proj, cmp_limit, bol);
> ++  }
> ++
> ++  // (2.3)
> ++  const bool init_plus_stride_could_overflow =
> ++          (stride_con > 0 && init_t->_hi > max_jint - stride_con) ||
> ++          (stride_con < 0 && init_t->_lo < min_jint - stride_con);
> ++  // (2.1)
> ++  const bool init_gte_limit = (stride_con > 0 && init_t->_hi >=
> limit_t->_lo) ||
> ++                              (stride_con < 0 && init_t->_lo <=
> limit_t->_hi);
> ++
> ++  if (init_gte_limit && // (2.1)
> ++     ((bt == BoolTest::ne || init_plus_stride_could_overflow) && // (2.3)
> ++      !has_dominating_loop_limit_check(init_trip, limit, stride_con,
> init_control))) { // (2.2)
> ++    // (2) Iteration Loop Limit Check Predicate is required because
> neither (2.1), (2.2), nor (2.3) holds.
> ++    // We use the following condition:
> ++    // - stride > 0: init < limit
> ++    // - stride < 0: init > limit
> ++    //
> ++    // This predicate is always required if we have a non-equal-operator
> in the loop exit check (where stride = 1 is
> ++    // a requirement). We transform the loop exit check by using a
> less-than-operator. By doing so, we must always
> ++    // check that init < limit. Otherwise, we could have a different
> number of iterations at runtime.
> ++
> +     ProjNode *limit_check_proj =
> find_predicate_insertion_point(init_control,
> Deoptimization::Reason_loop_limit_check);
> +     if (!limit_check_proj) {
> +       // The limit check predicate is not generated if this method
> trapped here before.
> +@@ -520,41 +768,38 @@ bool PhaseIdealLoop::is_counted_loop( Node *x,
> IdealLoopTree *loop ) {
> + #endif
> +       return false;
> +     }
> +-
> +     IfNode* check_iff = limit_check_proj->in(0)->as_If();
> ++
> ++    if (!is_dominator(get_ctrl(limit), check_iff->in(0)) ||
> ++        !is_dominator(get_ctrl(init_trip), check_iff->in(0))) {
> ++      return false;
> ++    }
> ++
> +     Node* cmp_limit;
> +     Node* bol;
> +
> +     if (stride_con > 0) {
> +-      cmp_limit = new (C) CmpINode(limit, _igvn.intcon(max_jint -
> stride_m));
> +-      bol = new (C) BoolNode(cmp_limit, BoolTest::le);
> ++      cmp_limit = new (C) CmpINode(init_trip, limit);
> ++      bol = new (C) BoolNode(cmp_limit, BoolTest::lt);
> +     } else {
> +-      cmp_limit = new (C) CmpINode(limit, _igvn.intcon(min_jint -
> stride_m));
> +-      bol = new (C) BoolNode(cmp_limit, BoolTest::ge);
> ++      cmp_limit = new (C) CmpINode(init_trip, limit);
> ++      bol = new (C) BoolNode(cmp_limit, BoolTest::gt);
> +     }
> +-    cmp_limit = _igvn.register_new_node_with_optimizer(cmp_limit);
> +-    bol = _igvn.register_new_node_with_optimizer(bol);
> +-    set_subtree_ctrl(bol);
> +-
> +-    // Replace condition in original predicate but preserve Opaque node
> +-    // so that previous predicates could be found.
> +-    assert(check_iff->in(1)->Opcode() == Op_Conv2B &&
> +-           check_iff->in(1)->in(1)->Opcode() == Op_Opaque1, "");
> +-    Node* opq = check_iff->in(1)->in(1);
> +-    _igvn.hash_delete(opq);
> +-    opq->set_req(1, bol);
> +-    // Update ctrl.
> +-    set_ctrl(opq, check_iff->in(0));
> +-    set_ctrl(check_iff->in(1), check_iff->in(0));
> +
> +-#ifndef PRODUCT
> +-    // report that the loop predication has been actually performed
> +-    // for this loop
> +-    if (TraceLoopLimitCheck) {
> +-      tty->print_cr("Counted Loop Limit Check generated:");
> +-      debug_only( bol->dump(2); )
> ++    insert_loop_limit_check(limit_check_proj, cmp_limit, bol);
> ++  }
> ++
> ++  if (bt == BoolTest::ne) {
> ++    // Now we need to canonicalize the loop condition if it is 'ne'.
> ++    assert(stride_con == 1 || stride_con == -1, "simple increment only -
> checked before");
> ++    if (stride_con > 0) {
> ++      // 'ne' can be replaced with 'lt' only when init < limit. This is
> ensured by the inserted predicate above.
> ++      bt = BoolTest::lt;
> ++    } else {
> ++      assert(stride_con < 0, "must be");
> ++      // 'ne' can be replaced with 'gt' only when init > limit. This is
> ensured by the inserted predicate above.
> ++      bt = BoolTest::gt;
> +     }
> +-#endif
> +   }
> +
> +   if (phi_incr != NULL) {
> +@@ -567,26 +812,15 @@ bool PhaseIdealLoop::is_counted_loop( Node *x,
> IdealLoopTree *loop ) {
> +     // is converted to
> +     //   i = init; do {} while(++i < limit+1);
> +     //
> +-    limit = gvn->transform(new (C) AddINode(limit, stride));
> +-  }
> +-
> +-  // Now we need to canonicalize loop condition.
> +-  if (bt == BoolTest::ne) {
> +-    assert(stride_con == 1 || stride_con == -1, "simple increment only");
> +-    // 'ne' can be replaced with 'lt' only when init < limit.
> +-    if (stride_con > 0 && init_t->_hi < limit_t->_lo)
> +-      bt = BoolTest::lt;
> +-    // 'ne' can be replaced with 'gt' only when init > limit.
> +-    if (stride_con < 0 && init_t->_lo > limit_t->_hi)
> +-      bt = BoolTest::gt;
> ++    adjusted_limit = gvn->transform(new (C) AddINode(limit, stride));
> +   }
> +
> +-  if (incl_limit) {
> ++  if (includes_limit) {
> +     // The limit check guaranties that 'limit <= (max_jint - stride)' so
> +     // we can convert 'i <= limit' to 'i < limit+1' since stride != 0.
> +     //
> +     Node* one = (stride_con > 0) ? gvn->intcon( 1) : gvn->intcon(-1);
> +-    limit = gvn->transform(new (C) AddINode(limit, one));
> ++    adjusted_limit = gvn->transform(new (C) AddINode(adjusted_limit,
> one));
> +     if (bt == BoolTest::le)
> +       bt = BoolTest::lt;
> +     else if (bt == BoolTest::ge)
> +@@ -594,10 +828,11 @@ bool PhaseIdealLoop::is_counted_loop( Node *x,
> IdealLoopTree *loop ) {
> +     else
> +       ShouldNotReachHere();
> +   }
> +-  set_subtree_ctrl( limit );
> ++  set_subtree_ctrl(adjusted_limit);
> +
> +   } else { // LoopLimitCheck
> +
> ++  Node *hook = new (C) Node(6);
> +   // If compare points to incr, we are ok.  Otherwise the compare
> +   // can directly point to the phi; in this case adjust the compare so
> that
> +   // it points to the incr by adjusting the limit.
> +@@ -691,6 +926,11 @@ bool PhaseIdealLoop::is_counted_loop( Node *x,
> IdealLoopTree *loop ) {
> +   limit = gvn->transform(new (C) AddINode(span,init_trip));
> +   set_subtree_ctrl( limit );
> +
> ++  adjusted_limit = limit;
> ++
> ++  // Free up intermediate goo
> ++  _igvn.remove_dead_node(hook);
> ++
> +   } // LoopLimitCheck
> +
> +   if (!UseCountedLoopSafepoints) {
> +@@ -728,7 +968,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x,
> IdealLoopTree *loop ) {
> +   }
> +   cmp = cmp->clone();
> +   cmp->set_req(1,incr);
> +-  cmp->set_req(2,limit);
> ++  cmp->set_req(2, adjusted_limit);
> +   cmp = _igvn.register_new_node_with_optimizer(cmp);
> +   set_ctrl(cmp, iff->in(0));
> +
> +@@ -802,9 +1042,6 @@ bool PhaseIdealLoop::is_counted_loop( Node *x,
> IdealLoopTree *loop ) {
> +     }
> +   }
> +
> +-  // Free up intermediate goo
> +-  _igvn.remove_dead_node(hook);
> +-
> + #ifdef ASSERT
> +   assert(l->is_valid_counted_loop(), "counted loop shape is messed up");
> +   assert(l == loop->_head && l->phi() == phi && l->loopexit() == lex, ""
> );
> +@@ -821,6 +1058,37 @@ bool PhaseIdealLoop::is_counted_loop( Node *x,
> IdealLoopTree *loop ) {
> +   return true;
> + }
> +
> ++// Check if there is a dominating loop limit check of the form 'init <
> limit' starting at the loop entry.
> ++// If there is one, then we do not need to create an additional Loop
> Limit Check Predicate.
> ++bool PhaseIdealLoop::has_dominating_loop_limit_check(Node* init_trip,
> Node* limit, const int stride_con,
> ++                                                     Node* loop_entry) {
> ++  // Eagerly call transform() on the Cmp and Bool node to common them up
> if possible. This is required in order to
> ++  // successfully find a dominated test with the If node below.
> ++  Node* cmp_limit;
> ++  Node* bol;
> ++  if (stride_con > 0) {
> ++    cmp_limit = _igvn.transform(new (C) CmpINode(init_trip, limit));
> ++    bol = _igvn.transform(new (C) BoolNode(cmp_limit, BoolTest::lt));
> ++  } else {
> ++    cmp_limit = _igvn.transform(new (C) CmpINode(init_trip, limit));
> ++    bol = _igvn.transform(new (C) BoolNode(cmp_limit, BoolTest::gt));
> ++  }
> ++
> ++  // Check if there is already a dominating init < limit check. If so,
> we do not need a Loop Limit Check Predicate.
> ++  IfNode* iff = new (C) IfNode(loop_entry, bol, PROB_MIN, COUNT_UNKNOWN);
> ++  // Also add fake IfProj nodes in order to call transform() on the
> newly created IfNode.
> ++  IfFalseNode* if_false = new (C) IfFalseNode(iff);
> ++  IfTrueNode* if_true = new (C) IfTrueNode(iff);
> ++  Node* dominated_iff = _igvn.transform(iff);
> ++  // ConI node? Found dominating test (IfNode::dominated_by() returns a
> ConI node).
> ++  const bool found_dominating_test = dominated_iff != NULL &&
> dominated_iff->Opcode() == Op_ConI;
> ++
> ++  // Kill the If with its projections again in the next IGVN round by
> cutting it off from the graph.
> ++  _igvn.replace_input_of(iff, 0, C->top());
> ++  _igvn.replace_input_of(iff, 1, C->top());
> ++  return found_dominating_test;
> ++}
> ++
> +
> //----------------------exact_limit-------------------------------------------
> + Node* PhaseIdealLoop::exact_limit( IdealLoopTree *loop ) {
> +   assert(loop->_head->is_CountedLoop(), "");
> +diff --git a/hotspot/src/share/vm/opto/loopnode.hpp
> b/hotspot/src/share/vm/opto/loopnode.hpp
> +index 55a7def3..3ae41f8d 100644
> +--- a/hotspot/src/share/vm/opto/loopnode.hpp
> ++++ b/hotspot/src/share/vm/opto/loopnode.hpp
> +@@ -896,6 +896,10 @@ public:
> +   // Create a new if above the uncommon_trap_if_pattern for the
> predicate to be promoted
> +   ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node*
> new_entry,
> +                                         Deoptimization::DeoptReason
> reason);
> ++  void insert_loop_limit_check(ProjNode* limit_check_proj, Node*
> cmp_limit, Node* bol);
> ++  bool has_dominating_loop_limit_check(Node* init_trip, Node* limit, int
> stride_con,
> ++                                       Node* loop_entry);
> ++
> +   void register_control(Node* n, IdealLoopTree *loop, Node* pred);
> +
> +   // Clone loop predicates to cloned loops (peeled, unswitched)
> +diff --git a/hotspot/src/share/vm/opto/phaseX.hpp
> b/hotspot/src/share/vm/opto/phaseX.hpp
> +index a2a2a538..bd7393ac 100644
> +--- a/hotspot/src/share/vm/opto/phaseX.hpp
> ++++ b/hotspot/src/share/vm/opto/phaseX.hpp
> +@@ -431,9 +431,6 @@ private:
> +
> + protected:
> +
> +-  // Idealize new Node 'n' with respect to its inputs and its value
> +-  virtual Node *transform( Node *a_node );
> +-
> +   // Warm up hash table, type table and initial worklist
> +   void init_worklist( Node *a_root );
> +
> +@@ -447,6 +444,9 @@ public:
> +   PhaseIterGVN( PhaseGVN *gvn ); // Used after Parser
> +   PhaseIterGVN( PhaseIterGVN *igvn, const char *dummy ); // Used after
> +VerifyOpto
> +
> ++  // Idealize new Node 'n' with respect to its inputs and its value
> ++  virtual Node *transform( Node *a_node );
> ++
> +   virtual PhaseIterGVN *is_IterGVN() { return this; }
> +
> +   Unique_Node_List _worklist;       // Iterative worklist
> +--
> +2.25.1
> +
> --
> 2.25.1
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#111138):
> https://lists.openembedded.org/g/openembedded-devel/message/111138
> Mute This Topic: https://lists.openembedded.org/mt/106923033/924729
> Group Owner: openembedded-devel+owner@lists.openembedded.org
> Unsubscribe: https://lists.openembedded.org/g/openembedded-devel/unsub [
> ticotimo@gmail.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
>
diff mbox series

Patch

diff --git a/recipes-core/openjdk/openjdk-8-release-common.inc b/recipes-core/openjdk/openjdk-8-release-common.inc
index c977c96..985d0d7 100644
--- a/recipes-core/openjdk/openjdk-8-release-common.inc
+++ b/recipes-core/openjdk/openjdk-8-release-common.inc
@@ -22,6 +22,8 @@  PATCHES_URI = "\
     file://2008-jdk-no-unused-deps.patch \
     file://2009-jdk-make-use-gcc-instead-of-ld-for-genSocketOptionRe.patch \
     file://CVE-2022-40433.patch \
+    file://CVE-2024-20919.patch \
+    file://CVE-2024-20921.patch \
 "
 HOTSPOT_UB_PATCH = "\
     file://1001-hotspot-fix-crash-on-JNI_CreateJavaVM.patch \
diff --git a/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20919.patch b/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20919.patch
new file mode 100644
index 0000000..566e01c
--- /dev/null
+++ b/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20919.patch
@@ -0,0 +1,126 @@ 
+From 77d38b78e4993381ddb113d012b30ab2d7cd9215 Mon Sep 17 00:00:00 2001
+From: Martin Balao <mbalao@openjdk.org>
+Date: Fri, 29 Sep 2023 13:01:13 +0000
+Subject: [PATCH] 8314295: Enhance verification of verifier
+
+Reviewed-by: yan, andrew
+Backport-of: 08980a0a60bc48c17eacd57fd2d7065ac2d986a8
+
+Upstream-Status: Backport [https://github.com/openjdk/jdk8u/commit/77d38b78e4993381ddb113d012b30ab2d7cd9215]
+CVE: CVE-2024-20919
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ hotspot/src/share/vm/classfile/verifier.cpp   |  5 +++--
+ .../src/share/vm/interpreter/bytecodes.cpp    | 22 ++++++++++++++-----
+ jdk/src/share/native/common/check_code.c      | 11 ++++++----
+ 3 files changed, 26 insertions(+), 12 deletions(-)
+
+diff --git a/hotspot/src/share/vm/classfile/verifier.cpp b/hotspot/src/share/vm/classfile/verifier.cpp
+index 2a572058..3a3e04ba 100644
+--- a/hotspot/src/share/vm/classfile/verifier.cpp
++++ b/hotspot/src/share/vm/classfile/verifier.cpp
+@@ -2078,11 +2078,12 @@ void ClassVerifier::verify_switch(
+           "low must be less than or equal to high in tableswitch");
+       return;
+     }
+-    keys = high - low + 1;
+-    if (keys < 0) {
++    int64_t keys64 = ((int64_t)high - low) + 1;
++    if (keys64 > 65535) {  // Max code length
+       verify_error(ErrorContext::bad_code(bci), "too many keys in tableswitch");
+       return;
+     }
++    keys = (int)keys64;
+     delta = 1;
+   } else {
+     keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize);
+diff --git a/hotspot/src/share/vm/interpreter/bytecodes.cpp b/hotspot/src/share/vm/interpreter/bytecodes.cpp
+index 24adc4d9..f0753735 100644
+--- a/hotspot/src/share/vm/interpreter/bytecodes.cpp
++++ b/hotspot/src/share/vm/interpreter/bytecodes.cpp
+@@ -111,12 +111,18 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end)
+       if (end != NULL && aligned_bcp + 3*jintSize >= end) {
+         return -1; // don't read past end of code buffer
+       }
++      // Promote calculation to signed 64 bits to do range checks, used by the verifier.
+       jlong lo = (jint)Bytes::get_Java_u4(aligned_bcp + 1*jintSize);
+       jlong hi = (jint)Bytes::get_Java_u4(aligned_bcp + 2*jintSize);
+       jlong len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize;
+-      // only return len if it can be represented as a positive int;
+-      // return -1 otherwise
+-      return (len > 0 && len == (int)len) ? len : -1;
++      // Only return len if it can be represented as a positive int and lo <= hi.
++      // The caller checks for bytecode stream overflow.
++      if (lo <= hi && len == (int)len) {
++        assert(len > 0, "must be");
++        return (int)len;
++      } else {
++        return -1;
++      }
+     }
+ 
+   case _lookupswitch:      // fall through
+@@ -128,9 +134,13 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end)
+       }
+       jlong npairs = (jint)Bytes::get_Java_u4(aligned_bcp + jintSize);
+       jlong len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize;
+-      // only return len if it can be represented as a positive int;
+-      // return -1 otherwise
+-      return (len > 0 && len == (int)len) ? len : -1;
++      // Only return len if it can be represented as a positive int and npairs >= 0.
++      if (npairs >= 0 && len == (int)len) {
++        assert(len > 0, "must be");
++        return (int)len;
++      } else {
++        return -1;
++      }
+     }
+   }
+   // Note: Length functions must return <=0 for invalid bytecodes.
+diff --git a/jdk/src/share/native/common/check_code.c b/jdk/src/share/native/common/check_code.c
+index 96091720..491b95cd 100644
+--- a/jdk/src/share/native/common/check_code.c
++++ b/jdk/src/share/native/common/check_code.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 1994, 2014, Oracle and/or its affiliates. All rights reserved.
++ * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  *
+  * This code is free software; you can redistribute it and/or modify it
+@@ -84,6 +84,7 @@
+ #include <assert.h>
+ #include <limits.h>
+ #include <stdlib.h>
++#include <stdint.h>
+ 
+ #include "jni.h"
+ #include "jvm.h"
+@@ -1202,7 +1203,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset)
+             }
+         }
+         if (opcode == JVM_OPC_tableswitch) {
+-            keys = _ck_ntohl(lpc[2]) -  _ck_ntohl(lpc[1]) + 1;
++            keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1;
+             delta = 1;
+         } else {
+             keys = _ck_ntohl(lpc[1]); /* number of pairs */
+@@ -1682,11 +1683,13 @@ static int instruction_length(unsigned char *iptr, unsigned char *end)
+     switch (instruction) {
+         case JVM_OPC_tableswitch: {
+             int *lpc = (int *)UCALIGN(iptr + 1);
+-            int index;
+             if (lpc + 2 >= (int *)end) {
+                 return -1; /* do not read pass the end */
+             }
+-            index = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]);
++            int64_t low  = _ck_ntohl(lpc[1]);
++            int64_t high = _ck_ntohl(lpc[2]);
++            int64_t index = high - low;
++            // The value of low must be less than or equal to high - i.e. index >= 0
+             if ((index < 0) || (index > 65535)) {
+                 return -1;      /* illegal */
+             } else {
+-- 
+2.25.1
+
diff --git a/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20921.patch b/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20921.patch
new file mode 100644
index 0000000..edce6f0
--- /dev/null
+++ b/recipes-core/openjdk/patches-openjdk-8/CVE-2024-20921.patch
@@ -0,0 +1,657 @@ 
+From f7cb28de01117f598ecf48ad58e277c3a4590436 Mon Sep 17 00:00:00 2001
+From: Roland Westrelin <rwestrel@redhat.com>
+Date: Tue, 7 Nov 2023 11:08:30 +0000
+Subject: [PATCH] 8314307: Improve loop handling
+
+Reviewed-by: mbalao, fferrari, andrew
+Backport-of: 62ac93d145ca9fa1ab0c040533c62c42c202703a
+
+Upstream-Status: Backport [https://github.com/openjdk/jdk8u/commit/f7cb28de01117f598ecf48ad58e277c3a4590436]
+CVE: CVE-2024-20921
+Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
+---
+ hotspot/src/share/vm/opto/ifnode.cpp   |  59 +++-
+ hotspot/src/share/vm/opto/loopnode.cpp | 422 ++++++++++++++++++++-----
+ hotspot/src/share/vm/opto/loopnode.hpp |   4 +
+ hotspot/src/share/vm/opto/phaseX.hpp   |   6 +-
+ 4 files changed, 404 insertions(+), 87 deletions(-)
+
+diff --git a/hotspot/src/share/vm/opto/ifnode.cpp b/hotspot/src/share/vm/opto/ifnode.cpp
+index 68f068d0..51579032 100644
+--- a/hotspot/src/share/vm/opto/ifnode.cpp
++++ b/hotspot/src/share/vm/opto/ifnode.cpp
+@@ -882,6 +882,46 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+     // then we are guaranteed to fail, so just start interpreting there.
+     // We 'expand' the top 3 range checks to include all post-dominating
+     // checks.
++    //
++    // Example:
++    // a[i+x] // (1) 1 < x < 6
++    // a[i+3] // (2)
++    // a[i+4] // (3)
++    // a[i+6] // max = max of all constants
++    // a[i+2]
++    // a[i+1] // min = min of all constants
++    //
++    // If x < 3:
++    //   (1) a[i+x]: Leave unchanged
++    //   (2) a[i+3]: Replace with a[i+max] = a[i+6]: i+x < i+3 <= i+6  -> (2) is covered
++    //   (3) a[i+4]: Replace with a[i+min] = a[i+1]: i+1 < i+4 <= i+6  -> (3) and all following checks are covered
++    //   Remove all other a[i+c] checks
++    //
++    // If x >= 3:
++    //   (1) a[i+x]: Leave unchanged
++    //   (2) a[i+3]: Replace with a[i+min] = a[i+1]: i+1 < i+3 <= i+x  -> (2) is covered
++    //   (3) a[i+4]: Replace with a[i+max] = a[i+6]: i+1 < i+4 <= i+6  -> (3) and all following checks are covered
++    //   Remove all other a[i+c] checks
++    //
++    // We only need the top 2 range checks if x is the min or max of all constants.
++    //
++    // This, however, only works if the interval [i+min,i+max] is not larger than max_int (i.e. abs(max - min) < max_int):
++    // The theoretical max size of an array is max_int with:
++    // - Valid index space: [0,max_int-1]
++    // - Invalid index space: [max_int,-1] // max_int, min_int, min_int - 1 ..., -1
++    //
++    // The size of the consecutive valid index space is smaller than the size of the consecutive invalid index space.
++    // If we choose min and max in such a way that:
++    // - abs(max - min) < max_int
++    // - i+max and i+min are inside the valid index space
++    // then all indices [i+min,i+max] must be in the valid index space. Otherwise, the invalid index space must be
++    // smaller than the valid index space which is never the case for any array size.
++    //
++    // Choosing a smaller array size only makes the valid index space smaller and the invalid index space larger and
++    // the argument above still holds.
++    //
++    // Note that the same optimization with the same maximal accepted interval size can also be found in C1.
++    const jlong maximum_number_of_min_max_interval_indices = (jlong)max_jint;
+ 
+     // The top 3 range checks seen
+     const int NRC =3;
+@@ -915,13 +955,18 @@ Node *IfNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+             found_immediate_dominator = true;
+             break;
+           }
+-          // Gather expanded bounds
+-          off_lo = MIN2(off_lo,offset2);
+-          off_hi = MAX2(off_hi,offset2);
+-          // Record top NRC range checks
+-          prev_checks[nb_checks%NRC].ctl = prev_dom;
+-          prev_checks[nb_checks%NRC].off = offset2;
+-          nb_checks++;
++
++          // "x - y" -> must add one to the difference for number of elements in [x,y]
++          const jlong diff = (jlong)MIN2(offset2, off_lo) - (jlong)MAX2(offset2, off_hi);
++          if (ABS(diff) < maximum_number_of_min_max_interval_indices) {
++            // Gather expanded bounds
++            off_lo = MIN2(off_lo, offset2);
++            off_hi = MAX2(off_hi, offset2);
++            // Record top NRC range checks
++            prev_checks[nb_checks % NRC].ctl = prev_dom;
++            prev_checks[nb_checks % NRC].off = offset2;
++            nb_checks++;
++          }
+         }
+       }
+       prev_dom = dom;
+diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp
+index b2d5dccd..8bc9dd29 100644
+--- a/hotspot/src/share/vm/opto/loopnode.cpp
++++ b/hotspot/src/share/vm/opto/loopnode.cpp
+@@ -260,6 +260,49 @@ void PhaseIdealLoop::set_subtree_ctrl( Node *n ) {
+   set_early_ctrl( n );
+ }
+ 
++void PhaseIdealLoop::insert_loop_limit_check(ProjNode* limit_check_proj, Node* cmp_limit, Node* bol) {
++  Node* new_predicate_proj = create_new_if_for_predicate(limit_check_proj, NULL,
++                                                         Deoptimization::Reason_loop_limit_check);
++  Node* iff = new_predicate_proj->in(0);
++  assert(iff->Opcode() == Op_If, "bad graph shape");
++  Node* conv = iff->in(1);
++  assert(conv->Opcode() == Op_Conv2B, "bad graph shape");
++  Node* opaq = conv->in(1);
++  assert(opaq->Opcode() == Op_Opaque1, "bad graph shape");
++  cmp_limit = _igvn.register_new_node_with_optimizer(cmp_limit);
++  bol = _igvn.register_new_node_with_optimizer(bol);
++  set_subtree_ctrl(bol);
++  _igvn.replace_input_of(iff, 1, bol);
++
++#ifndef PRODUCT
++  // report that the loop predication has been actually performed
++  // for this loop
++  if (TraceLoopLimitCheck) {
++    tty->print_cr("Counted Loop Limit Check generated:");
++    debug_only( bol->dump(2); )
++  }
++#endif
++}
++
++static int check_stride_overflow(jlong final_correction, const TypeInt* limit_t) {
++  if (final_correction > 0) {
++    if (limit_t->_lo > (max_jint - final_correction)) {
++      return -1;
++    }
++    if (limit_t->_hi > (max_jint - final_correction)) {
++      return 1;
++    }
++  } else {
++    if (limit_t->_hi < (min_jint - final_correction)) {
++      return -1;
++    }
++    if (limit_t->_lo < (min_jint - final_correction)) {
++      return 1;
++    }
++  }
++  return 0;
++}
++
+ //------------------------------is_counted_loop--------------------------------
+ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+   PhaseGVN *gvn = &_igvn;
+@@ -463,51 +506,256 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+   assert(x->Opcode() == Op_Loop, "regular loops only");
+   C->print_method(PHASE_BEFORE_CLOOPS, 3);
+ 
+-  Node *hook = new (C) Node(6);
++  Node* adjusted_limit = limit;
+ 
+   if (LoopLimitCheck) {
+ 
+   // ===================================================
+-  // Generate loop limit check to avoid integer overflow
+-  // in cases like next (cyclic loops):
++  // We can only convert this loop to a counted loop if we can guarantee that the iv phi will never overflow at runtime.
++  // This is an implicit assumption taken by some loop optimizations. We therefore must ensure this property at all cost.
++  // At this point, we've already excluded some trivial cases where an overflow could have been proven statically.
++  // But even though we cannot prove that an overflow will *not* happen, we still want to speculatively convert this loop
++  // to a counted loop. This can be achieved by adding additional iv phi overflow checks before the loop. If they fail,
++  // we trap and resume execution before the loop without having executed any iteration of the loop, yet.
+   //
+-  // for (i=0; i <= max_jint; i++) {}
+-  // for (i=0; i <  max_jint; i+=2) {}
++  // These additional iv phi overflow checks can be inserted as Loop Limit Check Predicates above the Loop Limit Check
++  // Parse Predicate which captures a JVM state just before the entry of the loop. If there is no such Parse Predicate,
++  // we cannot generate a Loop Limit Check Predicate and thus cannot speculatively convert the loop to a counted loop.
+   //
++  // In the following, we only focus on int loops with stride > 0 to keep things simple. The argumentation and proof
++  // for stride < 0 is analogously. For long loops, we would replace max_int with max_long.
+   //
+-  // Limit check predicate depends on the loop test:
+   //
+-  // for(;i != limit; i++)       --> limit <= (max_jint)
+-  // for(;i <  limit; i+=stride) --> limit <= (max_jint - stride + 1)
+-  // for(;i <= limit; i+=stride) --> limit <= (max_jint - stride    )
++  // The loop to be converted does not always need to have the often used shape:
+   //
++  //                                                 i = init
++  //     i = init                                loop:
++  //     do {                                        ...
++  //         // ...               equivalent         i+=stride
++  //         i+=stride               <==>            if (i < limit)
++  //     } while (i < limit);                          goto loop
++  //                                             exit:
++  //                                                 ...
++  //
++  // where the loop exit check uses the post-incremented iv phi and a '<'-operator.
++  //
++  // We could also have '<='-operator (or '>='-operator for negative strides) or use the pre-incremented iv phi value
++  // in the loop exit check:
++  //
++  //         i = init
++  //     loop:
++  //         ...
++  //         if (i <= limit)
++  //             i+=stride
++  //             goto loop
++  //     exit:
++  //         ...
++  //
++  // Let's define the following terms:
++  // - iv_pre_i: The pre-incremented iv phi before the i-th iteration.
++  // - iv_post_i: The post-incremented iv phi after the i-th iteration.
++  //
++  // The iv_pre_i and iv_post_i have the following relation:
++  //      iv_pre_i + stride = iv_post_i
++  //
++  // When converting a loop to a counted loop, we want to have a canonicalized loop exit check of the form:
++  //     iv_post_i < adjusted_limit
++  //
++  // If that is not the case, we need to canonicalize the loop exit check by using different values for adjusted_limit:
++  // (LE1) iv_post_i < limit: Already canonicalized. We can directly use limit as adjusted_limit.
++  //           -> adjusted_limit = limit.
++  // (LE2) iv_post_i <= limit:
++  //           iv_post_i < limit + 1
++  //           -> adjusted limit = limit + 1
++  // (LE3) iv_pre_i < limit:
++  //           iv_pre_i + stride < limit + stride
++  //           iv_post_i < limit + stride
++  //           -> adjusted_limit = limit + stride
++  // (LE4) iv_pre_i <= limit:
++  //           iv_pre_i < limit + 1
++  //           iv_pre_i + stride < limit + stride + 1
++  //           iv_post_i < limit + stride + 1
++  //           -> adjusted_limit = limit + stride + 1
++  //
++  // Note that:
++  //     (AL) limit <= adjusted_limit.
++  //
++  // The following loop invariant has to hold for counted loops with n iterations (i.e. loop exit check true after n-th
++  // loop iteration) and a canonicalized loop exit check to guarantee that no iv_post_i over- or underflows:
++  // (INV) For i = 1..n, min_int <= iv_post_i <= max_int
++  //
++  // To prove (INV), we require the following two conditions/assumptions:
++  // (i): adjusted_limit - 1 + stride <= max_int
++  // (ii): init < limit
++  //
++  // If we can prove (INV), we know that there can be no over- or underflow of any iv phi value. We prove (INV) by
++  // induction by assuming (i) and (ii).
++  //
++  // Proof by Induction
++  // ------------------
++  // > Base case (i = 1): We show that (INV) holds after the first iteration:
++  //     min_int <= iv_post_1 = init + stride <= max_int
++  // Proof:
++  //     First, we note that (ii) implies
++  //         (iii) init <= limit - 1
++  //     max_int >= adjusted_limit - 1 + stride   [using (i)]
++  //             >= limit - 1 + stride            [using (AL)]
++  //             >= init + stride                 [using (iii)]
++  //             >= min_int                       [using stride > 0, no underflow]
++  // Thus, no overflow happens after the first iteration and (INV) holds for i = 1.
++  //
++  // Note that to prove the base case we need (i) and (ii).
++  //
++  // > Induction Hypothesis (i = j, j > 1): Assume that (INV) holds after the j-th iteration:
++  //     min_int <= iv_post_j <= max_int
++  // > Step case (i = j + 1): We show that (INV) also holds after the j+1-th iteration:
++  //     min_int <= iv_post_{j+1} = iv_post_j + stride <= max_int
++  // Proof:
++  // If iv_post_j >= adjusted_limit:
++  //     We exit the loop after the j-th iteration, and we don't execute the j+1-th iteration anymore. Thus, there is
++  //     also no iv_{j+1}. Since (INV) holds for iv_j, there is nothing left to prove.
++  // If iv_post_j < adjusted_limit:
++  //     First, we note that:
++  //         (iv) iv_post_j <= adjusted_limit - 1
++  //     max_int >= adjusted_limit - 1 + stride    [using (i)]
++  //             >= iv_post_j + stride             [using (iv)]
++  //             >= min_int                        [using stride > 0, no underflow]
++  //
++  // Note that to prove the step case we only need (i).
++  //
++  // Thus, by assuming (i) and (ii), we proved (INV).
++  //
++  //
++  // It is therefore enough to add the following two Loop Limit Check Predicates to check assumptions (i) and (ii):
++  //
++  // (1) Loop Limit Check Predicate for (i):
++  //     Using (i): adjusted_limit - 1 + stride <= max_int
++  //
++  //     This condition is now restated to use limit instead of adjusted_limit:
++  //
++  //     To prevent an overflow of adjusted_limit -1 + stride itself, we rewrite this check to
++  //         max_int - stride + 1 >= adjusted_limit
++  //     We can merge the two constants into
++  //         canonicalized_correction = stride - 1
++  //     which gives us
++  //        max_int - canonicalized_correction >= adjusted_limit
++  //
++  //     To directly use limit instead of adjusted_limit in the predicate condition, we split adjusted_limit into:
++  //         adjusted_limit = limit + limit_correction
++  //     Since stride > 0 and limit_correction <= stride + 1, we can restate this with no over- or underflow into:
++  //         max_int - canonicalized_correction - limit_correction >= limit
++  //     Since canonicalized_correction and limit_correction are both constants, we can replace them with a new constant:
++  //         final_correction = canonicalized_correction + limit_correction
++  //     which gives us:
++  //
++  //     Final predicate condition:
++  //         max_int - final_correction >= limit
++  //
++  // (2) Loop Limit Check Predicate for (ii):
++  //     Using (ii): init < limit
++  //
++  //     This Loop Limit Check Predicate is not required if we can prove at compile time that either:
++  //        (2.1) type(init) < type(limit)
++  //             In this case, we know:
++  //                 all possible values of init < all possible values of limit
++  //             and we can skip the predicate.
++  //
++  //        (2.2) init < limit is already checked before (i.e. found as a dominating check)
++  //            In this case, we do not need to re-check the condition and can skip the predicate.
++  //            This is often found for while- and for-loops which have the following shape:
++  //
++  //                if (init < limit) { // Dominating test. Do not need the Loop Limit Check Predicate below.
++  //                    i = init;
++  //                    if (init >= limit) { trap(); } // Here we would insert the Loop Limit Check Predicate
++  //                    do {
++  //                        i += stride;
++  //                    } while (i < limit);
++  //                }
++  //
++  //        (2.3) init + stride <= max_int
++  //            In this case, there is no overflow of the iv phi after the first loop iteration.
++  //            In the proof of the base case above we showed that init + stride <= max_int by using assumption (ii):
++  //                init < limit
++  //            In the proof of the step case above, we did not need (ii) anymore. Therefore, if we already know at
++  //            compile time that init + stride <= max_int then we have trivially proven the base case and that
++  //            there is no overflow of the iv phi after the first iteration. In this case, we don't need to check (ii)
++  //            again and can skip the predicate.
++
++
++  // Accounting for (LE3) and (LE4) where we use pre-incremented phis in the loop exit check.
++  const jlong limit_correction_for_pre_iv_exit_check = (phi_incr != NULL) ? stride_con : 0;
++
++  // Accounting for (LE2) and (LE4) where we use <= or >= in the loop exit check.
++  const bool includes_limit = (bt == BoolTest::le || bt == BoolTest::ge);
++  const jlong limit_correction_for_le_ge_exit_check = (includes_limit ? (stride_con > 0 ? 1 : -1) : 0);
++
++  const jlong limit_correction = limit_correction_for_pre_iv_exit_check + limit_correction_for_le_ge_exit_check;
++  const jlong canonicalized_correction = stride_con + (stride_con > 0 ? -1 : 1);
++  const jlong final_correction = canonicalized_correction + limit_correction;
++
++  int sov = check_stride_overflow(final_correction, limit_t);
++
++  // If sov==0, limit's type always satisfies the condition, for
++  // example, when it is an array length.
++  if (sov != 0) {
++    if (sov < 0) {
++      return false;  // Bailout: integer overflow is certain.
++    }
++    // (1) Loop Limit Check Predicate is required because we could not statically prove that
++    //     limit + final_correction = adjusted_limit - 1 + stride <= max_int
++    ProjNode *limit_check_proj = find_predicate_insertion_point(init_control, Deoptimization::Reason_loop_limit_check);
++    if (!limit_check_proj) {
++      // The Loop Limit Check Parse Predicate is not generated if this method trapped here before.
++#ifdef ASSERT
++      if (TraceLoopLimitCheck) {
++        tty->print("missing loop limit check:");
++        loop->dump_head();
++        x->dump(1);
++      }
++#endif
++      return false;
++    }
+ 
+-  // Check if limit is excluded to do more precise int overflow check.
+-  bool incl_limit = (bt == BoolTest::le || bt == BoolTest::ge);
+-  int stride_m  = stride_con - (incl_limit ? 0 : (stride_con > 0 ? 1 : -1));
+-
+-  // If compare points directly to the phi we need to adjust
+-  // the compare so that it points to the incr. Limit have
+-  // to be adjusted to keep trip count the same and the
+-  // adjusted limit should be checked for int overflow.
+-  if (phi_incr != NULL) {
+-    stride_m  += stride_con;
+-  }
++    IfNode* check_iff = limit_check_proj->in(0)->as_If();
+ 
+-  if (limit->is_Con()) {
+-    int limit_con = limit->get_int();
+-    if ((stride_con > 0 && limit_con > (max_jint - stride_m)) ||
+-        (stride_con < 0 && limit_con < (min_jint - stride_m))) {
+-      // Bailout: it could be integer overflow.
++    if (!is_dominator(get_ctrl(limit), check_iff->in(0))) {
+       return false;
+     }
+-  } else if ((stride_con > 0 && limit_t->_hi <= (max_jint - stride_m)) ||
+-             (stride_con < 0 && limit_t->_lo >= (min_jint - stride_m))) {
+-      // Limit's type may satisfy the condition, for example,
+-      // when it is an array length.
+-  } else {
+-    // Generate loop's limit check.
+-    // Loop limit check predicate should be near the loop.
++
++    Node* cmp_limit;
++    Node* bol;
++
++    if (stride_con > 0) {
++      cmp_limit = new (C) CmpINode(limit, _igvn.intcon(max_jint - final_correction));
++      bol = new (C) BoolNode(cmp_limit, BoolTest::le);
++    } else {
++      cmp_limit = new (C) CmpINode(limit, _igvn.intcon(min_jint - final_correction));
++      bol = new (C) BoolNode(cmp_limit, BoolTest::ge);
++    }
++
++    insert_loop_limit_check(limit_check_proj, cmp_limit, bol);
++  }
++
++  // (2.3)
++  const bool init_plus_stride_could_overflow =
++          (stride_con > 0 && init_t->_hi > max_jint - stride_con) ||
++          (stride_con < 0 && init_t->_lo < min_jint - stride_con);
++  // (2.1)
++  const bool init_gte_limit = (stride_con > 0 && init_t->_hi >= limit_t->_lo) ||
++                              (stride_con < 0 && init_t->_lo <= limit_t->_hi);
++
++  if (init_gte_limit && // (2.1)
++     ((bt == BoolTest::ne || init_plus_stride_could_overflow) && // (2.3)
++      !has_dominating_loop_limit_check(init_trip, limit, stride_con, init_control))) { // (2.2)
++    // (2) Iteration Loop Limit Check Predicate is required because neither (2.1), (2.2), nor (2.3) holds.
++    // We use the following condition:
++    // - stride > 0: init < limit
++    // - stride < 0: init > limit
++    //
++    // This predicate is always required if we have a non-equal-operator in the loop exit check (where stride = 1 is
++    // a requirement). We transform the loop exit check by using a less-than-operator. By doing so, we must always
++    // check that init < limit. Otherwise, we could have a different number of iterations at runtime.
++
+     ProjNode *limit_check_proj = find_predicate_insertion_point(init_control, Deoptimization::Reason_loop_limit_check);
+     if (!limit_check_proj) {
+       // The limit check predicate is not generated if this method trapped here before.
+@@ -520,41 +768,38 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+ #endif
+       return false;
+     }
+-
+     IfNode* check_iff = limit_check_proj->in(0)->as_If();
++
++    if (!is_dominator(get_ctrl(limit), check_iff->in(0)) ||
++        !is_dominator(get_ctrl(init_trip), check_iff->in(0))) {
++      return false;
++    }
++
+     Node* cmp_limit;
+     Node* bol;
+ 
+     if (stride_con > 0) {
+-      cmp_limit = new (C) CmpINode(limit, _igvn.intcon(max_jint - stride_m));
+-      bol = new (C) BoolNode(cmp_limit, BoolTest::le);
++      cmp_limit = new (C) CmpINode(init_trip, limit);
++      bol = new (C) BoolNode(cmp_limit, BoolTest::lt);
+     } else {
+-      cmp_limit = new (C) CmpINode(limit, _igvn.intcon(min_jint - stride_m));
+-      bol = new (C) BoolNode(cmp_limit, BoolTest::ge);
++      cmp_limit = new (C) CmpINode(init_trip, limit);
++      bol = new (C) BoolNode(cmp_limit, BoolTest::gt);
+     }
+-    cmp_limit = _igvn.register_new_node_with_optimizer(cmp_limit);
+-    bol = _igvn.register_new_node_with_optimizer(bol);
+-    set_subtree_ctrl(bol);
+-
+-    // Replace condition in original predicate but preserve Opaque node
+-    // so that previous predicates could be found.
+-    assert(check_iff->in(1)->Opcode() == Op_Conv2B &&
+-           check_iff->in(1)->in(1)->Opcode() == Op_Opaque1, "");
+-    Node* opq = check_iff->in(1)->in(1);
+-    _igvn.hash_delete(opq);
+-    opq->set_req(1, bol);
+-    // Update ctrl.
+-    set_ctrl(opq, check_iff->in(0));
+-    set_ctrl(check_iff->in(1), check_iff->in(0));
+ 
+-#ifndef PRODUCT
+-    // report that the loop predication has been actually performed
+-    // for this loop
+-    if (TraceLoopLimitCheck) {
+-      tty->print_cr("Counted Loop Limit Check generated:");
+-      debug_only( bol->dump(2); )
++    insert_loop_limit_check(limit_check_proj, cmp_limit, bol);
++  }
++
++  if (bt == BoolTest::ne) {
++    // Now we need to canonicalize the loop condition if it is 'ne'.
++    assert(stride_con == 1 || stride_con == -1, "simple increment only - checked before");
++    if (stride_con > 0) {
++      // 'ne' can be replaced with 'lt' only when init < limit. This is ensured by the inserted predicate above.
++      bt = BoolTest::lt;
++    } else {
++      assert(stride_con < 0, "must be");
++      // 'ne' can be replaced with 'gt' only when init > limit. This is ensured by the inserted predicate above.
++      bt = BoolTest::gt;
+     }
+-#endif
+   }
+ 
+   if (phi_incr != NULL) {
+@@ -567,26 +812,15 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+     // is converted to
+     //   i = init; do {} while(++i < limit+1);
+     //
+-    limit = gvn->transform(new (C) AddINode(limit, stride));
+-  }
+-
+-  // Now we need to canonicalize loop condition.
+-  if (bt == BoolTest::ne) {
+-    assert(stride_con == 1 || stride_con == -1, "simple increment only");
+-    // 'ne' can be replaced with 'lt' only when init < limit.
+-    if (stride_con > 0 && init_t->_hi < limit_t->_lo)
+-      bt = BoolTest::lt;
+-    // 'ne' can be replaced with 'gt' only when init > limit.
+-    if (stride_con < 0 && init_t->_lo > limit_t->_hi)
+-      bt = BoolTest::gt;
++    adjusted_limit = gvn->transform(new (C) AddINode(limit, stride));
+   }
+ 
+-  if (incl_limit) {
++  if (includes_limit) {
+     // The limit check guaranties that 'limit <= (max_jint - stride)' so
+     // we can convert 'i <= limit' to 'i < limit+1' since stride != 0.
+     //
+     Node* one = (stride_con > 0) ? gvn->intcon( 1) : gvn->intcon(-1);
+-    limit = gvn->transform(new (C) AddINode(limit, one));
++    adjusted_limit = gvn->transform(new (C) AddINode(adjusted_limit, one));
+     if (bt == BoolTest::le)
+       bt = BoolTest::lt;
+     else if (bt == BoolTest::ge)
+@@ -594,10 +828,11 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+     else
+       ShouldNotReachHere();
+   }
+-  set_subtree_ctrl( limit );
++  set_subtree_ctrl(adjusted_limit);
+ 
+   } else { // LoopLimitCheck
+ 
++  Node *hook = new (C) Node(6);
+   // If compare points to incr, we are ok.  Otherwise the compare
+   // can directly point to the phi; in this case adjust the compare so that
+   // it points to the incr by adjusting the limit.
+@@ -691,6 +926,11 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+   limit = gvn->transform(new (C) AddINode(span,init_trip));
+   set_subtree_ctrl( limit );
+ 
++  adjusted_limit = limit;
++
++  // Free up intermediate goo
++  _igvn.remove_dead_node(hook);
++
+   } // LoopLimitCheck
+ 
+   if (!UseCountedLoopSafepoints) {
+@@ -728,7 +968,7 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+   }
+   cmp = cmp->clone();
+   cmp->set_req(1,incr);
+-  cmp->set_req(2,limit);
++  cmp->set_req(2, adjusted_limit);
+   cmp = _igvn.register_new_node_with_optimizer(cmp);
+   set_ctrl(cmp, iff->in(0));
+ 
+@@ -802,9 +1042,6 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+     }
+   }
+ 
+-  // Free up intermediate goo
+-  _igvn.remove_dead_node(hook);
+-
+ #ifdef ASSERT
+   assert(l->is_valid_counted_loop(), "counted loop shape is messed up");
+   assert(l == loop->_head && l->phi() == phi && l->loopexit() == lex, "" );
+@@ -821,6 +1058,37 @@ bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) {
+   return true;
+ }
+ 
++// Check if there is a dominating loop limit check of the form 'init < limit' starting at the loop entry.
++// If there is one, then we do not need to create an additional Loop Limit Check Predicate.
++bool PhaseIdealLoop::has_dominating_loop_limit_check(Node* init_trip, Node* limit, const int stride_con,
++                                                     Node* loop_entry) {
++  // Eagerly call transform() on the Cmp and Bool node to common them up if possible. This is required in order to
++  // successfully find a dominated test with the If node below.
++  Node* cmp_limit;
++  Node* bol;
++  if (stride_con > 0) {
++    cmp_limit = _igvn.transform(new (C) CmpINode(init_trip, limit));
++    bol = _igvn.transform(new (C) BoolNode(cmp_limit, BoolTest::lt));
++  } else {
++    cmp_limit = _igvn.transform(new (C) CmpINode(init_trip, limit));
++    bol = _igvn.transform(new (C) BoolNode(cmp_limit, BoolTest::gt));
++  }
++
++  // Check if there is already a dominating init < limit check. If so, we do not need a Loop Limit Check Predicate.
++  IfNode* iff = new (C) IfNode(loop_entry, bol, PROB_MIN, COUNT_UNKNOWN);
++  // Also add fake IfProj nodes in order to call transform() on the newly created IfNode.
++  IfFalseNode* if_false = new (C) IfFalseNode(iff);
++  IfTrueNode* if_true = new (C) IfTrueNode(iff);
++  Node* dominated_iff = _igvn.transform(iff);
++  // ConI node? Found dominating test (IfNode::dominated_by() returns a ConI node).
++  const bool found_dominating_test = dominated_iff != NULL && dominated_iff->Opcode() == Op_ConI;
++
++  // Kill the If with its projections again in the next IGVN round by cutting it off from the graph.
++  _igvn.replace_input_of(iff, 0, C->top());
++  _igvn.replace_input_of(iff, 1, C->top());
++  return found_dominating_test;
++}
++
+ //----------------------exact_limit-------------------------------------------
+ Node* PhaseIdealLoop::exact_limit( IdealLoopTree *loop ) {
+   assert(loop->_head->is_CountedLoop(), "");
+diff --git a/hotspot/src/share/vm/opto/loopnode.hpp b/hotspot/src/share/vm/opto/loopnode.hpp
+index 55a7def3..3ae41f8d 100644
+--- a/hotspot/src/share/vm/opto/loopnode.hpp
++++ b/hotspot/src/share/vm/opto/loopnode.hpp
+@@ -896,6 +896,10 @@ public:
+   // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted
+   ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry,
+                                         Deoptimization::DeoptReason reason);
++  void insert_loop_limit_check(ProjNode* limit_check_proj, Node* cmp_limit, Node* bol);
++  bool has_dominating_loop_limit_check(Node* init_trip, Node* limit, int stride_con,
++                                       Node* loop_entry);
++
+   void register_control(Node* n, IdealLoopTree *loop, Node* pred);
+ 
+   // Clone loop predicates to cloned loops (peeled, unswitched)
+diff --git a/hotspot/src/share/vm/opto/phaseX.hpp b/hotspot/src/share/vm/opto/phaseX.hpp
+index a2a2a538..bd7393ac 100644
+--- a/hotspot/src/share/vm/opto/phaseX.hpp
++++ b/hotspot/src/share/vm/opto/phaseX.hpp
+@@ -431,9 +431,6 @@ private:
+ 
+ protected:
+ 
+-  // Idealize new Node 'n' with respect to its inputs and its value
+-  virtual Node *transform( Node *a_node );
+-
+   // Warm up hash table, type table and initial worklist
+   void init_worklist( Node *a_root );
+ 
+@@ -447,6 +444,9 @@ public:
+   PhaseIterGVN( PhaseGVN *gvn ); // Used after Parser
+   PhaseIterGVN( PhaseIterGVN *igvn, const char *dummy ); // Used after +VerifyOpto
+ 
++  // Idealize new Node 'n' with respect to its inputs and its value
++  virtual Node *transform( Node *a_node );
++
+   virtual PhaseIterGVN *is_IterGVN() { return this; }
+ 
+   Unique_Node_List _worklist;       // Iterative worklist
+-- 
+2.25.1
+