ADDITIONAL SYSTEM INFORMATION :
System: Windows10 / Windows11 / Centos6.9 / Centos7.9
Java Runtime Infomation:The JDK environment we used for testing was JDK1.8u91/JDK1.8u241/JDK1.8u391
A DESCRIPTION OF THE PROBLEM :
When the JVM is optimizing partial space code, when certain permutations occur, such as when some code is executed very frequently, it can cause a JVM Crash.
The crash probability in Windows 10/11 MacOS in JDK1.8u191+181 is very high
The crash probability in JDK1.8u391 is low and almost impossible to experiment
Note that we used IDEA's Debug mode to run the code in our tests
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the test source code directly in Debug mode in IDEA
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Run 5 million cycles normally
ACTUAL -
A JVM Crash occurs after tens of thousands of runs
---------- BEGIN SOURCE ----------
Execute the Main method of the current class:
package org.example.test2;
import com.hfdp.commons.method.annotation.ParamentValidate;
import com.hfdp.commons.method.annotation.ValidateRules;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
public class TestCrash {
static class CompileService {
@ParamentValidate(name = "name")
@ParamentValidate(index = 1, name = "age")
public String test01(String name, Integer age) {
return "name:" + name + ",age:" + age;
}
}
public static void main(String[] args) {
CompileService compileService = new CompileService();
Method method = getMethodByName(compileService.getClass(), true, "test01");
for (int i = 0; i < 5000000; i++) {
Object[] params = new Object[]{"Mr Zhang", 12};
Class<?> returnType = method.getReturnType();
Class<?>[] parameterTypes = method.getParameterTypes();
ParamentValidate[] annotationsByType = method.getAnnotationsByType(ParamentValidate.class);
checkParam(params, returnType, annotationsByType, parameterTypes);
System.out.println("execute count -> " + i);
}
}
public static Method getMethodByName(Class<?> clazz, boolean ignoreCase, String methodName) throws SecurityException {
if (null == clazz || "".equals(methodName)) {
return null;
}
final Method[] methods = clazz.getMethods();
if (methods != null && methods.length > 0) {
for (Method method : methods) {
if (equals(methodName, method.getName(), ignoreCase)) {
return method;
}
}
}
return null;
}
private static void checkParam(Object[] args, Class<?> returnType, ParamentValidate[] paramentValidates, Class[] paramTyps) {
for (ParamentValidate paramentValidate : paramentValidates) {
paramCheck(paramentValidate, paramTyps[paramentValidate.index()], args[paramentValidate.index()]);
}
}
public static String paramCheck(ParamentValidate paramentValidate, Type paramType, Object parn) {
ValidateRules[] rules = paramentValidate.rules();
for (ValidateRules rule : rules) {
if (checkNull(paramType, parn)) {
return paramentValidate.name() + "be not null";
}
if (rule.equals(ValidateRules.NOT_NULL)) {
continue;
}
if (checkNull(paramType, parn)) {
return paramentValidate.name() + "be not null";
}
}
return null;
}
private static boolean checkNull(Type paramType, Object param) {
boolean typeBl = paramType == String.class || paramType == Integer.class || paramType == Date.class;
if (typeBl && "".equals(param)) {
return true;
} else {
if (paramType.getClass() == Class.class) {
if (param instanceof String && "".equals(param)) {
return true;
}
if (param instanceof HashMap) {
HashMap value = (HashMap) param;
if (value.size() == 0) {
return true;
}
}
if (param instanceof ArrayList) {
ArrayList value = (ArrayList) param;
if (value.size() == 0) {
return true;
}
}
}
}
return false;
}
public static boolean equals(CharSequence str1, CharSequence str2, boolean ignoreCase) {
if (null == str1) {
return str2 == null;
}
if (null == str2) {
return false;
}
if (ignoreCase) {
return str1.toString().equalsIgnoreCase(str2.toString());
} else {
return str1.toString().contentEquals(str2);
}
}
}
Test the classes that need the other two external dependencies in your code:
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(value = ParamentValidates.class)
public @interface ParamentValidate {
int index() default 0;
String name() default "";
ValidateRules[] rules() default {ValidateRules.NOT_NULL};
String length() default "";
int timeOffset() default 0;
String regularValue() default "";
}
public enum ValidateRules {
NOT_NULL,
LENGTH,
NULL_LENGTH,
MOBILE,
IDENTITY,
TIME,
REGULAR,
OBJECT;
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
1. On line 67 of TestCrash.java, change rule.equals(ValidateRules.NOT_NULL) to ValidateRules. Not_null.equals (rule)
2. Upgrade the JDK11 or later version
3. Set the JVM parameter -Xint
For now, we'll take the first approach
FREQUENCY : often
System: Windows10 / Windows11 / Centos6.9 / Centos7.9
Java Runtime Infomation:The JDK environment we used for testing was JDK1.8u91/JDK1.8u241/JDK1.8u391
A DESCRIPTION OF THE PROBLEM :
When the JVM is optimizing partial space code, when certain permutations occur, such as when some code is executed very frequently, it can cause a JVM Crash.
The crash probability in Windows 10/11 MacOS in JDK1.8u191+181 is very high
The crash probability in JDK1.8u391 is low and almost impossible to experiment
Note that we used IDEA's Debug mode to run the code in our tests
REGRESSION : Last worked in version 8
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the test source code directly in Debug mode in IDEA
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Run 5 million cycles normally
ACTUAL -
A JVM Crash occurs after tens of thousands of runs
---------- BEGIN SOURCE ----------
Execute the Main method of the current class:
package org.example.test2;
import com.hfdp.commons.method.annotation.ParamentValidate;
import com.hfdp.commons.method.annotation.ValidateRules;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
public class TestCrash {
static class CompileService {
@ParamentValidate(name = "name")
@ParamentValidate(index = 1, name = "age")
public String test01(String name, Integer age) {
return "name:" + name + ",age:" + age;
}
}
public static void main(String[] args) {
CompileService compileService = new CompileService();
Method method = getMethodByName(compileService.getClass(), true, "test01");
for (int i = 0; i < 5000000; i++) {
Object[] params = new Object[]{"Mr Zhang", 12};
Class<?> returnType = method.getReturnType();
Class<?>[] parameterTypes = method.getParameterTypes();
ParamentValidate[] annotationsByType = method.getAnnotationsByType(ParamentValidate.class);
checkParam(params, returnType, annotationsByType, parameterTypes);
System.out.println("execute count -> " + i);
}
}
public static Method getMethodByName(Class<?> clazz, boolean ignoreCase, String methodName) throws SecurityException {
if (null == clazz || "".equals(methodName)) {
return null;
}
final Method[] methods = clazz.getMethods();
if (methods != null && methods.length > 0) {
for (Method method : methods) {
if (equals(methodName, method.getName(), ignoreCase)) {
return method;
}
}
}
return null;
}
private static void checkParam(Object[] args, Class<?> returnType, ParamentValidate[] paramentValidates, Class[] paramTyps) {
for (ParamentValidate paramentValidate : paramentValidates) {
paramCheck(paramentValidate, paramTyps[paramentValidate.index()], args[paramentValidate.index()]);
}
}
public static String paramCheck(ParamentValidate paramentValidate, Type paramType, Object parn) {
ValidateRules[] rules = paramentValidate.rules();
for (ValidateRules rule : rules) {
if (checkNull(paramType, parn)) {
return paramentValidate.name() + "be not null";
}
if (rule.equals(ValidateRules.NOT_NULL)) {
continue;
}
if (checkNull(paramType, parn)) {
return paramentValidate.name() + "be not null";
}
}
return null;
}
private static boolean checkNull(Type paramType, Object param) {
boolean typeBl = paramType == String.class || paramType == Integer.class || paramType == Date.class;
if (typeBl && "".equals(param)) {
return true;
} else {
if (paramType.getClass() == Class.class) {
if (param instanceof String && "".equals(param)) {
return true;
}
if (param instanceof HashMap) {
HashMap value = (HashMap) param;
if (value.size() == 0) {
return true;
}
}
if (param instanceof ArrayList) {
ArrayList value = (ArrayList) param;
if (value.size() == 0) {
return true;
}
}
}
}
return false;
}
public static boolean equals(CharSequence str1, CharSequence str2, boolean ignoreCase) {
if (null == str1) {
return str2 == null;
}
if (null == str2) {
return false;
}
if (ignoreCase) {
return str1.toString().equalsIgnoreCase(str2.toString());
} else {
return str1.toString().contentEquals(str2);
}
}
}
Test the classes that need the other two external dependencies in your code:
@Target({ElementType.METHOD, ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(value = ParamentValidates.class)
public @interface ParamentValidate {
int index() default 0;
String name() default "";
ValidateRules[] rules() default {ValidateRules.NOT_NULL};
String length() default "";
int timeOffset() default 0;
String regularValue() default "";
}
public enum ValidateRules {
NOT_NULL,
LENGTH,
NULL_LENGTH,
MOBILE,
IDENTITY,
TIME,
REGULAR,
OBJECT;
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
1. On line 67 of TestCrash.java, change rule.equals(ValidateRules.NOT_NULL) to ValidateRules. Not_null.equals (rule)
2. Upgrade the JDK11 or later version
3. Set the JVM parameter -Xint
For now, we'll take the first approach
FREQUENCY : often