diff --git a/acceptance-test/TraceTarget.java b/acceptance-test/TraceTarget.java index 08e84cf..4d2a6e8 100644 --- a/acceptance-test/TraceTarget.java +++ b/acceptance-test/TraceTarget.java @@ -16,11 +16,14 @@ import java.io.ByteArrayOutputStream; import java.io.InputStream; +import java.lang.ArrayStoreException; +import java.util.Arrays; public class TraceTarget { public static void main(String[] args) throws Exception { Object o = loadClass(); + Arrays.asList(1,2).size(); while (true) { addOne(0); diff --git a/src/main/java/com/github/zhongl/housemd/duck/Duck.java b/src/main/java/com/github/zhongl/housemd/duck/Duck.java index ac474a9..584fc46 100644 --- a/src/main/java/com/github/zhongl/housemd/duck/Duck.java +++ b/src/main/java/com/github/zhongl/housemd/duck/Duck.java @@ -21,6 +21,7 @@ import java.lang.reflect.Array; import java.net.URL; import java.net.URLClassLoader; +import java.util.jar.JarFile; /** * @author zhongl @@ -32,6 +33,8 @@ public static void agentmain(String arguments, Instrumentation instrumentation) String telephoneClassName = parts[1]; int port = Integer.parseInt(parts[2]); + instrumentation.appendToBootstrapClassLoaderSearch(new JarFile(new File(agentJar.toURI()))); + ClassLoader classLoader = new URLClassLoader(new URL[]{agentJar}) { @Override protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { diff --git a/src/main/scala/com/github/zhongl/housemd/instrument/Transform.scala b/src/main/scala/com/github/zhongl/housemd/instrument/Transform.scala index 90c0438..b4bc668 100644 --- a/src/main/scala/com/github/zhongl/housemd/instrument/Transform.scala +++ b/src/main/scala/com/github/zhongl/housemd/instrument/Transform.scala @@ -52,9 +52,9 @@ class Transform extends ((Instrumentation, Filter, Seconds, Int, Loggable, Hook) def isNotInterface = skipClass("") { _.isInterface } @inline - def isNotFromBootClassLoader = skipClass("loaded from bootclassloader") { isFromBootClassLoader(_) } + def isNotThreadLocalOrInternal = skipClass("because tracing it could cause stack overflow") { _.getName.startsWith("java.lang.ThreadLocal") } - filter(c) && isNotBelongsHouseMD && isNotInterface //&& isNotFromBootClassLoader + filter(c) && isNotBelongsHouseMD && isNotInterface && isNotThreadLocalOrInternal } if (candidates.isEmpty) { @@ -138,7 +138,6 @@ class Transform extends ((Instrumentation, Filter, Seconds, Int, Loggable, Hook) } } - private def loadOrDefineAdviceClassFrom(loader: ClassLoader): Class[_] = loadOrDefine(classOf[Advice], loader) private def advice(limit: Int) = new Advice() { diff --git a/src/main/scala/com/github/zhongl/housemd/misc/ReflectionUtils.scala b/src/main/scala/com/github/zhongl/housemd/misc/ReflectionUtils.scala index 2b16066..585a679 100644 --- a/src/main/scala/com/github/zhongl/housemd/misc/ReflectionUtils.scala +++ b/src/main/scala/com/github/zhongl/housemd/misc/ReflectionUtils.scala @@ -79,7 +79,8 @@ object ReflectionUtils { def loadOrDefine(clazz: Class[_], inClassLoader: ClassLoader) = { val name = clazz.getName try { - inClassLoader.loadClass(name) + val loader = Option(inClassLoader) getOrElse Thread.currentThread().getContextClassLoader + loader.loadClass(name) } catch { case e: ClassNotFoundException => import Utils._ diff --git a/src/test/scala/com/github/zhongl/housemd/command/TransformCommandSpec.scala b/src/test/scala/com/github/zhongl/housemd/command/TransformCommandSpec.scala index 84ed4a2..c79fe96 100644 --- a/src/test/scala/com/github/zhongl/housemd/command/TransformCommandSpec.scala +++ b/src/test/scala/com/github/zhongl/housemd/command/TransformCommandSpec.scala @@ -102,9 +102,9 @@ class TransformCommandSpec extends FunSpec with ShouldMatchers with AdviceReflec } } - ignore("should not probe class loaded by boot classloader") { + it("should probe class loaded by boot classloader") { parseAndRun("String") { out => - out.split("\n").head should be("WARN : Skip " + classOf[String] + " loaded from bootclassloader") + out.split("\n").head should be("INFO : Probe " + classOf[String]) } } @@ -126,6 +126,15 @@ class TransformCommandSpec extends FunSpec with ShouldMatchers with AdviceReflec } } + it("should not probe classes ThreadLocal") { + parseAndRun("ThreadLocal") { out => + out.split("\n") should { + contain("WARN : Skip " + classOf[ThreadLocal] + " because tracing it could cause stack overflow.") + contain("No matched class") + } + } + } + it("should probe F by I+") { parseAndRun("-l 1 I+") { out => val withoutInfo = out.split("\n").filter(!_.startsWith("INFO"))