From 8b078563d98638f91e9729a90d7f25e4aac1af84 Mon Sep 17 00:00:00 2001 From: dongchenxu Date: Fri, 1 Feb 2019 11:40:41 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=97=AE=E9=A2=98=20#133?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../qatest/api/EventWatchBuilderTestCase.java | 1 - .../sandbox/core/enhance/EventEnhancer.java | 88 ++++++++----------- .../jvm/sandbox/core/util/AsmUtils.java | 63 +++++++++++++ .../core/enhance/target/MyCalculator.java | 9 ++ .../sandbox/qatest/core/issues/Issues130.java | 10 ++- .../sandbox/qatest/core/issues/Issues133.java | 22 +++++ .../qatest/core/util/CalculatorHelper.java | 11 +++ 7 files changed, 149 insertions(+), 55 deletions(-) create mode 100644 sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/AsmUtils.java create mode 100644 sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/issues/Issues133.java diff --git a/sandbox-api/src/test/java/com/alibaba/jvm/sandbox/qatest/api/EventWatchBuilderTestCase.java b/sandbox-api/src/test/java/com/alibaba/jvm/sandbox/qatest/api/EventWatchBuilderTestCase.java index b3aa94db..5d7a2143 100644 --- a/sandbox-api/src/test/java/com/alibaba/jvm/sandbox/qatest/api/EventWatchBuilderTestCase.java +++ b/sandbox-api/src/test/java/com/alibaba/jvm/sandbox/qatest/api/EventWatchBuilderTestCase.java @@ -6,7 +6,6 @@ import com.alibaba.jvm.sandbox.api.listener.ext.AdviceListener; import com.alibaba.jvm.sandbox.api.listener.ext.EventWatchBuilder; import com.alibaba.jvm.sandbox.qatest.api.mock.MockForBuilderModuleEventWatcher; -import com.alibaba.jvm.sandbox.qatest.api.mock.MockForBuilderProgress; import com.alibaba.jvm.sandbox.qatest.api.util.ApiQaArrayUtils; import org.junit.Assert; import org.junit.Test; diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java index 91773f51..b35b1a40 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java @@ -2,16 +2,18 @@ import com.alibaba.jvm.sandbox.api.event.Event; import com.alibaba.jvm.sandbox.core.enhance.weaver.asm.EventWeaver; +import com.alibaba.jvm.sandbox.core.util.AsmUtils; import com.alibaba.jvm.sandbox.core.util.ObjectIDs; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.File; +import java.io.IOException; import java.util.Set; -import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName; -import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toJavaClassName; +import static org.apache.commons.io.FileUtils.writeByteArrayToFile; import static org.objectweb.asm.ClassReader.EXPAND_FRAMES; import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS; @@ -19,7 +21,8 @@ /** * 事件代码增强器 - * Created by luanjia@taobao.com on 16/7/12. + * + * @author luanjia@taobao.com */ public class EventEnhancer implements Enhancer { @@ -46,57 +49,42 @@ private ClassWriter createClassWriter(final ClassLoader targetClassLoader, */ @Override protected String getCommonSuperClass(String type1, String type2) { - Class c, d; - try { - c = Class.forName(toJavaClassName(type1), false, targetClassLoader); - d = Class.forName(toJavaClassName(type2), false, targetClassLoader); - } catch (Exception e) { - throw new RuntimeException(e); - } - if (c.isAssignableFrom(d)) { - return type1; - } - if (d.isAssignableFrom(c)) { - return type2; - } - if (c.isInterface() || d.isInterface()) { - return "java/lang/Object"; - } else { - do { - c = c.getSuperclass(); - } while (!c.isAssignableFrom(d)); - return toInternalClassName(c.getName()); - } + return AsmUtils.getCommonSuperClass(type1, type2, targetClassLoader); } }; } -// /* -// * dump class to file -// * 用于代码调试 -// */ -// private static byte[] dumpClassIfNecessary(String className, byte[] data) { -// final File dumpClassFile = new File("./sandbox-class-dump/" + className + ".class"); -// final File classPath = new File(dumpClassFile.getParent()); -// -// // 创建类所在的包路径 -// if (!classPath.mkdirs() -// && !classPath.exists()) { -// logger.warn("create dump classpath={} failed.", classPath); -// return data; -// } -// -// // 将类字节码写入文件 -// try { -// writeByteArrayToFile(dumpClassFile, data); -// logger.info("dump {} to {} success.", className, dumpClassFile); -// } catch (IOException e) { -// logger.warn("dump {} to {} failed.", className, dumpClassFile, e); -// } -// -// return data; -// } + private static final boolean isDumpClass = false; + + /* + * dump class to file + * 用于代码调试 + */ + private static byte[] dumpClassIfNecessary(String className, byte[] data) { + if (!isDumpClass) { + return data; + } + final File dumpClassFile = new File("./sandbox-class-dump/" + className + ".class"); + final File classPath = new File(dumpClassFile.getParent()); + + // 创建类所在的包路径 + if (!classPath.mkdirs() + && !classPath.exists()) { + logger.warn("create dump classpath={} failed.", classPath); + return data; + } + + // 将类字节码写入文件 + try { + writeByteArrayToFile(dumpClassFile, data); + logger.info("dump {} to {} success.", className, dumpClassFile); + } catch (IOException e) { + logger.warn("dump {} to {} failed.", className, dumpClassFile, e); + } + + return data; + } @Override public byte[] toByteCodeArray(final ClassLoader targetClassLoader, @@ -119,7 +107,7 @@ public byte[] toByteCodeArray(final ClassLoader targetClassLoader, ), EXPAND_FRAMES ); - return cw.toByteArray(); + return dumpClassIfNecessary(cr.getClassName(), cw.toByteArray()); } } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/AsmUtils.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/AsmUtils.java new file mode 100644 index 00000000..365d5602 --- /dev/null +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/AsmUtils.java @@ -0,0 +1,63 @@ +package com.alibaba.jvm.sandbox.core.util; + +import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructure; +import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructureFactory; +import org.apache.commons.io.IOUtils; + +import java.io.InputStream; + +import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName; + +/** + * ASM工具集 + * + * @author luanjia@taobao.com + */ +public class AsmUtils { + + /** + * {@see org.objectweb.asm.ClassWriter#getCommonSuperClass(String, String)} + */ + public static String getCommonSuperClass(String type1, String type2, ClassLoader loader) { + return getCommonSuperClassImplByAsm(type1, type2, loader); + } + + // implements by ASM + private static String getCommonSuperClassImplByAsm(String type1, String type2, ClassLoader targetClassLoader) { + InputStream inputStreamOfType1 = null, inputStreamOfType2 = null; + try { + inputStreamOfType1 = targetClassLoader.getResourceAsStream(type1 + ".class"); + if (null == inputStreamOfType1) { + return "java/lang/Object"; + } + inputStreamOfType2 = targetClassLoader.getResourceAsStream(type2 + ".class"); + if (null == inputStreamOfType2) { + return "java/lang/Object"; + } + final ClassStructure classStructureOfType1 = ClassStructureFactory.createClassStructure(inputStreamOfType1, targetClassLoader); + final ClassStructure classStructureOfType2 = ClassStructureFactory.createClassStructure(inputStreamOfType2, targetClassLoader); + if (classStructureOfType2.getFamilyTypeClassStructures().contains(classStructureOfType1)) { + return type1; + } + if (classStructureOfType1.getFamilyTypeClassStructures().contains(classStructureOfType2)) { + return type2; + } + if (classStructureOfType1.getAccess().isInterface() + || classStructureOfType2.getAccess().isInterface()) { + return "java/lang/Object"; + } + ClassStructure classStructure = classStructureOfType1; + do { + classStructure = classStructure.getSuperClassStructure(); + if (null == classStructure) { + return "java/lang/Object"; + } + } while (!classStructureOfType2.getFamilyTypeClassStructures().contains(classStructure)); + return toInternalClassName(classStructure.getJavaClassName()); + } finally { + IOUtils.closeQuietly(inputStreamOfType1); + IOUtils.closeQuietly(inputStreamOfType2); + } + } + +} diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/target/MyCalculator.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/target/MyCalculator.java index 36845ebe..9a1b09ee 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/target/MyCalculator.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/target/MyCalculator.java @@ -7,4 +7,13 @@ public MyCalculator(String tCaseName) { .toUpperCase()); } + public MyCalculator() { + super(); + } + + @Override + public int sum(int... numArray) { + return super.sum(numArray); + } + } diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/issues/Issues130.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/issues/Issues130.java index cb4538e0..c1c0d10a 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/issues/Issues130.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/issues/Issues130.java @@ -9,7 +9,6 @@ import static com.alibaba.jvm.sandbox.api.event.Event.Type.CALL_BEFORE; import static com.alibaba.jvm.sandbox.api.event.Event.Type.LINE; import static com.alibaba.jvm.sandbox.qatest.core.util.CalculatorHelper.*; -import static com.alibaba.jvm.sandbox.qatest.core.util.CalculatorHelper.newInstance; import static org.junit.Assert.assertEquals; /** @@ -35,8 +34,9 @@ public void onEvent(Event event) throws Throwable { ) .loadClass(CALCULATOR_CLASS_NAME); + final Object objectOfCal = newInstance(calculatorClass); for (int i = 0; i < 1000000; i++) { - assertEquals(30, sum(newInstance(calculatorClass), 10, 20)); + assertEquals(30, sum(objectOfCal, 10, 20)); } } @@ -58,8 +58,9 @@ public void onEvent(Event event) throws Throwable { ) .loadClass(CALCULATOR_CLASS_NAME); + final Object objectOfCal = newInstance(calculatorClass); for (int i = 0; i < 1000000; i++) { - assertEquals(30, sum(newInstance(calculatorClass), 10, 20)); + assertEquals(30, sum(objectOfCal, 10, 20)); } } @@ -81,8 +82,9 @@ public void onEvent(Event event) throws Throwable { ) .loadClass(CALCULATOR_CLASS_NAME); + final Object objectOfCal = newInstance(calculatorClass); for (int i = 0; i < 1000000; i++) { - assertEquals(30, sum(newInstance(calculatorClass), 10, 20)); + assertEquals(30, sum(objectOfCal, 10, 20)); } } diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/issues/Issues133.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/issues/Issues133.java new file mode 100644 index 00000000..0b9b3ffa --- /dev/null +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/issues/Issues133.java @@ -0,0 +1,22 @@ +package com.alibaba.jvm.sandbox.qatest.core.issues; + +import org.junit.Assert; +import org.junit.Test; + +import java.io.InputStream; + +import static com.alibaba.jvm.sandbox.core.util.AsmUtils.getCommonSuperClass; + +public class Issues133 { + + @Test + public void test() { + final ClassLoader loader = getClass().getClassLoader(); + Assert.assertEquals("java/io/InputStream", getCommonSuperClass("java/io/FileInputStream", "javax/servlet/ServletInputStream", loader)); + Assert.assertEquals("java/lang/Exception", getCommonSuperClass("java/io/IOException", "javax/servlet/ServletException", loader)); + Assert.assertEquals("javax/servlet/ServletResponse", getCommonSuperClass("javax/servlet/ServletResponse", "javax/servlet/http/HttpServletResponse", loader)); + Assert.assertEquals("javax/servlet/ServletResponse", getCommonSuperClass("javax/servlet/http/HttpServletResponse", "javax/servlet/ServletResponse", loader)); + Assert.assertEquals("java/lang/Object", getCommonSuperClass("java/lang/Throwable", "java/io/FileInputStream", loader)); + } + +} diff --git a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/CalculatorHelper.java b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/CalculatorHelper.java index 5c4fbd03..f1cfd041 100644 --- a/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/CalculatorHelper.java +++ b/sandbox-core/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/CalculatorHelper.java @@ -8,6 +8,7 @@ import com.alibaba.jvm.sandbox.api.filter.NameRegexFilter; import com.alibaba.jvm.sandbox.core.util.UnCaughtException; import com.alibaba.jvm.sandbox.qatest.core.enhance.target.Calculator; +import com.alibaba.jvm.sandbox.qatest.core.enhance.target.MyCalculator; import java.lang.reflect.InvocationTargetException; import java.util.Stack; @@ -22,6 +23,7 @@ public class CalculatorHelper { public static final String CALCULATOR_CLASS_NAME = getJavaClassName(Calculator.class); + public static final String MY_CALCULATOR_CLASS_NAME = getJavaClassName(MyCalculator.class); /** * 拦截sum()方法过滤器 @@ -68,6 +70,15 @@ public class CalculatorHelper { "" ); + /** + * 拦截sum()方法过滤器 + */ + public static final Filter MY_CALCULATOR_SUM_FILTER + = new NameRegexFilter( + "^com\\.alibaba\\.jvm.sandbox\\.qatest\\.core\\.enhance\\.target\\.MyCalculator$", + "^sum$" + ); + public static final Filter CALCULATOR_INIT_FILTER_WITH_TEST_CASE = new Filter() { @Override