diff --git a/hotspot/src/share/vm/opto/loopnode.cpp b/hotspot/src/share/vm/opto/loopnode.cpp index 8103d5cd92c..8c92ffffeee 100644 --- a/hotspot/src/share/vm/opto/loopnode.cpp +++ b/hotspot/src/share/vm/opto/loopnode.cpp @@ -1220,7 +1220,7 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) { const TypeInt* init_t = phase->type(in(Init) )->is_int(); const TypeInt* limit_t = phase->type(in(Limit))->is_int(); - int stride_p; + jlong stride_p; jlong lim, ini; julong max; if (stride_con > 0) { @@ -1229,10 +1229,10 @@ Node *LoopLimitNode::Ideal(PhaseGVN *phase, bool can_reshape) { ini = init_t->_lo; max = (julong)max_jint; } else { - stride_p = -stride_con; + stride_p = -(jlong)stride_con; lim = init_t->_hi; ini = limit_t->_lo; - max = (julong)min_jint; + max = (julong)(juint)min_jint; // double cast to get 0x0000000080000000, not 0xffffffff80000000 } julong range = lim - ini + stride_p; if (range <= max) { diff --git a/hotspot/src/share/vm/opto/superword.cpp b/hotspot/src/share/vm/opto/superword.cpp index 63baac179f3..cf47f3a8978 100644 --- a/hotspot/src/share/vm/opto/superword.cpp +++ b/hotspot/src/share/vm/opto/superword.cpp @@ -2317,7 +2317,11 @@ char* SuperWord::blank(uint depth) { //----------------------------SWPointer------------------------ SWPointer::SWPointer(MemNode* mem, SuperWord* slp) : _mem(mem), _slp(slp), _base(NULL), _adr(NULL), - _scale(0), _offset(0), _invar(NULL), _negate_invar(false) { + _scale(0), _offset(0), _invar(NULL), _negate_invar(false), + _has_int_index_after_convI2L(false), + _int_index_after_convI2L_offset(0), + _int_index_after_convI2L_invar(NULL), + _int_index_after_convI2L_scale(0) { Node* adr = mem->in(MemNode::Address); if (!adr->is_AddP()) { @@ -2346,6 +2350,12 @@ SWPointer::SWPointer(MemNode* mem, SuperWord* slp) : break; // stop looking at addp's } } + + if (!is_safe_to_use_as_simple_form(base, adr)) { + assert(!valid(), "does not have simple form"); + return; + } + _base = base; _adr = adr; assert(valid(), "Usable"); @@ -2355,7 +2365,354 @@ SWPointer::SWPointer(MemNode* mem, SuperWord* slp) : // the pattern match of an address expression. SWPointer::SWPointer(SWPointer* p) : _mem(p->_mem), _slp(p->_slp), _base(NULL), _adr(NULL), - _scale(0), _offset(0), _invar(NULL), _negate_invar(false) {} + _scale(0), _offset(0), _invar(NULL), _negate_invar(false), + _has_int_index_after_convI2L(false), + _int_index_after_convI2L_offset(0), + _int_index_after_convI2L_invar(NULL), + _int_index_after_convI2L_scale(0) {} + +// We would like to make decisions about aliasing (i.e. removing memory edges) and adjacency +// (i.e. which loads/stores can be packed) based on the simple form: +// +// s_pointer = adr + offset + invar + scale * ConvI2L(iv) +// +// However, we parse the compound-long-int form: +// +// c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index) +// int_index = int_offset + int_invar + int_scale * iv +// +// In general, the simple and the compound-long-int form do not always compute the same pointer +// at runtime. For example, the simple form would give a different result due to an overflow +// in the int_index. +// +// Example: +// For both forms, we have: +// iv = 0 +// scale = 1 +// +// We now account the offset and invar once to the long part and once to the int part: +// Pointer 1 (long offset and long invar): +// long_offset = min_int +// long_invar = min_int +// int_offset = 0 +// int_invar = 0 +// +// Pointer 2 (int offset and int invar): +// long_offset = 0 +// long_invar = 0 +// int_offset = min_int +// int_invar = min_int +// +// This gives us the following pointers: +// Compound-long-int form pointers: +// Form: +// c_pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + int_invar + int_scale * iv) +// +// Pointers: +// c_pointer1 = adr + min_int + min_int + 1 * ConvI2L(0 + 0 + 1 * 0) +// = adr + min_int + min_int +// = adr - 2^32 +// +// c_pointer2 = adr + 0 + 0 + 1 * ConvI2L(min_int + min_int + 1 * 0) +// = adr + ConvI2L(min_int + min_int) +// = adr + 0 +// = adr +// +// Simple form pointers: +// Form: +// s_pointer = adr + offset + invar + scale * ConvI2L(iv) +// s_pointer = adr + (long_offset + int_offset) + (long_invar + int_invar) + (long_scale * int_scale) * ConvI2L(iv) +// +// Pointers: +// s_pointer1 = adr + (min_int + 0 ) + (min_int + 0 ) + 1 * 0 +// = adr + min_int + min_int +// = adr - 2^32 +// s_pointer2 = adr + (0 + min_int ) + (0 + min_int ) + 1 * 0 +// = adr + min_int + min_int +// = adr - 2^32 +// +// We see that the two addresses are actually 2^32 bytes apart (derived from the c_pointers), but their simple form look identical. +// +// Hence, we need to determine in which cases it is safe to make decisions based on the simple +// form, rather than the compound-long-int form. If we cannot prove that using the simple form +// is safe (i.e. equivalent to the compound-long-int form), then we do not get a valid SWPointer, +// and the associated memop cannot be vectorized. +bool SWPointer::is_safe_to_use_as_simple_form(Node* base, Node* adr) const { +#ifndef _LP64 + // On 32-bit platforms, there is never an explicit int_index with ConvI2L for the iv. Thus, the + // parsed pointer form is always the simple form, with int operations: + // + // pointer = adr + offset + invar + scale * iv + // + assert(!_has_int_index_after_convI2L, "32-bit never has an int_index with ConvI2L for the iv"); + return true; +#else + + // Array accesses that are not Unsafe always have a RangeCheck which ensures that there is no + // int_index overflow. This implies that the conversion to long can be done separately: + // + // ConvI2L(int_index) = ConvI2L(int_offset) + ConvI2L(int_invar) + ConvI2L(scale) * ConvI2L(iv) + // + // And hence, the simple form is guaranteed to be identical to the compound-long-int form at + // runtime and the SWPointer is safe/valid to be used. + const TypeAryPtr* ary_ptr_t = _mem->adr_type()->isa_aryptr(); + + // We did not find the int_index. Just to be safe, reject this SWPointer. + if (!_has_int_index_after_convI2L) { + return false; + } + + int int_offset = _int_index_after_convI2L_offset; + Node* int_invar = _int_index_after_convI2L_invar; + int int_scale = _int_index_after_convI2L_scale; + int long_scale = _scale / int_scale; + + // If "int_index = iv", then the simple form is identical to the compound-long-int form. + // + // int_index = int_offset + int_invar + int_scale * iv + // = 0 0 1 * iv + // = iv + if (int_offset == 0 && int_invar == NULL && int_scale == 1) { + return true; + } + + // Intuition: What happens if the int_index overflows? Let us look at two pointers on the "overflow edge": + // + // pointer1 = adr + ConvI2L(int_index1) + // pointer2 = adr + ConvI2L(int_index2) + // + // int_index1 = max_int + 0 = max_int -> very close to but before the overflow + // int_index2 = max_int + 1 = min_int -> just enough to get the overflow + // + // When looking at the difference of pointer1 and pointer2, we notice that it is very large + // (almost 2^32). Since arrays have at most 2^31 elements, chances are high that pointer2 is + // an actual out-of-bounds access at runtime. These would normally be prevented by range checks + // at runtime. However, if the access was done by using Unsafe, where range checks are omitted, + // then an out-of-bounds access constitutes undefined behavior. This means that we are allowed to + // do anything, including changing the behavior. + // + // If we can set the right conditions, we have a guarantee that an overflow is either impossible + // (no overflow or range checks preventing that) or undefined behavior. In both cases, we are + // safe to do a vectorization. + // + // Approach: We want to prove a lower bound for the distance between these two pointers, and an + // upper bound for the size of a memory object. We can derive such an upper bound for + // arrays. We know they have at most 2^31 elements. If we know the size of the elements + // in bytes, we have: + // + // array_element_size_in_bytes * 2^31 >= max_possible_array_size_in_bytes + // >= array_size_in_bytes (ARR) + // + // If some small difference "delta" leads to an int_index overflow, we know that the + // int_index1 before overflow must have been close to max_int, and the int_index2 after + // the overflow must be close to min_int: + // + // pointer1 = adr + long_offset + long_invar + long_scale * ConvI2L(int_index1) + // =approx adr + long_offset + long_invar + long_scale * max_int + // + // pointer2 = adr + long_offset + long_invar + long_scale * ConvI2L(int_index2) + // =approx adr + long_offset + long_invar + long_scale * min_int + // + // We realize that the pointer difference is very large: + // + // difference =approx long_scale * 2^32 + // + // Hence, if we set the right condition for long_scale and array_element_size_in_bytes, + // we can prove that an overflow is impossible (or would imply undefined behaviour). + // + // We must now take this intuition, and develop a rigorous proof. We start by stating the problem + // more precisely, with the help of some definitions and the Statement we are going to prove. + // + // Definition: + // Two SWPointers are "comparable" (i.e. SWPointer::comparable is true, set with SWPointer::cmp()), + // iff all of these conditions apply for the simple form: + // 1) Both SWPointers are valid. + // 2) The adr are identical, or both are array bases of different arrays. + // 3) They have identical scale. + // 4) They have identical invar. + // 5) The difference in offsets is limited: abs(offset1 - offset2) < 2^31. (DIFF) + // + // For the Vectorization Optimization, we pair-wise compare SWPointers and determine if they are: + // 1) "not comparable": + // We do not optimize them (assume they alias, not assume adjacency). + // + // Whenever we chose this option based on the simple form, it is also correct based on the + // compound-long-int form, since we make no optimizations based on it. + // + // 2) "comparable" with different array bases at runtime: + // We assume they do not alias (remove memory edges), but not assume adjacency. + // + // Whenever we have two different array bases for the simple form, we also have different + // array bases for the compound-long-form. Since SWPointers provably point to different + // memory objects, they can never alias. + // + // 3) "comparable" with the same base address: + // We compute the relative pointer difference, and based on the load/store size we can + // compute aliasing and adjacency. + // + // We must find a condition under which the pointer difference of the simple form is + // identical to the pointer difference of the compound-long-form. We do this with the + // Statement below, which we then proceed to prove. + // + // Statement: + // If two SWPointers satisfy these 3 conditions: + // 1) They are "comparable". + // 2) They have the same base address. + // 3) Their long_scale is a multiple of the array element size in bytes: + // + // abs(long_scale) % array_element_size_in_bytes = 0 (A) + // + // Then their pointer difference of the simple form is identical to the pointer difference + // of the compound-long-int form. + // + // More precisely: + // Such two SWPointers by definition have identical adr, invar, and scale. + // Their simple form is: + // + // s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv) (B1) + // s_pointer2 = adr + offset2 + invar + scale * ConvI2L(iv) (B2) + // + // Thus, the pointer difference of the simple forms collapses to the difference in offsets: + // + // s_difference = s_pointer1 - s_pointer2 = offset1 - offset2 (C) + // + // Their compound-long-int form for these SWPointer is: + // + // c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1) (D1) + // int_index1 = int_offset1 + int_invar1 + int_scale1 * iv (D2) + // + // c_pointer2 = adr + long_offset2 + long_invar2 + long_scale2 * ConvI2L(int_index2) (D3) + // int_index2 = int_offset2 + int_invar2 + int_scale2 * iv (D4) + // + // And these are the offset1, offset2, invar and scale from the simple form (B1) and (B2): + // + // offset1 = long_offset1 + long_scale1 * ConvI2L(int_offset1) (D5) + // offset2 = long_offset2 + long_scale2 * ConvI2L(int_offset2) (D6) + // + // invar = long_invar1 + long_scale1 * ConvI2L(int_invar1) + // = long_invar2 + long_scale2 * ConvI2L(int_invar2) (D7) + // + // scale = long_scale1 * ConvI2L(int_scale1) + // = long_scale2 * ConvI2L(int_scale2) (D8) + // + // The pointer difference of the compound-long-int form is defined as: + // + // c_difference = c_pointer1 - c_pointer2 + // + // Thus, the statement claims that for the two SWPointer we have: + // + // s_difference = c_difference (Statement) + // + // We prove the Statement with the help of a Lemma: + // + // Lemma: + // There is some integer x, such that: + // + // c_difference = s_difference + array_element_size_in_bytes * x * 2^32 (Lemma) + // + // From condition (DIFF), we can derive: + // + // abs(s_difference) < 2^31 (E) + // + // Assuming the Lemma, we prove the Statement: + // If "x = 0" (intuitively: the int_index does not overflow), then: + // c_difference = s_difference + // and hence the simple form computes the same pointer difference as the compound-long-int form. + // If "x != 0" (intuitively: the int_index overflows), then: + // abs(c_difference) >= abs(s_difference + array_element_size_in_bytes * x * 2^32) + // >= array_element_size_in_bytes * 2^32 - abs(s_difference) + // -- apply (E) -- + // > array_element_size_in_bytes * 2^32 - 2^31 + // >= array_element_size_in_bytes * 2^31 + // -- apply (ARR) -- + // >= max_possible_array_size_in_bytes + // >= array_size_in_bytes + // + // This shows that c_pointer1 and c_pointer2 have a distance that exceeds the maximum array size. + // Thus, at least one of the two pointers must be outside of the array bounds. But we can assume + // that out-of-bounds accesses do not happen. If they still do, it is undefined behavior. Hence, + // we are allowed to do anything. We can also "safely" use the simple form in this case even though + // it might not match the compound-long-int form at runtime. + // QED Statement. + // + // We must now prove the Lemma. + // + // ConvI2L always truncates by some power of 2^32, i.e. there is some integer y such that: + // + // ConvI2L(y1 + y2) = ConvI2L(y1) + ConvI2L(y2) + 2^32 * y (F) + // + // It follows, that there is an integer y1 such that: + // + // ConvI2L(int_index1) = ConvI2L(int_offset1 + int_invar1 + int_scale1 * iv) + // -- apply (F) -- + // = ConvI2L(int_offset1) + // + ConvI2L(int_invar1) + // + ConvI2L(int_scale1) * ConvI2L(iv) + // + y1 * 2^32 (G) + // + // Thus, we can write the compound-long-int form (D1) as: + // + // c_pointer1 = adr + long_offset1 + long_invar1 + long_scale1 * ConvI2L(int_index1) + // -- apply (G) -- + // = adr + // + long_offset1 + // + long_invar1 + // + long_scale1 * ConvI2L(int_offset1) + // + long_scale1 * ConvI2L(int_invar1) + // + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv) + // + long_scale1 * y1 * 2^32 (H) + // + // And we can write the simple form as: + // + // s_pointer1 = adr + offset1 + invar + scale * ConvI2L(iv) + // -- apply (D5, D7, D8) -- + // = adr + // + long_offset1 + // + long_scale1 * ConvI2L(int_offset1) + // + long_invar1 + // + long_scale1 * ConvI2L(int_invar1) + // + long_scale1 * ConvI2L(int_scale1) * ConvI2L(iv) (K) + // + // We now compute the pointer difference between the simple (K) and compound-long-int form (H). + // Most terms cancel out immediately: + // + // sc_difference1 = c_pointer1 - s_pointer1 = long_scale1 * y1 * 2^32 (L) + // + // Rearranging the equation (L), we get: + // + // c_pointer1 = s_pointer1 + long_scale1 * y1 * 2^32 (M) + // + // And since long_scale1 is a multiple of array_element_size_in_bytes, there is some integer + // x1, such that (M) implies: + // + // c_pointer1 = s_pointer1 + array_element_size_in_bytes * x1 * 2^32 (N) + // + // With an analogue equation for c_pointer2, we can now compute the pointer difference for + // the compound-long-int form: + // + // c_difference = c_pointer1 - c_pointer2 + // -- apply (N) -- + // = s_pointer1 + array_element_size_in_bytes * x1 * 2^32 + // -(s_pointer2 + array_element_size_in_bytes * x2 * 2^32) + // -- where "x = x1 - x2" -- + // = s_pointer1 - s_pointer2 + array_element_size_in_bytes * x * 2^32 + // -- apply (C) -- + // = s_difference + array_element_size_in_bytes * x * 2^32 + // QED Lemma. + if (ary_ptr_t != NULL) { + BasicType array_element_bt = ary_ptr_t->elem()->array_element_basic_type(); + if (is_java_primitive(array_element_bt)) { + int array_element_size_in_bytes = type2aelembytes(array_element_bt); + if (abs(long_scale) % array_element_size_in_bytes == 0) { + return true; + } + } + } + + // General case: we do not know if it is safe to use the simple form. + return false; +#endif +} //------------------------scaled_iv_plus_offset-------------------- // Match: k*iv + offset @@ -2378,10 +2735,30 @@ bool SWPointer::scaled_iv_plus_offset(Node* n) { } } else if (opc == Op_SubI) { if (scaled_iv(n->in(1)) && offset_plus_k(n->in(2), true)) { + // (scale * iv) - (offset1 + invar1) + // Subtraction handled via "negate" flag of "offset_plus_k". return true; } - if (scaled_iv(n->in(2)) && offset_plus_k(n->in(1))) { - _scale *= -1; + SWPointer tmp(this); + if (tmp.scaled_iv(n->in(2)) && offset_plus_k(n->in(1))) { + // (offset1 + invar1) - (scale * iv) + // Subtraction handled explicitly below. + assert(_scale == 0, "shouldn't be set yet"); + // _scale = -tmp._scale + if (!try_MulI_no_overflow(-1, tmp._scale, _scale)) { + return false; // mul overflow. + } + // _offset -= tmp._offset + if (!try_SubI_no_overflow(_offset, tmp._offset, _offset)) { + return false; // sub overflow. + } + + // SWPointer tmp does not have an integer part to be forwarded + // (tmp._has_int_index_after_convI2L is false) because n is a SubI, all + // nodes above must also be of integer type (ConvL2I is not handled + // to allow a long) and ConvI2L (the only node that can add an integer + // part) won't be present. + return true; } } @@ -2409,16 +2786,56 @@ bool SWPointer::scaled_iv(Node* n) { } } else if (opc == Op_LShiftI) { if (n->in(1) == iv() && n->in(2)->is_Con()) { - _scale = 1 << n->in(2)->get_int(); + if (!try_LShiftI_no_overflow(1, n->in(2)->get_int(), _scale)) { + return false; // shift overflow. + } return true; } - } else if (opc == Op_ConvI2L) { + } else if (opc == Op_ConvI2L && !has_iv()) { if (n->in(1)->Opcode() == Op_CastII && n->in(1)->as_CastII()->has_range_check()) { // Skip range check dependent CastII nodes n = n->in(1); } - if (scaled_iv_plus_offset(n->in(1))) { + + // So far we have not found the iv yet, and are about to enter a ConvI2L subgraph, + // which may be the int index (that might overflow) for the memory access, of the form: + // + // int_index = int_offset + int_invar + int_scale * iv + // + // If we simply continue parsing with the current SWPointer, then the int_offset and + // int_invar simply get added to the long offset and invar. But for the checks in + // SWPointer::is_safe_to_use_as_simple_form() we need to have explicit access to the + // int_index. Thus, we must parse it explicitly here. For this, we use a temporary + // SWPointer, to pattern match the int_index sub-expression of the address. + + SWPointer tmp(this); + + if (tmp.scaled_iv_plus_offset(n->in(1)) && tmp.has_iv()) { + // We successfully matched an integer index, of the form: + // int_index = int_offset + int_invar + int_scale * iv + // Forward scale. + assert(_scale == 0 && tmp._scale != 0, "iv only found just now"); + _scale = tmp._scale; + // Accumulate offset. + if (!try_AddI_no_overflow(_offset, tmp._offset, _offset)) { + return false; // add overflow. + } + // Forward invariant if not already found. + if (tmp._invar != NULL) { + if (_invar != NULL) { + return false; + } + _invar = tmp._invar; + _negate_invar = tmp._negate_invar; + } + // Set info about the int_index: + assert(!_has_int_index_after_convI2L, "no previous int_index discovered"); + _has_int_index_after_convI2L = true; + _int_index_after_convI2L_offset = tmp._offset; + _int_index_after_convI2L_invar = tmp._invar; + _int_index_after_convI2L_scale = tmp._scale; + return true; } } else if (opc == Op_LShiftL) { @@ -2429,9 +2846,27 @@ bool SWPointer::scaled_iv(Node* n) { SWPointer tmp(this); if (tmp.scaled_iv_plus_offset(n->in(1))) { if (tmp._invar == NULL) { - int mult = 1 << n->in(2)->get_int(); - _scale = tmp._scale * mult; - _offset += tmp._offset * mult; + int shift = (int)(n->in(2)->get_int()); + // Accumulate scale. + if (!try_LShiftI_no_overflow(tmp._scale, shift, _scale)) { + return false; // shift overflow. + } + // Accumulate offset. + jint shifted_offset = 0; + if (!try_LShiftI_no_overflow(tmp._offset, shift, shifted_offset)) { + return false; // shift overflow. + } + if (!try_AddI_no_overflow(_offset, shifted_offset, _offset)) { + return false; // add overflow. + } + + // Forward info about the int_index: + assert(!_has_int_index_after_convI2L, "no previous int_index discovered"); + _has_int_index_after_convI2L = tmp._has_int_index_after_convI2L; + _int_index_after_convI2L_offset = tmp._int_index_after_convI2L_offset; + _int_index_after_convI2L_invar = tmp._int_index_after_convI2L_invar; + _int_index_after_convI2L_scale = tmp._int_index_after_convI2L_scale; + return true; } } @@ -2446,7 +2881,9 @@ bool SWPointer::scaled_iv(Node* n) { bool SWPointer::offset_plus_k(Node* n, bool negate) { int opc = n->Opcode(); if (opc == Op_ConI) { - _offset += negate ? -(n->get_int()) : n->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } return true; } else if (opc == Op_ConL) { // Okay if value fits into an int @@ -2454,7 +2891,9 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { if (t->higher_equal(TypeLong::INT)) { jlong loff = n->get_long(); jint off = (jint)loff; - _offset += negate ? -off : loff; + if (!try_AddSubI_no_overflow(_offset, off, negate, _offset)) { + return false; // add/sub overflow. + } return true; } return false; @@ -2464,10 +2903,14 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { if (n->in(2)->is_Con() && invariant(n->in(1))) { _negate_invar = negate; _invar = n->in(1); - _offset += negate ? -(n->in(2)->get_int()) : n->in(2)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } return true; } else if (n->in(1)->is_Con() && invariant(n->in(2))) { - _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } _negate_invar = negate; _invar = n->in(2); return true; @@ -2477,10 +2920,14 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { if (n->in(2)->is_Con() && invariant(n->in(1))) { _negate_invar = negate; _invar = n->in(1); - _offset += !negate ? -(n->in(2)->get_int()) : n->in(2)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(2)->get_int(), !negate, _offset)) { + return false; // add/sub overflow. + } return true; } else if (n->in(1)->is_Con() && invariant(n->in(2))) { - _offset += negate ? -(n->in(1)->get_int()) : n->in(1)->get_int(); + if (!try_AddSubI_no_overflow(_offset, n->in(1)->get_int(), negate, _offset)) { + return false; // add/sub overflow. + } _negate_invar = !negate; _invar = n->in(2); return true; @@ -2494,6 +2941,57 @@ bool SWPointer::offset_plus_k(Node* n, bool negate) { return false; } +bool SWPointer::try_AddI_no_overflow(jint offset1, jint offset2, jint& result) { + jlong long_offset = java_add((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_add( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + +bool SWPointer::try_SubI_no_overflow(jint offset1, jint offset2, jint& result) { + jlong long_offset = java_subtract((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_subtract( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + +bool SWPointer::try_AddSubI_no_overflow(jint offset1, jint offset2, bool is_sub, jint& result) { + if (is_sub) { + return try_SubI_no_overflow(offset1, offset2, result); + } else { + return try_AddI_no_overflow(offset1, offset2, result); + } +} + +bool SWPointer::try_LShiftI_no_overflow(jint offset, int shift, jint& result) { + if (shift < 0 || shift > 31) { + return false; + } + jlong long_offset = java_shift_left((jlong)(offset), (julong)((jlong)(shift))); + jint int_offset = java_shift_left( offset, (juint)((jint)(shift))); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + +bool SWPointer::try_MulI_no_overflow(jint offset1, jint offset2, jint& result) { + jlong long_offset = java_multiply((jlong)(offset1), (jlong)(offset2)); + jint int_offset = java_multiply( offset1, offset2); + if (long_offset != int_offset) { + return false; + } + result = int_offset; + return true; +} + //----------------------------print------------------------ void SWPointer::print() { #ifndef PRODUCT diff --git a/hotspot/src/share/vm/opto/superword.hpp b/hotspot/src/share/vm/opto/superword.hpp index 13fd2bf9de7..056baad1f52 100644 --- a/hotspot/src/share/vm/opto/superword.hpp +++ b/hotspot/src/share/vm/opto/superword.hpp @@ -452,18 +452,63 @@ class SuperWord : public ResourceObj { //------------------------------SWPointer--------------------------- // Information about an address for dependence checking and vector alignment +// +// We parse and represent pointers of the simple form: +// +// pointer = adr + offset + invar + scale * ConvI2L(iv) +// +// Where: +// +// adr: the base address of an array (base = adr) +// OR +// some address to off-heap memory (base = TOP) +// +// offset: a constant offset +// invar: a runtime variable, which is invariant during the loop +// scale: scaling factor +// iv: loop induction variable +// +// But more precisely, we parse the composite-long-int form: +// +// pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_offset + inv_invar + int_scale * iv) +// +// pointer = adr + long_offset + long_invar + long_scale * ConvI2L(int_index) +// int_index = int_offset + int_invar + int_scale * iv +// +// However, for aliasing and adjacency checks (e.g. SWPointer::cmp()) we always use the simple form to make +// decisions. Hence, we must make sure to only create a "valid" SWPointer if the optimisations based on the +// simple form produce the same result as the compound-long-int form would. Intuitively, this depends on +// if the int_index overflows, but the precise conditions are given in SWPointer::is_safe_to_use_as_simple_form(). +// +// ConvI2L(int_index) = ConvI2L(int_offset + int_invar + int_scale * iv) +// = Convi2L(int_offset) + ConvI2L(int_invar) + ConvI2L(int_scale) * ConvI2L(iv) +// +// scale = long_scale * ConvI2L(int_scale) +// offset = long_offset + long_scale * ConvI2L(int_offset) +// invar = long_invar + long_scale * ConvI2L(int_invar) +// +// pointer = adr + offset + invar + scale * ConvI2L(iv) +// class SWPointer VALUE_OBJ_CLASS_SPEC { protected: MemNode* _mem; // My memory reference node SuperWord* _slp; // SuperWord class - Node* _base; // NULL if unsafe nonheap reference - Node* _adr; // address pointer + // Components of the simple form: + Node* _base; // Base address of an array OR NULL if some off-heap memory. + Node* _adr; // Same as _base if an array pointer OR some off-heap memory pointer. jint _scale; // multiplier for iv (in bytes), 0 if no loop iv jint _offset; // constant offset (in bytes) Node* _invar; // invariant offset (in bytes), NULL if none bool _negate_invar; // if true then use: (0 - _invar) + // The int_index components of the compound-long-int form. Used to decide if it is safe to use the + // simple form rather than the compound-long-int form that was parsed. + bool _has_int_index_after_convI2L; + int _int_index_after_convI2L_offset; + Node* _int_index_after_convI2L_invar; + int _int_index_after_convI2L_scale; + PhaseIdealLoop* phase() { return _slp->phase(); } IdealLoopTree* lpt() { return _slp->lpt(); } PhiNode* iv() { return _slp->iv(); } // Induction var @@ -480,6 +525,8 @@ class SWPointer VALUE_OBJ_CLASS_SPEC { // Match: offset is (k [+/- invariant]) bool offset_plus_k(Node* n, bool negate = false); + bool is_safe_to_use_as_simple_form(Node* base, Node* adr) const; + public: enum CMP { Less = 1, @@ -507,12 +554,45 @@ class SWPointer VALUE_OBJ_CLASS_SPEC { int memory_size() { return _mem->memory_size(); } // Comparable? + // We compute if and how two SWPointers can alias at runtime, i.e. if the two addressed regions of memory can + // ever overlap. There are essentially 3 relevant return states: + // - NotComparable: Synonymous to "unknown aliasing". + // We have no information about how the two SWPointers can alias. They could overlap, refer + // to another location in the same memory object, or point to a completely different object. + // -> Memory edge required. Aliasing unlikely but possible. + // + // - Less / Greater: Synonymous to "never aliasing". + // The two SWPointers may point into the same memory object, but be non-aliasing (i.e. we + // know both address regions inside the same memory object, but these regions are non- + // overlapping), or the SWPointers point to entirely different objects. + // -> No memory edge required. Aliasing impossible. + // + // - Equal: Synonymous to "overlap, or point to different memory objects". + // The two SWPointers either overlap on the same memory object, or point to two different + // memory objects. + // -> Memory edge required. Aliasing likely. + // + // In a future refactoring, we can simplify to two states: + // - NeverAlias: instead of Less / Greater + // - MayAlias: instead of Equal / NotComparable + // + // Two SWPointer are "comparable" (Less / Greater / Equal), iff all of these conditions apply: + // 1) Both are valid, i.e. expressible in the compound-long-int or simple form. + // 2) The adr are identical, or both are array bases of different arrays. + // 3) They have identical scale. + // 4) They have identical invar. + // 5) The difference in offsets is limited: abs(offset0 - offset1) < 2^31. int cmp(SWPointer& q) { if (valid() && q.valid() && (_adr == q._adr || _base == _adr && q._base == q._adr) && _scale == q._scale && _invar == q._invar && _negate_invar == q._negate_invar) { + jlong difference = abs(java_subtract((jlong)_offset, (jlong)q._offset)); + jlong max_diff = (jlong)1 << 31; + if (difference >= max_diff) { + return NotComparable; + } bool overlap = q._offset < _offset + memory_size() && _offset < q._offset + q.memory_size(); return overlap ? Equal : (_offset < q._offset ? Less : Greater); @@ -529,6 +609,13 @@ class SWPointer VALUE_OBJ_CLASS_SPEC { static bool comparable(int cmp) { return cmp < NotComparable; } void print(); + + static bool try_AddI_no_overflow(jint offset1, jint offset2, jint& result); + static bool try_SubI_no_overflow(jint offset1, jint offset2, jint& result); + static bool try_AddSubI_no_overflow(jint offset1, jint offset2, bool is_sub, jint& result); + static bool try_LShiftI_no_overflow(jint offset1, int offset2, jint& result); + static bool try_MulI_no_overflow(jint offset1, jint offset2, jint& result); + }; #endif // SHARE_VM_OPTO_SUPERWORD_HPP diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/Obj.java b/jdk/src/share/classes/com/sun/jndi/ldap/Obj.java index 35cb9b244d3..444be925517 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/Obj.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/Obj.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, 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 @@ -241,6 +241,10 @@ static Object decodeObject(Attributes attrs) ClassLoader cl = helper.getURLClassLoader(codebases); return deserializeObject((byte[])attr.get(), cl); } else if ((attr = attrs.get(JAVA_ATTRIBUTES[REMOTE_LOC])) != null) { + // javaRemoteLocation attribute (RMI stub will be created) + if (!VersionHelper12.isSerialDataAllowed()) { + throw new NamingException("Object deserialization is not allowed"); + } // For backward compatibility only return decodeRmiObject( (String)attrs.get(JAVA_ATTRIBUTES[CLASSNAME]).get(), diff --git a/jdk/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java b/jdk/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java index 596cf1f5057..d78a2fa48c8 100644 --- a/jdk/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java +++ b/jdk/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2022, 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 @@ -40,13 +40,13 @@ final class VersionHelper12 extends VersionHelper { "com.sun.jndi.ldap.object.trustURLCodebase"; // System property to control whether classes are allowed to be loaded from - // 'javaSerializedData' attribute + // 'javaSerializedData', 'javaRemoteLocation' or 'javaReferenceAddress' attributes. private static final String TRUST_SERIAL_DATA_PROPERTY = "com.sun.jndi.ldap.object.trustSerialData"; /** - * Determines whether objects may be deserialized from the content of - * 'javaSerializedData' attribute. + * Determines whether objects may be deserialized or reconstructed from a content of + * 'javaSerializedData', 'javaRemoteLocation' or 'javaReferenceAddress' LDAP attributes. */ private static final boolean trustSerialData; @@ -56,7 +56,7 @@ final class VersionHelper12 extends VersionHelper { static { String trust = getPrivilegedProperty(TRUST_URL_CODEBASE_PROPERTY, "false"); trustURLCodebase = "true".equalsIgnoreCase(trust); - String trustSDString = getPrivilegedProperty(TRUST_SERIAL_DATA_PROPERTY, "true"); + String trustSDString = getPrivilegedProperty(TRUST_SERIAL_DATA_PROPERTY, "false"); trustSerialData = "true".equalsIgnoreCase(trustSDString); } @@ -72,8 +72,9 @@ private static String getPrivilegedProperty(String propertyName, String defaultV VersionHelper12() {} // Disallow external from creating one of these. /** - * Returns true if deserialization of objects from 'javaSerializedData' - * and 'javaReferenceAddress' LDAP attributes is allowed. + * Returns true if deserialization or reconstruction of objects from + * 'javaSerializedData', 'javaRemoteLocation' and 'javaReferenceAddress' + * LDAP attributes is allowed. * * @return true if deserialization is allowed; false - otherwise */ diff --git a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java index 13822df62a3..e6cab7bd684 100644 --- a/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java +++ b/jdk/src/share/classes/com/sun/security/auth/module/Krb5LoginModule.java @@ -41,7 +41,6 @@ import sun.security.krb5.*; import sun.security.jgss.krb5.Krb5Util; import sun.security.krb5.Credentials; -import sun.misc.HexDumpEncoder; /** *
This LoginModule authenticates users using
@@ -786,15 +785,11 @@ private void attemptAuthentication(boolean getPasswdFromSharedState)
if (debug) {
System.out.println("principal is " + principal);
- HexDumpEncoder hd = new HexDumpEncoder();
if (ktab != null) {
System.out.println("Will use keytab");
} else if (storeKey) {
for (int i = 0; i < encKeys.length; i++) {
- System.out.println("EncryptionKey: keyType=" +
- encKeys[i].getEType() +
- " keyBytes (hex dump)=" +
- hd.encodeBuffer(encKeys[i].getBytes()));
+ System.out.println(encKeys[i].toString());
}
}
}
@@ -895,7 +890,7 @@ private void promptForPass(boolean getPasswdFromSharedState)
}
if (debug) {
System.out.println
- ("password is " + new String(password));
+ ("Get password from shared state");
}
return;
}
diff --git a/jdk/src/share/classes/java/net/doc-files/net-properties.html b/jdk/src/share/classes/java/net/doc-files/net-properties.html
index 2d25e1b9f34..a02ee3d3c9e 100644
--- a/jdk/src/share/classes/java/net/doc-files/net-properties.html
+++ b/jdk/src/share/classes/java/net/doc-files/net-properties.html
@@ -220,6 +220,14 @@
{@systemProperty jdk.http.maxHeaderSize} (default: 393216 or 384kB)
+ This is the maximum header field section size that a client is prepared to accept.
+ This is computed as the sum of the size of the uncompressed header name, plus
+ the size of the uncompressed header value, plus an overhead of 32 bytes for
+ each field section line. If a peer sends a field section that exceeds this
+ size a {@link java.net.ProtocolException ProtocolException} will be raised.
+ This applies to all versions of the HTTP protocol. A value of zero or a negative
+ value means no limit. If left unspecified, the default value is 393216 bytes.
All these properties are checked only once at startup.
diff --git a/jdk/src/share/classes/java/text/MessageFormat.java b/jdk/src/share/classes/java/text/MessageFormat.java index 2497a490eb0..ec47fbfa36c 100644 --- a/jdk/src/share/classes/java/text/MessageFormat.java +++ b/jdk/src/share/classes/java/text/MessageFormat.java @@ -41,6 +41,7 @@ import java.io.InvalidObjectException; import java.io.IOException; import java.io.ObjectInputStream; +import java.io.ObjectStreamException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; @@ -960,6 +961,8 @@ public Object[] parse(String source, ParsePosition pos) { maximumArgumentNumber = argumentNumbers[i]; } } + + // Constructors/applyPattern ensure that resultArray.length < MAX_ARGUMENT_INDEX Object[] resultArray = new Object[maximumArgumentNumber + 1]; int patternOffset = 0; @@ -1210,6 +1213,9 @@ protected Object readResolve() throws InvalidObjectException { * @serial */ private int[] argumentNumbers = new int[INITIAL_FORMATS]; + // Implementation limit for ArgumentIndex pattern element. Valid indices must + // be less than this value + private static final int MAX_ARGUMENT_INDEX = 10000; /** * One less than the number of entries inoffsets. Can also be thought of
@@ -1434,6 +1440,11 @@ private void makeFormat(int position, int offsetNumber,
+ argumentNumber);
}
+ if (argumentNumber >= MAX_ARGUMENT_INDEX) {
+ throw new IllegalArgumentException(
+ argumentNumber + " exceeds the ArgumentIndex implementation limit");
+ }
+
// resize format information arrays if necessary
if (offsetNumber >= formats.length) {
int newLength = formats.length * 2;
@@ -1580,24 +1591,52 @@ private static final void copyAndFixQuotes(String source, int start, int end,
* @throws InvalidObjectException if the objects read from the stream is invalid.
*/
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
- in.defaultReadObject();
- boolean isValid = maxOffset >= -1
- && formats.length > maxOffset
- && offsets.length > maxOffset
- && argumentNumbers.length > maxOffset;
+ ObjectInputStream.GetField fields = in.readFields();
+ if (fields.defaulted("argumentNumbers") || fields.defaulted("offsets")
+ || fields.defaulted("formats") || fields.defaulted("locale")
+ || fields.defaulted("pattern") || fields.defaulted("maxOffset")){
+ throw new InvalidObjectException("Stream has missing data");
+ }
+
+ locale = (Locale) fields.get("locale", null);
+ String patt = (String) fields.get("pattern", null);
+ int maxOff = fields.get("maxOffset", -2);
+ int[] argNums = ((int[]) fields.get("argumentNumbers", null)).clone();
+ int[] offs = ((int[]) fields.get("offsets", null)).clone();
+ Format[] fmts = ((Format[]) fields.get("formats", null)).clone();
+
+ // Check arrays/maxOffset have correct value/length
+ boolean isValid = maxOff >= -1 && argNums.length > maxOff
+ && offs.length > maxOff && fmts.length > maxOff;
+
+ // Check the correctness of arguments and offsets
if (isValid) {
- int lastOffset = pattern.length() + 1;
- for (int i = maxOffset; i >= 0; --i) {
- if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
+ int lastOffset = patt.length() + 1;
+ for (int i = maxOff; i >= 0; --i) {
+ if (argNums[i] < 0 || argNums[i] >= MAX_ARGUMENT_INDEX
+ || offs[i] < 0 || offs[i] > lastOffset) {
isValid = false;
break;
} else {
- lastOffset = offsets[i];
+ lastOffset = offs[i];
}
}
}
+
if (!isValid) {
- throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
+ throw new InvalidObjectException("Stream has invalid data");
}
+ maxOffset = maxOff;
+ pattern = patt;
+ offsets = offs;
+ formats = fmts;
+ argumentNumbers = argNums;
+ }
+
+ /**
+ * Serialization without data not supported for this class.
+ */
+ private void readObjectNoData() throws ObjectStreamException {
+ throw new InvalidObjectException("Deserialized MessageFormat objects need data");
}
}
diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java b/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java
index 5c8b65f2703..70ba1676f7f 100644
--- a/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java
+++ b/jdk/src/share/classes/javax/security/auth/kerberos/KerberosKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, 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
@@ -233,9 +233,9 @@ public String toString() {
if (destroyed) {
return "Destroyed Principal";
}
- return "Kerberos Principal " + principal.toString() +
- "Key Version " + versionNum +
- "key " + key.toString();
+ return "KerberosKey: principal " + principal +
+ ", version " + versionNum +
+ ", key " + key.toString();
}
/**
diff --git a/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java b/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java
index f4ee947212b..0455d218b07 100644
--- a/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java
+++ b/jdk/src/share/classes/javax/security/auth/kerberos/KeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2024, 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
@@ -30,7 +30,8 @@
import javax.crypto.SecretKey;
import javax.security.auth.Destroyable;
import javax.security.auth.DestroyFailedException;
-import sun.misc.HexDumpEncoder;
+
+import sun.security.jgss.krb5.Krb5Util;
import sun.security.krb5.Asn1Exception;
import sun.security.krb5.PrincipalName;
import sun.security.krb5.EncryptionKey;
@@ -200,15 +201,8 @@ private void readObject(ObjectInputStream ois)
}
public String toString() {
- HexDumpEncoder hd = new HexDumpEncoder();
- return "EncryptionKey: keyType=" + keyType
- + " keyBytes (hex dump)="
- + (keyBytes == null || keyBytes.length == 0 ?
- " Empty Key" :
- '\n' + hd.encodeBuffer(keyBytes)
- + '\n');
-
-
+ return "keyType=" + keyType
+ + ", " + Krb5Util.keyInfo(keyBytes);
}
public int hashCode() {
diff --git a/jdk/src/share/classes/sun/net/www/MessageHeader.java b/jdk/src/share/classes/sun/net/www/MessageHeader.java
index 6ab2008dd4f..335ec49d3f3 100644
--- a/jdk/src/share/classes/sun/net/www/MessageHeader.java
+++ b/jdk/src/share/classes/sun/net/www/MessageHeader.java
@@ -30,6 +30,8 @@
package sun.net.www;
import java.io.*;
+import java.lang.reflect.Array;
+import java.net.ProtocolException;
import java.util.Collections;
import java.util.*;
@@ -46,11 +48,32 @@ class MessageHeader {
private String values[];
private int nkeys;
+ // max number of bytes for headers, <=0 means unlimited;
+ // this corresponds to the length of the names, plus the length
+ // of the values, plus an overhead of 32 bytes per name: value
+ // pair.
+ // Note: we use the same definition as HTTP/2 SETTINGS_MAX_HEADER_LIST_SIZE
+ // see RFC 9113, section 6.5.2.
+ // https://www.rfc-editor.org/rfc/rfc9113.html#SETTINGS_MAX_HEADER_LIST_SIZE
+ private final int maxHeaderSize;
+
+ // Aggregate size of the field lines (name + value + 32) x N
+ // that have been parsed and accepted so far.
+ // This is defined as a long to force promotion to long
+ // and avoid overflows; see checkNewSize;
+ private long size;
+
public MessageHeader () {
+ this(0);
+ }
+
+ public MessageHeader (int maxHeaderSize) {
+ this.maxHeaderSize = maxHeaderSize;
grow();
}
public MessageHeader (InputStream is) throws java.io.IOException {
+ maxHeaderSize = 0;
parseHeader(is);
}
@@ -466,10 +489,28 @@ public static String canonicalID(String id) {
public void parseHeader(InputStream is) throws java.io.IOException {
synchronized (this) {
nkeys = 0;
+ size = 0;
}
mergeHeader(is);
}
+ private void checkMaxHeaderSize(int sz) throws ProtocolException {
+ if (maxHeaderSize > 0) checkNewSize(size, sz, 0);
+ }
+
+ private long checkNewSize(long size, int name, int value) throws ProtocolException {
+ // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
+ long newSize = size + name + value + 32;
+ if (maxHeaderSize > 0 && newSize > maxHeaderSize) {
+ Arrays.fill(keys, 0, nkeys, null);
+ Arrays.fill(values,0, nkeys, null);
+ nkeys = 0;
+ throw new ProtocolException(String.format("Header size too big: %s > %s",
+ newSize, maxHeaderSize));
+ }
+ return newSize;
+ }
+
/** Parse and merge a MIME header from an input stream. */
@SuppressWarnings("fallthrough")
public void mergeHeader(InputStream is) throws java.io.IOException {
@@ -483,7 +524,15 @@ public void mergeHeader(InputStream is) throws java.io.IOException {
int c;
boolean inKey = firstc > ' ';
s[len++] = (char) firstc;
+ checkMaxHeaderSize(len);
parseloop:{
+ // We start parsing for a new name value pair here.
+ // The max header size includes an overhead of 32 bytes per
+ // name value pair.
+ // See SETTINGS_MAX_HEADER_LIST_SIZE, RFC 9113, section 6.5.2.
+ long maxRemaining = maxHeaderSize > 0
+ ? maxHeaderSize - size - 32
+ : Long.MAX_VALUE;
while ((c = is.read()) >= 0) {
switch (c) {
case ':':
@@ -517,6 +566,9 @@ public void mergeHeader(InputStream is) throws java.io.IOException {
s = ns;
}
s[len++] = (char) c;
+ if (maxHeaderSize > 0 && len > maxRemaining) {
+ checkMaxHeaderSize(len);
+ }
}
firstc = -1;
}
@@ -538,6 +590,9 @@ public void mergeHeader(InputStream is) throws java.io.IOException {
v = new String();
else
v = String.copyValueOf(s, keyend, len - keyend);
+ int klen = k == null ? 0 : k.length();
+
+ size = checkNewSize(size, klen, v.length());
add(k, v);
}
}
diff --git a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
index f64db254e54..e3419c535e7 100644
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
@@ -163,6 +163,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
*/
private static int bufSize4ES = 0;
+ private static final int maxHeaderSize;
+
/*
* Restrict setting of request headers through the public api
* consistent with JavaScript XMLHttpRequest2 with a few
@@ -284,6 +286,19 @@ private static Set