diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index b051c8d90d5..ff25840e5ea 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -586,7 +586,6 @@ ciKlass* ciEnv::get_klass_by_index(const constantPoolHandle& cpool, ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, int pool_index, int cache_index, ciInstanceKlass* accessor) { - bool ignore_will_link; EXCEPTION_CONTEXT; int index = pool_index; if (cache_index >= 0) { @@ -658,8 +657,8 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, return ciConstant(T_OBJECT, constant); } } else if (tag.is_klass() || tag.is_unresolved_klass()) { - // 4881222: allow ldc to take a class type - ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor); + bool will_link; + ciKlass* klass = get_klass_by_index_impl(cpool, index, will_link, accessor); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; record_out_of_memory_failure(); @@ -667,7 +666,8 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, } assert (klass->is_instance_klass() || klass->is_array_klass(), "must be an instance or array klass "); - return ciConstant(T_OBJECT, klass->java_mirror()); + ciInstance* mirror = (will_link ? klass->java_mirror() : get_unloaded_klass_mirror(klass)); + return ciConstant(T_OBJECT, mirror); } else if (tag.is_method_type()) { // must execute Java code to link this CP entry into cache[i].f1 ciSymbol* signature = get_symbol(cpool->method_type_signature_at(index)); @@ -675,6 +675,7 @@ ciConstant ciEnv::get_constant_by_index_impl(const constantPoolHandle& cpool, return ciConstant(T_OBJECT, ciobj); } else if (tag.is_method_handle()) { // must execute Java code to link this CP entry into cache[i].f1 + bool ignore_will_link; int ref_kind = cpool->method_handle_ref_kind_at(index); int callee_index = cpool->method_handle_klass_index_at(index); ciKlass* callee = get_klass_by_index_impl(cpool, callee_index, ignore_will_link, accessor); diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index 81998728f66..d0a206ba5d0 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -1698,10 +1698,32 @@ void LinkResolver::resolve_handle_call(CallInfo& result, assert(resolved_klass == SystemDictionary::MethodHandle_klass() || resolved_klass == SystemDictionary::VarHandle_klass(), ""); assert(MethodHandles::is_signature_polymorphic_name(link_info.name()), ""); - Handle resolved_appendix; - Handle resolved_method_type; + Handle resolved_appendix; + Handle resolved_method_type; methodHandle resolved_method = lookup_polymorphic_method(link_info, - &resolved_appendix, &resolved_method_type, CHECK); + &resolved_appendix, &resolved_method_type, CHECK); + + if (link_info.check_access()) { + Symbol* name = link_info.name(); + vmIntrinsics::ID iid = MethodHandles::signature_polymorphic_name_id(name); + if (MethodHandles::is_signature_polymorphic_intrinsic(iid)) { + // Check if method can be accessed by the referring class. + // MH.linkTo* invocations are not rewritten to invokehandle. + assert(iid == vmIntrinsics::_invokeBasic, "%s", vmIntrinsics::name_at(iid)); + + Klass* current_klass = link_info.current_klass(); + assert(current_klass != NULL , "current_klass should not be null"); + check_method_accessability(current_klass, + resolved_klass, + resolved_method->method_holder(), + resolved_method, + CHECK); + } else { + // Java code is free to arbitrarily link signature-polymorphic invokers. + assert(iid == vmIntrinsics::_invokeGeneric, "not an invoker: %s", vmIntrinsics::name_at(iid)); + assert(MethodHandles::is_signature_polymorphic_public_name(resolved_klass, name), "not public"); + } + } result.set_handle(resolved_klass, resolved_method, resolved_appendix, resolved_method_type, CHECK); } diff --git a/src/java.base/share/classes/java/net/HostPortrange.java b/src/java.base/share/classes/java/net/HostPortrange.java index 09f20d43cbe..ec602035f4d 100644 --- a/src/java.base/share/classes/java/net/HostPortrange.java +++ b/src/java.base/share/classes/java/net/HostPortrange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -137,7 +137,7 @@ public int hashCode() { } this.ipv4 = this.literal = ipv4; if (ipv4) { - byte[] ip = IPAddressUtil.textToNumericFormatV4(hoststr); + byte[] ip = IPAddressUtil.validateNumericFormatV4(hoststr); if (ip == null) { throw new IllegalArgumentException("illegal IPv4 address"); } diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java index c35056e3c65..646476f4cfb 100644 --- a/src/java.base/share/classes/java/net/InetAddress.java +++ b/src/java.base/share/classes/java/net/InetAddress.java @@ -1089,7 +1089,11 @@ private String removeComments(String hostsEntry) { private byte [] createAddressByteArray(String addrStr) { byte[] addrArray; // check if IPV4 address - most likely - addrArray = IPAddressUtil.textToNumericFormatV4(addrStr); + try { + addrArray = IPAddressUtil.validateNumericFormatV4(addrStr); + } catch (IllegalArgumentException iae) { + return null; + } if (addrArray == null) { addrArray = IPAddressUtil.textToNumericFormatV6(addrStr); } @@ -1324,13 +1328,19 @@ private static InetAddress[] getAllByName(String host, InetAddress reqAddr) } // if host is an IP address, we won't do further lookup - if (Character.digit(host.charAt(0), 16) != -1 + if (IPAddressUtil.digit(host.charAt(0), 16) != -1 || (host.charAt(0) == ':')) { - byte[] addr = null; + byte[] addr; int numericZone = -1; String ifname = null; // see if it is IPv4 address - addr = IPAddressUtil.textToNumericFormatV4(host); + try { + addr = IPAddressUtil.validateNumericFormatV4(host); + } catch (IllegalArgumentException iae) { + var uhe = new UnknownHostException(host); + uhe.initCause(iae); + throw uhe; + } if (addr == null) { // This is supposed to be an IPv6 literal // Check if a numeric or string zone id is present diff --git a/src/java.base/share/classes/java/net/SocketPermission.java b/src/java.base/share/classes/java/net/SocketPermission.java index 3f06c81c7cc..79cd8b78f48 100644 --- a/src/java.base/share/classes/java/net/SocketPermission.java +++ b/src/java.base/share/classes/java/net/SocketPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -463,7 +463,7 @@ private void init(String host, int mask) { if (!host.isEmpty()) { // see if we are being initialized with an IP address. char ch = host.charAt(0); - if (ch == ':' || Character.digit(ch, 16) != -1) { + if (ch == ':' || IPAddressUtil.digit(ch, 16) != -1) { byte ip[] = IPAddressUtil.textToNumericFormatV4(host); if (ip == null) { ip = IPAddressUtil.textToNumericFormatV6(host); diff --git a/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java b/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java index b50b1293fb7..6bcd5f7eae8 100644 --- a/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java +++ b/src/java.base/share/classes/jdk/internal/util/xml/impl/Parser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -30,6 +30,7 @@ import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import jdk.internal.org.xml.sax.InputSource; @@ -42,7 +43,11 @@ public abstract class Parser { public static final String FAULT = ""; protected static final int BUFFSIZE_READER = 512; + // Initial buffer (mBuff) size protected static final int BUFFSIZE_PARSER = 128; + // Max buffer size + private static final int MAX_ARRAY_SIZE = 1024 << 16; + /** * The end of stream character. */ @@ -525,6 +530,10 @@ private void dtd() throws Exception { mPh = PH_DTD; // DTD for (short st = 0; st >= 0;) { ch = getch(); + // report error if EOS is reached while parsing the DTD + if (ch == EOS) { + panic(FAULT); + } switch (st) { case 0: // read the document type name if (chtyp(ch) != ' ') { @@ -1664,6 +1673,10 @@ private void cdat() mBuffIdx = -1; for (short st = 0; st >= 0;) { ch = getch(); + // report error if EOS is reached while parsing the DTD + if (ch == EOS) { + panic(FAULT); + } switch (st) { case 0: // the first '[' of the CDATA open if (ch == '[') { @@ -1871,7 +1884,7 @@ protected String eqstr(char flag) throws Exception { } /** - * Resoves an entity. + * Resolves an entity. * * This method resolves built-in and character entity references. It is also * reports external entities to the application. @@ -2529,7 +2542,7 @@ private char bkeyword() } /** - * Reads a single or double quotted string in to the buffer. + * Reads a single or double quoted string into the buffer. * * This method resolves entities inside a string unless the parser parses * DTD. @@ -2664,7 +2677,7 @@ protected abstract void bflash_ws() * @param ch The character to append to the buffer. * @param mode The normalization mode. */ - private void bappend(char ch, char mode) { + private void bappend(char ch, char mode) throws Exception { // This implements attribute value normalization as // described in the XML specification [#3.3.3]. switch (mode) { @@ -2714,16 +2727,9 @@ private void bappend(char ch, char mode) { * * @param ch The character to append to the buffer. */ - private void bappend(char ch) { - try { - mBuff[++mBuffIdx] = ch; - } catch (Exception exp) { - // Double the buffer size - char buff[] = new char[mBuff.length << 1]; - System.arraycopy(mBuff, 0, buff, 0, mBuff.length); - mBuff = buff; - mBuff[mBuffIdx] = ch; - } + private void bappend(char ch) throws Exception { + ensureCapacity(++mBuffIdx); + mBuff[mBuffIdx] = ch; } /** @@ -2733,14 +2739,9 @@ private void bappend(char ch) { * @param cidx The character buffer (mChars) start index. * @param bidx The parser buffer (mBuff) start index. */ - private void bcopy(int cidx, int bidx) { + private void bcopy(int cidx, int bidx) throws Exception { int length = mChIdx - cidx; - if ((bidx + length + 1) >= mBuff.length) { - // Expand the buffer - char buff[] = new char[mBuff.length + length]; - System.arraycopy(mBuff, 0, buff, 0, mBuff.length); - mBuff = buff; - } + ensureCapacity(bidx + length + 1); System.arraycopy(mChars, cidx, mBuff, bidx, length); mBuffIdx += length; } @@ -3327,7 +3328,7 @@ protected char chtyp(char ch) { } /** - * Retrives the next character in the document. + * Retrieves the next character in the document. * * @return The next character in the document. */ @@ -3433,4 +3434,23 @@ protected Pair del(Pair pair) { return next; } + + private void ensureCapacity(int minCapacity) throws Exception { + if (mBuff == null) { + int newCapacity = minCapacity > BUFFSIZE_PARSER ? + minCapacity + BUFFSIZE_PARSER : BUFFSIZE_PARSER; + mBuff = new char[newCapacity]; + return; + } + + if (mBuff.length <= minCapacity) { + int size = mBuff.length << 1; + int newCapacity = size > minCapacity ? size : minCapacity + BUFFSIZE_PARSER; + if (newCapacity < 0 || newCapacity > MAX_ARRAY_SIZE) { + panic(FAULT); + } + + mBuff = Arrays.copyOf(mBuff, newCapacity); + } + } } diff --git a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java index 52cc6344a23..04fcbe5098c 100644 --- a/src/java.base/share/classes/sun/net/util/IPAddressUtil.java +++ b/src/java.base/share/classes/sun/net/util/IPAddressUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 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 @@ -28,13 +28,15 @@ import java.net.URL; import java.util.Arrays; -import java.io.IOException; +import sun.security.action.GetPropertyAction; + import java.io.UncheckedIOException; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketException; +import java.nio.CharBuffer; import java.security.AccessController; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; @@ -102,7 +104,7 @@ public static byte[] textToNumericFormatV4(String src) tmpValue = 0; newOctet = true; } else { - int digit = Character.digit(c, 10); + int digit = digit(c, 10); if (digit < 0) { return null; } @@ -127,6 +129,29 @@ public static byte[] textToNumericFormatV4(String src) return res; } + /** + * Validates if input string is a valid IPv4 address literal. + * If the "jdk.net.allowAmbiguousIPAddressLiterals" system property is set + * to {@code false}, or is not set then validation of the address string is performed as follows: + * If string can't be parsed by following IETF IPv4 address string literals + * formatting style rules (default one), but can be parsed by following BSD formatting + * style rules, the IPv4 address string content is treated as ambiguous and + * {@code IllegalArgumentException} is thrown. + * + * @param src input string + * @return bytes array if string is a valid IPv4 address string + * @throws IllegalArgumentException if "jdk.net.allowAmbiguousIPAddressLiterals" SP is set to + * "false" and IPv4 address string {@code "src"} is ambiguous + */ + public static byte[] validateNumericFormatV4(String src) { + byte[] parsedBytes = textToNumericFormatV4(src); + if (!ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE + && parsedBytes == null && isBsdParsableV4(src)) { + throw new IllegalArgumentException("Invalid IP address literal: " + src); + } + return parsedBytes; + } + /* * Convert IPv6 presentation level address to network order binary form. * credit: @@ -172,7 +197,7 @@ public static byte[] textToNumericFormatV6(String src) val = 0; while (i < srcb_length) { ch = srcb[i++]; - int chval = Character.digit(ch, 16); + int chval = digit(ch, 16); if (chval != -1) { val <<= 4; val |= chval; @@ -553,4 +578,249 @@ private static InetAddress findScopedAddress(InetAddress address) { return null; } } + + /** + * Returns the numeric value of the character {@code ch} in the + * specified radix. + * + * @param ch the character to be converted. + * @param radix the radix. + * @return the numeric value represented by the character in the + * specified radix. + */ + public static int digit(char ch, int radix) { + if (ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE) { + return Character.digit(ch, radix); + } else { + return parseAsciiDigit(ch, radix); + } + } + + /** + * Try to parse String as IPv4 address literal by following + * BSD-style formatting rules. + * + * @param input input string + * @return {@code true} if input string is parsable as IPv4 address literal, + * {@code false} otherwise. + */ + public static boolean isBsdParsableV4(String input) { + char firstSymbol = input.charAt(0); + // Check if first digit is not a decimal digit + if (parseAsciiDigit(firstSymbol, DECIMAL) == -1) { + return false; + } + + // Last character is dot OR is not a supported digit: [0-9,A-F,a-f] + char lastSymbol = input.charAt(input.length() - 1); + if (lastSymbol == '.' || parseAsciiHexDigit(lastSymbol) == -1) { + return false; + } + + // Parse IP address fields + CharBuffer charBuffer = CharBuffer.wrap(input); + int fieldNumber = 0; + while (charBuffer.hasRemaining()) { + long fieldValue = -1L; + // Try to parse fields in all supported radixes + for (int radix : SUPPORTED_RADIXES) { + fieldValue = parseV4FieldBsd(radix, charBuffer, fieldNumber); + if (fieldValue >= 0) { + fieldNumber++; + break; + } else if (fieldValue == TERMINAL_PARSE_ERROR) { + return false; + } + } + // If field can't be parsed as one of supported radixes stop + // parsing + if (fieldValue < 0) { + return false; + } + } + return true; + } + + /** + * Method tries to parse IP address field that starts from {@linkplain CharBuffer#position() + * current position} of the provided character buffer. + *

+ * This method supports three {@code "radix"} values to decode field values in + * {@code "HEXADECIMAL (radix=16)"}, {@code "DECIMAL (radix=10)"} and + * {@code "OCTAL (radix=8)"} radixes. + *

+ * If {@code -1} value is returned the char buffer position is reset to the value + * it was before it was called. + *

+ * Method returns {@code -2} if formatting illegal for all supported {@code radix} + * values is observed, and there is no point in checking other radix values. + * That includes the following cases:

+ * + * @param radix digits encoding radix to use for parsing. Valid values: 8, 10, 16. + * @param buffer {@code CharBuffer} with position set to the field's fist character + * @param fieldNumber parsed field number + * @return {@code CANT_PARSE_IN_RADIX} if field can not be parsed in requested {@code radix}. + * {@code TERMINAL_PARSE_ERROR} if field can't be parsed and the whole parse process should be terminated. + * Parsed field value otherwise. + */ + private static long parseV4FieldBsd(int radix, CharBuffer buffer, int fieldNumber) { + int initialPos = buffer.position(); + long val = 0; + int digitsCount = 0; + if (!checkPrefix(buffer, radix)) { + val = CANT_PARSE_IN_RADIX; + } + boolean dotSeen = false; + while (buffer.hasRemaining() && val != CANT_PARSE_IN_RADIX && !dotSeen) { + char c = buffer.get(); + if (c == '.') { + dotSeen = true; + // Fail if 4 dots in IP address string. + // fieldNumber counter starts from 0, therefore 3 + if (fieldNumber == 3) { + // Terminal state, can stop parsing: too many fields + return TERMINAL_PARSE_ERROR; + } + // Check for literals with two dots, like '1.2..3', '1.2.3..' + if (digitsCount == 0) { + // Terminal state, can stop parsing: dot with no digits + return TERMINAL_PARSE_ERROR; + } + if (val > 255) { + // Terminal state, can stop parsing: too big value for an octet + return TERMINAL_PARSE_ERROR; + } + } else { + int dv = parseAsciiDigit(c, radix); + if (dv >= 0) { + digitsCount++; + val *= radix; + val += dv; + } else { + // Spotted digit can't be parsed in the requested 'radix'. + // The order in which radixes are checked - hex, octal, decimal: + // - if symbol is not a valid digit in hex radix - terminal + // - if symbol is not a valid digit in octal radix, and given + // that octal prefix was observed before - terminal + // - if symbol is not a valid digit in decimal radix - terminal + return TERMINAL_PARSE_ERROR; + } + } + } + if (val == CANT_PARSE_IN_RADIX) { + buffer.position(initialPos); + } else if (!dotSeen) { + // It is the last field - check its value + // This check will ensure that address strings with less + // than 4 fields, i.e. A, A.B and A.B.C address types + // contain value less then the allowed maximum for the last field. + long maxValue = (1L << ((4 - fieldNumber) * 8)) - 1; + if (val > maxValue) { + // Terminal state, can stop parsing: last field value exceeds its + // allowed value + return TERMINAL_PARSE_ERROR; + } + } + return val; + } + + // This method moves the position of the supplied CharBuffer by analysing the digit prefix + // symbols if any. + // The caller should reset the position when method returns false. + private static boolean checkPrefix(CharBuffer buffer, int radix) { + switch (radix) { + case OCTAL: + return isOctalFieldStart(buffer); + case DECIMAL: + return isDecimalFieldStart(buffer); + case HEXADECIMAL: + return isHexFieldStart(buffer); + default: + throw new AssertionError("Not supported radix"); + } + } + + // This method always moves the position of the supplied CharBuffer + // removing the octal prefix symbols '0'. + // The caller should reset the position when method returns false. + private static boolean isOctalFieldStart(CharBuffer cb) { + // .0 is not treated as octal field + if (cb.remaining() < 2) { + return false; + } + + // Fetch two first characters + int position = cb.position(); + char first = cb.get(); + char second = cb.get(); + + // Return false if the first char is not octal prefix '0' or second is a + // field separator - parseV4FieldBsd will reset position to start of the field. + // '.0.' fields will be successfully parsed in decimal radix. + boolean isOctalPrefix = first == '0' && second != '.'; + + // If the prefix looks like octal - consume '0', otherwise 'false' is returned + // and caller will reset the buffer position. + if (isOctalPrefix) { + cb.position(position + 1); + } + return isOctalPrefix; + } + + // This method doesn't move the position of the supplied CharBuffer + private static boolean isDecimalFieldStart(CharBuffer cb) { + return cb.hasRemaining(); + } + + // This method always moves the position of the supplied CharBuffer + // removing the hexadecimal prefix symbols '0x'. + // The caller should reset the position when method returns false. + private static boolean isHexFieldStart(CharBuffer cb) { + if (cb.remaining() < 2) { + return false; + } + char first = cb.get(); + char second = cb.get(); + return first == '0' && (second == 'x' || second == 'X'); + } + + // Parse ASCII digit in given radix + private static int parseAsciiDigit(char c, int radix) { + assert radix == OCTAL || radix == DECIMAL || radix == HEXADECIMAL; + if (radix == HEXADECIMAL) { + return parseAsciiHexDigit(c); + } + int val = c - '0'; + return (val < 0 || val >= radix) ? -1 : val; + } + + // Parse ASCII digit in hexadecimal radix + private static int parseAsciiHexDigit(char digit) { + char c = Character.toLowerCase(digit); + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + return parseAsciiDigit(c, DECIMAL); + } + + // Supported radixes + private static final int HEXADECIMAL = 16; + private static final int DECIMAL = 10; + private static final int OCTAL = 8; + // Order in which field formats are exercised to parse one IP address textual field + private static final int[] SUPPORTED_RADIXES = new int[]{HEXADECIMAL, OCTAL, DECIMAL}; + + // BSD parser's return values + private final static long CANT_PARSE_IN_RADIX = -1L; + private final static long TERMINAL_PARSE_ERROR = -2L; + + private static final String ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP = "jdk.net.allowAmbiguousIPAddressLiterals"; + private static final boolean ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP_VALUE = Boolean.valueOf( + GetPropertyAction.privilegedGetProperty(ALLOW_AMBIGUOUS_IPADDRESS_LITERALS_SP, "false")); } diff --git a/src/java.base/share/classes/sun/security/util/BitArray.java b/src/java.base/share/classes/sun/security/util/BitArray.java index f22f259e15f..0d1310be416 100644 --- a/src/java.base/share/classes/sun/security/util/BitArray.java +++ b/src/java.base/share/classes/sun/security/util/BitArray.java @@ -63,22 +63,32 @@ public BitArray(int length) throws IllegalArgumentException { repn = new byte[(length + BITS_PER_UNIT - 1)/BITS_PER_UNIT]; } - /** * Creates a BitArray of the specified size, initialized from the - * specified byte array. The most significant bit of {@code a[0]} gets - * index zero in the BitArray. The array a must be large enough - * to specify a value for every bit in the BitArray. In other words, - * {@code 8*a.length <= length}. + * specified byte array. The most significant bit of {@code a[0]} gets + * index zero in the BitArray. The array must be large enough to specify + * a value for every bit of the BitArray. i.e. {@code 8*a.length <= length}. */ public BitArray(int length, byte[] a) throws IllegalArgumentException { + this(length, a, 0); + } + + /** + * Creates a BitArray of the specified size, initialized from the + * specified byte array starting at the specified offset. The most + * significant bit of {@code a[ofs]} gets index zero in the BitArray. + * The array must be large enough to specify a value for every bit of + * the BitArray, i.e. {@code 8*(a.length - ofs) <= length}. + */ + public BitArray(int length, byte[] a, int ofs) + throws IllegalArgumentException { if (length < 0) { throw new IllegalArgumentException("Negative length for BitArray"); } - if (a.length * BITS_PER_UNIT < length) { - throw new IllegalArgumentException("Byte array too short to represent " + - "bit array of given length"); + if ((a.length - ofs) * BITS_PER_UNIT < length) { + throw new IllegalArgumentException + ("Byte array too short to represent " + length + "-bit array"); } this.length = length; @@ -93,7 +103,7 @@ public BitArray(int length, byte[] a) throws IllegalArgumentException { 2. zero out extra bits in the last byte */ repn = new byte[repLength]; - System.arraycopy(a, 0, repn, 0, repLength); + System.arraycopy(a, ofs, repn, 0, repLength); if (repLength > 0) { repn[repLength - 1] &= bitMask; } @@ -266,7 +276,7 @@ public String toString() { public BitArray truncate() { for (int i=length-1; i>=0; i--) { if (get(i)) { - return new BitArray(i+1, Arrays.copyOf(repn, (i + BITS_PER_UNIT)/BITS_PER_UNIT)); + return new BitArray(i+1, repn, 0); } } return new BitArray(1); diff --git a/src/java.base/share/classes/sun/security/util/DerInputBuffer.java b/src/java.base/share/classes/sun/security/util/DerInputBuffer.java index a5cf8fdaafc..a2c054890c5 100644 --- a/src/java.base/share/classes/sun/security/util/DerInputBuffer.java +++ b/src/java.base/share/classes/sun/security/util/DerInputBuffer.java @@ -189,6 +189,28 @@ public int getInteger(int len) throws IOException { return result.intValue(); } + // check the number of pad bits, validate the pad bits in the bytes + // if enforcing DER (i.e. allowBER == false), and return the number of + // bits of the resulting BitString + private static int checkPaddedBits(int numOfPadBits, byte[] data, int start, + int end, boolean allowBER) throws IOException { + // number of pad bits should be from 0(min) to 7(max). + if ((numOfPadBits < 0) || (numOfPadBits > 7)) { + throw new IOException("Invalid number of padding bits"); + } + int lenInBits = ((end - start) << 3) - numOfPadBits; + if (lenInBits < 0) { + throw new IOException("Not enough bytes in BitString"); + } + + // padding bits should be all zeros for DER + if (!allowBER && numOfPadBits != 0 && + (data[end - 1] & (0xff >>> (8 - numOfPadBits))) != 0) { + throw new IOException("Invalid value of padding bits"); + } + return lenInBits; + } + /** * Returns the bit string which takes up the specified * number of bytes in this buffer. @@ -201,18 +223,20 @@ public byte[] getBitString(int len) throws IOException { throw new IOException("Invalid encoding: zero length bit string"); } - int numOfPadBits = buf[pos]; - if ((numOfPadBits < 0) || (numOfPadBits > 7)) { - throw new IOException("Invalid number of padding bits"); - } + int start = pos; + int end = start + len; + skip(len); // Compatibility. + + int numOfPadBits = buf[start++]; + checkPaddedBits(numOfPadBits, buf, start, end, allowBER); + // minus the first byte which indicates the number of padding bits byte[] retval = new byte[len - 1]; - System.arraycopy(buf, pos + 1, retval, 0, len - 1); - if (numOfPadBits != 0) { - // get rid of the padding bits - retval[len - 2] &= (0xff << numOfPadBits); + System.arraycopy(buf, start, retval, 0, len - 1); + if (allowBER && numOfPadBits != 0) { + // fix the potential non-zero padding bits + retval[retval.length - 1] &= (0xff << numOfPadBits); } - skip(len); return retval; } @@ -228,26 +252,35 @@ byte[] getBitString() throws IOException { * The bit string need not be byte-aligned. */ BitArray getUnalignedBitString() throws IOException { + return getUnalignedBitString(available()); + } + + /** + * Returns the bit string which takes up the specified + * number of bytes in this buffer. + * The bit string need not be byte-aligned. + */ + BitArray getUnalignedBitString(int len) throws IOException { + if (len > available()) + throw new IOException("short read of bit string"); + + if (len == 0) { + throw new IOException("Invalid encoding: zero length bit string"); + } + if (pos >= count) return null; /* * Just copy the data into an aligned, padded octet buffer, * and consume the rest of the buffer. */ - int len = available(); - int unusedBits = buf[pos] & 0xff; - if (unusedBits > 7 ) { - throw new IOException("Invalid value for unused bits: " + unusedBits); - } - byte[] bits = new byte[len - 1]; - // number of valid bits - int length = (bits.length == 0) ? 0 : bits.length * 8 - unusedBits; - - System.arraycopy(buf, pos + 1, bits, 0, len - 1); - - BitArray bitArray = new BitArray(length, bits); - pos = count; - return bitArray; + int start = pos; + int end = start + len; + pos = count; // Compatibility. + int numOfPadBits = buf[start++]; + int lenInBits = checkPaddedBits(numOfPadBits, buf, start, + end, allowBER); + return new BitArray(lenInBits, buf, start); } /** diff --git a/src/java.base/share/classes/sun/security/util/DerInputStream.java b/src/java.base/share/classes/sun/security/util/DerInputStream.java index e4880a2081a..c39e4beb440 100644 --- a/src/java.base/share/classes/sun/security/util/DerInputStream.java +++ b/src/java.base/share/classes/sun/security/util/DerInputStream.java @@ -261,27 +261,7 @@ public BitArray getUnalignedBitString() throws IOException { return new BitArray(0); } - /* - * First byte = number of excess bits in the last octet of the - * representation. - */ - length--; - int excessBits = buffer.read(); - if (excessBits < 0) { - throw new IOException("Unused bits of bit string invalid"); - } - int validBits = length*8 - excessBits; - if (validBits < 0) { - throw new IOException("Valid bits of bit string invalid"); - } - - byte[] repn = new byte[length]; - - if ((length != 0) && (buffer.read(repn) != length)) { - throw new IOException("Short read of DER bit string"); - } - - return new BitArray(validBits, repn); + return buffer.getUnalignedBitString(length); } /** diff --git a/src/java.base/share/native/libzip/zlib/deflate.c b/src/java.base/share/native/libzip/zlib/deflate.c index f30f71bdd79..2b80a735886 100644 --- a/src/java.base/share/native/libzip/zlib/deflate.c +++ b/src/java.base/share/native/libzip/zlib/deflate.c @@ -276,11 +276,6 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, int wrap = 1; static const char my_version[] = ZLIB_VERSION; - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - if (version == Z_NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; @@ -350,9 +345,47 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + /* We overlay pending_buf and sym_buf. This works since the average size + * for length/distance pairs over any compressed block is assured to be 31 + * bits or less. + * + * Analysis: The longest fixed codes are a length code of 8 bits plus 5 + * extra bits, for lengths 131 to 257. The longest fixed distance codes are + * 5 bits plus 13 extra bits, for distances 16385 to 32768. The longest + * possible fixed-codes length/distance pair is then 31 bits total. + * + * sym_buf starts one-fourth of the way into pending_buf. So there are + * three bytes in sym_buf for every four bytes in pending_buf. Each symbol + * in sym_buf is three bytes -- two for the distance and one for the + * literal/length. As each symbol is consumed, the pointer to the next + * sym_buf value to read moves forward three bytes. From that symbol, up to + * 31 bits are written to pending_buf. The closest the written pending_buf + * bits gets to the next sym_buf symbol to read is just before the last + * code is written. At that time, 31*(n-2) bits have been written, just + * after 24*(n-2) bits have been consumed from sym_buf. sym_buf starts at + * 8*n bits into pending_buf. (Note that the symbol buffer fills when n-1 + * symbols are written.) The closest the writing gets to what is unread is + * then n+14 bits. Here n is lit_bufsize, which is 16384 by default, and + * can range from 128 to 32768. + * + * Therefore, at a minimum, there are 142 bits of space between what is + * written and what is read in the overlain buffers, so the symbols cannot + * be overwritten by the compressed data. That space is actually 139 bits, + * due to the three-bit fixed-code block header. + * + * That covers the case where either Z_FIXED is specified, forcing fixed + * codes, or when the use of fixed codes is chosen, because that choice + * results in a smaller compressed block than dynamic codes. That latter + * condition then assures that the above analysis also covers all dynamic + * blocks. A dynamic-code block will only be chosen to be emitted if it has + * fewer bits than a fixed-code block would for the same set of symbols. + * Therefore its average symbol length is assured to be less than 31. So + * the compressed data for a dynamic block also cannot overwrite the + * symbols from which it is being constructed. + */ + + s->pending_buf = (uchf *) ZALLOC(strm, s->lit_bufsize, 4); + s->pending_buf_size = (ulg)s->lit_bufsize * 4; if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { @@ -361,8 +394,12 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, deflateEnd (strm); return Z_MEM_ERROR; } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + s->sym_buf = s->pending_buf + s->lit_bufsize; + s->sym_end = (s->lit_bufsize - 1) * 3; + /* We avoid equality with lit_bufsize*3 because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ s->level = level; s->strategy = strategy; @@ -573,7 +610,8 @@ int ZEXPORT deflatePrime (strm, bits, value) if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; - if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) + if (bits < 0 || bits > 16 || + s->sym_buf < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; do { put = Buf_size - s->bi_valid; @@ -1132,7 +1170,6 @@ int ZEXPORT deflateCopy (dest, source) #else deflate_state *ds; deflate_state *ss; - ushf *overlay; if (deflateStateCheck(source) || dest == Z_NULL) { @@ -1152,8 +1189,7 @@ int ZEXPORT deflateCopy (dest, source) ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; + ds->pending_buf = (uchf *) ZALLOC(dest, ds->lit_bufsize, 4); if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || ds->pending_buf == Z_NULL) { @@ -1167,8 +1203,7 @@ int ZEXPORT deflateCopy (dest, source) zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + ds->sym_buf = ds->pending_buf + ds->lit_bufsize; ds->l_desc.dyn_tree = ds->dyn_ltree; ds->d_desc.dyn_tree = ds->dyn_dtree; @@ -1936,7 +1971,7 @@ local block_state deflate_fast(s, flush) FLUSH_BLOCK(s, 1); return finish_done; } - if (s->last_lit) + if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } @@ -2067,7 +2102,7 @@ local block_state deflate_slow(s, flush) FLUSH_BLOCK(s, 1); return finish_done; } - if (s->last_lit) + if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } @@ -2142,7 +2177,7 @@ local block_state deflate_rle(s, flush) FLUSH_BLOCK(s, 1); return finish_done; } - if (s->last_lit) + if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } @@ -2181,7 +2216,7 @@ local block_state deflate_huff(s, flush) FLUSH_BLOCK(s, 1); return finish_done; } - if (s->last_lit) + if (s->sym_next) FLUSH_BLOCK(s, 0); return block_done; } diff --git a/src/java.base/share/native/libzip/zlib/deflate.h b/src/java.base/share/native/libzip/zlib/deflate.h index 183c22d430a..d3492eb17ee 100644 --- a/src/java.base/share/native/libzip/zlib/deflate.h +++ b/src/java.base/share/native/libzip/zlib/deflate.h @@ -241,7 +241,7 @@ typedef struct internal_state { /* Depth of each subtree used as tie breaker for trees of equal frequency */ - uchf *l_buf; /* buffer for literals or lengths */ + uchf *sym_buf; /* buffer for distances and literals/lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for @@ -263,13 +263,8 @@ typedef struct internal_state { * - I can't count above 4 */ - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ + uInt sym_next; /* running index in sym_buf */ + uInt sym_end; /* symbol table full when sym_next reaches this */ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ @@ -349,20 +344,22 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, # define _tr_tally_lit(s, c, flush) \ { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = 0; \ + s->sym_buf[s->sym_next++] = cc; \ s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ + flush = (s->sym_next == s->sym_end); \ } # define _tr_tally_dist(s, distance, length, flush) \ { uch len = (uch)(length); \ ush dist = (ush)(distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ + s->sym_buf[s->sym_next++] = (uch)dist; \ + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \ + s->sym_buf[s->sym_next++] = len; \ dist--; \ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ + flush = (s->sym_next == s->sym_end); \ } #else # define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) diff --git a/src/java.base/share/native/libzip/zlib/trees.c b/src/java.base/share/native/libzip/zlib/trees.c index c3703c0e763..030dc383e9b 100644 --- a/src/java.base/share/native/libzip/zlib/trees.c +++ b/src/java.base/share/native/libzip/zlib/trees.c @@ -440,7 +440,7 @@ local void init_block(s) s->dyn_ltree[END_BLOCK].Freq = 1; s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; + s->sym_next = s->matches = 0; } #define SMALLEST 1 @@ -971,7 +971,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); + s->sym_next / 3)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; @@ -1040,8 +1040,9 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) unsigned dist; /* distance of matched string */ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ { - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; + s->sym_buf[s->sym_next++] = (uch)dist; + s->sym_buf[s->sym_next++] = (uch)(dist >> 8); + s->sym_buf[s->sym_next++] = (uch)lc; if (dist == 0) { /* lc is the unmatched char */ s->dyn_ltree[lc].Freq++; @@ -1056,30 +1057,7 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc) s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; s->dyn_dtree[d_code(dist)].Freq++; } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ + return (s->sym_next == s->sym_end); } /* =========================================================================== @@ -1092,13 +1070,14 @@ local void compress_block(s, ltree, dtree) { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ + unsigned sx = 0; /* running index in sym_buf */ unsigned code; /* the code to send */ int extra; /* number of extra bits to send */ - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; + if (s->sym_next != 0) do { + dist = s->sym_buf[sx++] & 0xff; + dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8; + lc = s->sym_buf[sx++]; if (dist == 0) { send_code(s, lc, ltree); /* send a literal byte */ Tracecv(isgraph(lc), (stderr," '%c' ", lc)); @@ -1123,11 +1102,10 @@ local void compress_block(s, ltree, dtree) } } /* literal or match pair ? */ - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); + /* Check that the overlay between pending_buf and sym_buf is ok: */ + Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow"); - } while (lx < s->last_lit); + } while (sx < s->sym_next); send_code(s, END_BLOCK, ltree); } diff --git a/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java b/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java index 6f5a4bbf3c9..85f31acb0d5 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/StandardMidiFileReader.java @@ -380,6 +380,11 @@ void readTrack(Track track) throws IOException, InvalidMidiDataException { case 0xF7: // sys ex int sysexLength = (int) readVarInt(); + if (sysexLength < 0 || sysexLength > trackLength - pos) { + throw new InvalidMidiDataException("Message length is out of bounds: " + + sysexLength); + } + byte[] sysexData = new byte[sysexLength]; read(sysexData); @@ -392,8 +397,8 @@ void readTrack(Track track) throws IOException, InvalidMidiDataException { // meta int metaType = readUnsigned(); int metaLength = (int) readVarInt(); - if (metaLength < 0) { - throw new InvalidMidiDataException("length out of bounds: " + if (metaLength < 0 || metaLength > trackLength - pos) { + throw new InvalidMidiDataException("Message length is out of bounds: " + metaLength); } final byte[] metaData; diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java index 303b2b8ad8d..ed4ce0948ed 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantPool.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,6 +25,7 @@ import java.io.IOException; import com.sun.org.apache.bcel.internal.Const; +import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen; /** * This class represents the constant pool, i.e., a table of constants, of @@ -37,6 +37,7 @@ * @see Constant * @see com.sun.org.apache.bcel.internal.generic.ConstantPoolGen + * @LastModified: May 2022 */ public class ConstantPool implements Cloneable, Node { @@ -222,8 +223,16 @@ public String constantToString( final int index, final byte tag ) throws ClassFo * @throws IOException */ public void dump( final DataOutputStream file ) throws IOException { - file.writeShort(constantPool.length); - for (int i = 1; i < constantPool.length; i++) { + /* + * Constants over the size of the constant pool shall not be written out. + * This is a redundant measure as the ConstantPoolGen should have already + * reported an error back in the situation. + */ + int size = constantPool.length < ConstantPoolGen.CONSTANT_POOL_SIZE - 1 ? + constantPool.length : ConstantPoolGen.CONSTANT_POOL_SIZE - 1; + + file.writeShort(size); + for (int i = 1; i < size; i++) { if (constantPool[i] != null) { constantPool[i].dump(file); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ConstantPoolGen.java b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ConstantPoolGen.java index a1dadbfc4b6..806b40da1ed 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ConstantPoolGen.java +++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ConstantPoolGen.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -50,10 +50,10 @@ * JVM and that Double and Long constants need two slots. * * @see Constant - * @LastModified: May 2021 + * @LastModified: May 2022 */ public class ConstantPoolGen { - + public static final int CONSTANT_POOL_SIZE = 65536; private static final int DEFAULT_BUFFER_SIZE = 256; private int size; private Constant[] constants; @@ -83,7 +83,7 @@ private static class Index { public ConstantPoolGen(final Constant[] cs) { final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE); - size = Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64); + size = Math.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), CONSTANT_POOL_SIZE); constants = new Constant[size]; System.arraycopy(cs, 0, constants, 0, cs.length); @@ -212,9 +212,18 @@ public ConstantPoolGen() { /** Resize internal array of constants. */ protected void adjustSize() { + // 3 extra spaces are needed as some entries may take 3 slots + if (index + 3 >= CONSTANT_POOL_SIZE) { + throw new RuntimeException("The number of constants " + (index + 3) + + " is over the size of the constant pool: " + + (CONSTANT_POOL_SIZE - 1)); + } + if (index + 3 >= size) { final Constant[] cs = constants; size *= 2; + // the constant array shall not exceed the size of the constant pool + size = Math.min(size, CONSTANT_POOL_SIZE); constants = new Constant[size]; System.arraycopy(cs, 0, constants, 0, index); } diff --git a/test/jdk/sun/security/util/DerInputBuffer/PaddedBitString.java b/test/jdk/sun/security/util/DerInputBuffer/PaddedBitString.java index 2e31159c25e..8177a82b252 100644 --- a/test/jdk/sun/security/util/DerInputBuffer/PaddedBitString.java +++ b/test/jdk/sun/security/util/DerInputBuffer/PaddedBitString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2021, 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 @@ -26,52 +26,83 @@ * @bug 4511556 * @summary Verify BitString value containing padding bits is accepted. * @modules java.base/sun.security.util + * @library /test/lib */ - import java.io.*; -import java.util.Arrays; import java.math.BigInteger; +import java.util.Arrays; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; +import sun.security.util.BitArray; import sun.security.util.DerInputStream; +import sun.security.util.HexDumpEncoder; public class PaddedBitString { // Relaxed the BitString parsing routine to accept bit strings - // with padding bits, ex. treat DER_BITSTRING_PAD6 as the same - // bit string as DER_BITSTRING_NOPAD. + // with padding bits, ex. treat DER_BITSTRING_PAD6_b as the same + // bit string as DER_BITSTRING_PAD6_0/DER_BITSTRING_NOPAD. // Note: // 1. the number of padding bits has to be in [0...7] // 2. value of the padding bits is ignored - // bit string (01011101 11000000) - // With 6 padding bits (01011101 11001011) - private final static byte[] DER_BITSTRING_PAD6 = { 3, 3, 6, - (byte)0x5d, (byte)0xcb }; - // With no padding bits private final static byte[] DER_BITSTRING_NOPAD = { 3, 3, 0, (byte)0x5d, (byte)0xc0 }; + // With 6 zero padding bits (01011101 11000000) + private final static byte[] DER_BITSTRING_PAD6_0 = { 3, 3, 6, + (byte)0x5d, (byte)0xc0 }; - public static void main(String args[]) throws Exception { - byte[] ba0, ba1; - try { - DerInputStream derin = new DerInputStream(DER_BITSTRING_PAD6); - ba1 = derin.getBitString(); - } catch( IOException e ) { - e.printStackTrace(); - throw new Exception("Unable to parse BitString with 6 padding bits"); - } + // With 6 nonzero padding bits (01011101 11001011) + private final static byte[] DER_BITSTRING_PAD6_b = { 3, 3, 6, + (byte)0x5d, (byte)0xcb }; - try { - DerInputStream derin = new DerInputStream(DER_BITSTRING_NOPAD); - ba0 = derin.getBitString(); - } catch( IOException e ) { - e.printStackTrace(); - throw new Exception("Unable to parse BitString with no padding"); - } + // With 8 padding bits + private final static byte[] DER_BITSTRING_PAD8_0 = { 3, 3, 8, + (byte)0x5d, (byte)0xc0 }; + + private final static byte[] BITS = { (byte)0x5d, (byte)0xc0 }; + + static enum Type { + BIT_STRING, + UNALIGNED_BIT_STRING; + } - if (Arrays.equals(ba1, ba0) == false ) { - throw new Exception("BitString comparison check failed"); + public static void main(String args[]) throws Exception { + test(DER_BITSTRING_NOPAD, new BitArray(16, BITS)); + test(DER_BITSTRING_PAD6_0, new BitArray(10, BITS)); + test(DER_BITSTRING_PAD6_b, new BitArray(10, BITS)); + test(DER_BITSTRING_PAD8_0, null); + System.out.println("Tests Passed"); + } + + private static void test(byte[] in, BitArray ans) throws IOException { + System.out.print("Testing "); + new HexDumpEncoder().encodeBuffer(in, System.out); + for (Type t : Type.values()) { + DerInputStream derin = new DerInputStream(in); + boolean shouldPass = (ans != null); + switch (t) { + case BIT_STRING: + if (shouldPass) { + Asserts.assertTrue(Arrays.equals(ans.toByteArray(), + derin.getBitString())); + } else { + Utils.runAndCheckException(() -> derin.getBitString(), + IOException.class); + } + break; + case UNALIGNED_BIT_STRING: + if (shouldPass) { + Asserts.assertEQ(ans, derin.getUnalignedBitString()); + } else { + Utils.runAndCheckException(() -> + derin.getUnalignedBitString(), IOException.class); + } + break; + } } } + }