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:
+ * - Two subsequent dots are observer
+ *
- Number of dots more than 3
+ *
- Field value exceeds max allowed
+ *
- Character is not a valid digit for the requested {@code radix} value, given
+ * that a field has the radix specific prefix
+ *
+ *
+ * @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;
+ }
}
}
+
}