Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8343437: ClassDesc.of incorrectly permitting empty names #21830

Closed
wants to merge 4 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -174,92 +174,102 @@ public static ClassDesc parseReferenceTypeDesc(String descriptor) {
}

/**
* Validates the correctness of a binary class name. In particular checks for the presence of
* invalid characters in the name.
* Validates the correctness of a binary class name.
* In particular checks for the presence of invalid characters, empty
* name, consecutive, leading, or trailing {@code .}.
*
* @param name the class name
* @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid
* @throws NullPointerException if class name is {@code null}
*/
public static String validateBinaryClassName(String name) {
// state variable for detection of illegal states, such as:
// empty unqualified name, consecutive, leading, or trailing separators
int afterSeparator = 0;
int len = name.length();
for (int i = 0; i < len; i++) {
char ch = name.charAt(i);
// reject ';' or '[' or other form's separator
if (ch == ';' || ch == '[' || ch == '/')
throw invalidClassName(name);
if (ch == '.') {
if (i == afterSeparator) {
// illegal state when received separator indicates consecutive
// or leading separators
if (i == afterSeparator)
throw invalidClassName(name);
} else {
afterSeparator = i + 1;
}
afterSeparator = i + 1;
}
}
// reject empty unqualified name or trailing separators
if (len == afterSeparator)
throw invalidClassName(name);
return name;
}

/**
* Validates the correctness of an internal class name.
* In particular checks for the presence of invalid characters in the name.
* In particular checks for the presence of invalid characters, empty
* name, consecutive, leading, or trailing {@code /}.
*
* @param name the class name
* @return the class name passed if valid
* @throws IllegalArgumentException if the class name is invalid
* @throws NullPointerException if class name is {@code null}
*/
public static String validateInternalClassName(String name) {
// state variable for detection of illegal states, such as:
// empty unqualified name, consecutive, leading, or trailing separators
int afterSeparator = 0;
int len = name.length();
for (int i = 0; i < len; i++) {
char ch = name.charAt(i);
// reject ';' or '[' or other form's separator
if (ch == ';' || ch == '[' || ch == '.')
throw invalidClassName(name);
if (ch == '/') {
if (i == afterSeparator) {
// illegal state when received separator indicates consecutive
// or leading separators
if (i == afterSeparator)
throw invalidClassName(name);
} else {
afterSeparator = i + 1;
}
afterSeparator = i + 1;
}
}
// reject empty unqualified name or trailing separators
if (len == afterSeparator)
throw invalidClassName(name);
return name;
}

/**
* Validates the correctness of a binary package name.
* In particular checks for the presence of invalid characters in the name.
* Empty package name is allowed.
* In particular checks for the presence of invalid characters, consecutive,
* leading, or trailing {@code .}. Allows empty strings for the unnamed package.
*
* @param name the package name
* @return the package name passed if valid
* @throws IllegalArgumentException if the package name is invalid
* @throws NullPointerException if the package name is {@code null}
*/
public static String validateBinaryPackageName(String name) {
// Empty names are explicitly allowed
// the unnamed package + null check
if (name.isEmpty())
return name;
return validateBinaryClassName(name);
}

/**
* Validates the correctness of an internal package name.
* In particular checks for the presence of invalid characters in the name.
* Empty package name is allowed.
* In particular checks for the presence of invalid characters, consecutive,
* leading, or trailing {@code /}. Allows empty strings for the unnamed package.
*
* @param name the package name
* @return the package name passed if valid
* @throws IllegalArgumentException if the package name is invalid
* @throws NullPointerException if the package name is {@code null}
*/
public static String validateInternalPackageName(String name) {
// Empty names are explicitly allowed
// the unnamed package + null check
if (name.isEmpty())
return name;
return validateInternalClassName(name);
@@ -441,24 +451,20 @@ static int skipOverFieldSignature(String descriptor, int start, int end) {
case JVM_SIGNATURE_CLASS:
// state variable for detection of illegal states, such as:
// empty unqualified name, '//', leading '/', or trailing '/'
boolean legal = false;
int afterSeparator = index + 1; // start of internal name
while (index < end) {
switch (descriptor.charAt(index++)) {
case ';' -> {
// illegal state on parser exit indicates empty unqualified name or trailing '/'
return legal ? index - start : 0;
}
case '.', '[' -> {
// do not permit '.' or '['
ch = descriptor.charAt(index++);
if (ch == ';')
// reject empty unqualified name or trailing '/'
return index == afterSeparator ? 0 : index - start;
// reject '.' or '['
if (ch == '[' || ch == '.')
return 0;
if (ch == '/') {
// illegal state when received '/' indicates '//' or leading '/'
if (index == afterSeparator)
return 0;
}
case '/' -> {
// illegal state when received '/' indicates '//' or leading '/'
if (!legal) return 0;
legal = false;
}
default ->
legal = true;
afterSeparator = index + 1;
}
}
break;
3 changes: 2 additions & 1 deletion test/jdk/java/lang/constant/ClassDescTest.java
Original file line number Diff line number Diff line change
@@ -279,7 +279,8 @@ public void testArrayClassDesc() throws ReflectiveOperationException {
public void testBadClassDescs() {
List<String> badDescriptors = List.of("II", "I;", "Q", "L", "",
"java.lang.String", "[]", "Ljava/lang/String",
"Ljava.lang.String;", "java/lang/String");
"Ljava.lang.String;", "java/lang/String", "L;",
"La//b;", "L/a;", "La/;");

for (String d : badDescriptors) {
try {