mirror of
https://github.com/wahyd4/pinpoint.git
synced 2026-08-17 16:56:15 +10:00
#1807 Javassist bug : Incorrect StackMap Frame generation
- add bug regression testcase
This commit is contained in:
@@ -36,6 +36,22 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.navercorp.pinpoint</groupId>
|
||||
<artifactId>pinpoint-profiler</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
<artifactId>javassist</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm-debug-all</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package bug_regression_jdk7.javassist;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class CustomURLClassLoader extends URLClassLoader {
|
||||
|
||||
public CustomURLClassLoader(URL[] urls, ClassLoader parent) {
|
||||
super(urls, parent);
|
||||
}
|
||||
|
||||
public CustomURLClassLoader(URL[] urls) {
|
||||
super(urls);
|
||||
}
|
||||
|
||||
public Class<?> defineClass0(String name, byte[] bytes) {
|
||||
return this.defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public Class<?> defineClass0(String name, byte[] bytes, int off, int length) {
|
||||
return super.defineClass(name, bytes, off, length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
return super.loadClass(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
package bug_regression_jdk7.javassist;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class InvalidStackMapFrame {
|
||||
|
||||
public void bytecodeVerifyError() {
|
||||
// javassist bug : invalid stack map frame
|
||||
List<Integer> test = new ArrayList<Integer>();
|
||||
String[] newLine = new String[10];
|
||||
for (Integer idx : test) {
|
||||
String address = newLine[1];
|
||||
int tabPos = -1;
|
||||
if (tabPos != -1) {
|
||||
address = address.substring(tabPos + 1);
|
||||
}
|
||||
newLine[4] = address;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package bug_regression_jdk7.javassist;
|
||||
|
||||
import bug_regression_jdk7.javassist.asm.BytecodeVerifyTestClassVisitor;
|
||||
import com.navercorp.pinpoint.profiler.instrument.ASMBytecodeDisassembler;
|
||||
import com.navercorp.pinpoint.profiler.util.JavaAssistUtils;
|
||||
import javassist.ClassPool;
|
||||
import javassist.CtClass;
|
||||
import javassist.CtMethod;
|
||||
import javassist.LoaderClassPath;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class JavassistVerifyErrorTest {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private static final String INVALID_STACK_MAP_FRAME = "bug_regression_jdk7.javassist.InvalidStackMapFrame";
|
||||
|
||||
/**
|
||||
* bug id
|
||||
* https://github.com/naver/pinpoint/issues/1807
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void bug_regression_BytecodeVerifyError_Invalid_StackMapFrame() throws Exception {
|
||||
|
||||
CustomURLClassLoader classLoader = new CustomURLClassLoader(new URL[]{}, Thread.currentThread().getContextClassLoader());
|
||||
|
||||
ClassPool classPool = new ClassPool(true);
|
||||
classPool.appendClassPath(new LoaderClassPath(classLoader));
|
||||
|
||||
final CtClass ctClass = classPool.get(INVALID_STACK_MAP_FRAME);
|
||||
final CtMethod method = ctClass.getDeclaredMethod("bytecodeVerifyError");
|
||||
method.addLocalVariable("test_localVariable", CtClass.intType);
|
||||
method.insertBefore("{ test_localVariable = 1; }");
|
||||
|
||||
final byte[] bytecode = ctClass.toBytecode();
|
||||
classLoader.defineClass0(INVALID_STACK_MAP_FRAME, bytecode);
|
||||
try {
|
||||
Class.forName(INVALID_STACK_MAP_FRAME, true, classLoader);
|
||||
Assert.fail("VerifyError");
|
||||
} catch (java.lang.VerifyError e) {
|
||||
logger.debug("verifyError:{}", e.getMessage(), e);
|
||||
}
|
||||
|
||||
|
||||
final ASMBytecodeDisassembler bytecodeDisassembler = new ASMBytecodeDisassembler();
|
||||
|
||||
final String dumpBytecode = bytecodeDisassembler.dumpBytecode(bytecode);
|
||||
logger.debug("dumpBytecode:{}", dumpBytecode);
|
||||
|
||||
// javassist bug : invalid stack map frame
|
||||
// 00013 InvalidStackMapFrame ArrayList String Iterator I : : FRAME FULL [bug_regression_jdk7/javassist/InvalidStackMapFrame java/util/ArrayList [[[java/lang/Object->[Ljava/lang/String;]]] java/util/Iterator T T T I] []
|
||||
final String verify = bytecodeDisassembler.dumpVerify(bytecode, classLoader);
|
||||
logger.debug("dumpVerify:{}", verify);
|
||||
|
||||
final String dumpAsm = bytecodeDisassembler.dumpASM(bytecode);
|
||||
logger.debug("dumpAsm :{}", dumpAsm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void asm_stackmapframe_check() throws Exception {
|
||||
|
||||
CustomURLClassLoader classLoader = new CustomURLClassLoader(new URL[]{}, Thread.currentThread().getContextClassLoader());
|
||||
final InputStream stream = classLoader.getResourceAsStream(JavaAssistUtils.javaNameToJvmName(INVALID_STACK_MAP_FRAME) + ".class");
|
||||
|
||||
ClassReader cr = new ClassReader(stream);
|
||||
ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
|
||||
ClassVisitor cv = new BytecodeVerifyTestClassVisitor(cw);
|
||||
cr.accept(cv, ClassReader.EXPAND_FRAMES | ClassReader.SKIP_DEBUG);
|
||||
|
||||
byte[] bytecode = cw.toByteArray();
|
||||
classLoader.defineClass0(INVALID_STACK_MAP_FRAME, bytecode);
|
||||
|
||||
final Class<?> aClass = Class.forName(INVALID_STACK_MAP_FRAME, true, classLoader);
|
||||
Assert.assertSame(aClass.getClassLoader(), classLoader);
|
||||
|
||||
|
||||
final ASMBytecodeDisassembler bytecodeDisassembler = new ASMBytecodeDisassembler();
|
||||
|
||||
final String dumpBytecode = bytecodeDisassembler.dumpBytecode(bytecode);
|
||||
logger.debug("dumpBytecode:{}", dumpBytecode);
|
||||
|
||||
final String verify = bytecodeDisassembler.dumpVerify(bytecode, classLoader);
|
||||
logger.debug("dumpVerify:{}", verify);
|
||||
|
||||
// final String dumpAsm = bytecodeDisassembler.dumpASM(bytecode);
|
||||
// logger.debug("dumpAsm :{}", dumpAsm);
|
||||
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package bug_regression_jdk7.javassist.asm;
|
||||
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.AdviceAdapter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class AddIntVariableMethodAdapter extends AdviceAdapter {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private String name;
|
||||
|
||||
public AddIntVariableMethodAdapter(MethodVisitor mv, int acc, String name, String desc) {
|
||||
super(Opcodes.ASM5, mv, acc, name, desc);
|
||||
this.name = name;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
super.visitMaxs(maxStack + 1, maxLocals);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMethodEnter() {
|
||||
logger.debug("onMethodEnter() add int local variable inst:ISTORE_7 {}", name);
|
||||
mv.visitInsn(Opcodes.ICONST_0);
|
||||
mv.visitVarInsn(Opcodes.ISTORE, 7);
|
||||
}
|
||||
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package bug_regression_jdk7.javassist.asm;
|
||||
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||
|
||||
/**
|
||||
* @author Woonduk Kang(emeroad)
|
||||
*/
|
||||
public class BytecodeVerifyTestClassVisitor extends ClassVisitor {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
private String name;
|
||||
|
||||
public BytecodeVerifyTestClassVisitor(final ClassVisitor cv) {
|
||||
super(org.objectweb.asm.Opcodes.ASM5, cv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(final int version, final int access, final String name,
|
||||
final String signature, final String superName,
|
||||
final String[] interfaces) {
|
||||
this.name = name;
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(final int access, final String name,
|
||||
final String desc, final String signature, final String[] exceptions) {
|
||||
|
||||
MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
logger.debug("mv:{}", mv);
|
||||
logger.debug("name:{}", name);
|
||||
logger.debug("desc:{}", desc);
|
||||
logger.debug("signature:{}", signature);
|
||||
if (name.contains("bytecodeVerifyError")) {
|
||||
return new AddIntVariableMethodAdapter(mv, Opcodes.ACC_PUBLIC, name, "()V");
|
||||
}
|
||||
return mv;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE log4j:configuration PUBLIC "" "log4j.dtd">
|
||||
<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
|
||||
|
||||
<appender name="console" class="org.apache.log4j.ConsoleAppender">
|
||||
<layout class="org.apache.log4j.EnhancedPatternLayout">
|
||||
<param name="ConversionPattern" value="%d{HH:mm:ss} [%-5p](%-35c{1.}:%-3L) %m%n" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<appender name="dailyRollingFile" class="org.apache.log4j.DailyRollingFileAppender">
|
||||
<param name="file" value="${pinpoint.log}/pinpoint.log" />
|
||||
<param name="Append" value="true" />
|
||||
<param name="DatePattern" value="'.'yyyy-MM-dd"/>
|
||||
|
||||
<layout class="org.apache.log4j.EnhancedPatternLayout">
|
||||
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} [%-5p](%-35c{1.}) %m%n" />
|
||||
</layout>
|
||||
|
||||
</appender>
|
||||
|
||||
|
||||
|
||||
<logger name="com.navercorp.pinpoint" additivity="false">
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="console" />
|
||||
</logger>
|
||||
|
||||
<logger name="org.jboss.netty" additivity="false">
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="console" />
|
||||
</logger>
|
||||
|
||||
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
</log4j:configuration>
|
||||
Reference in New Issue
Block a user