From 4631f252a938cbc65a1d219bf68bdde2c7305e06 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 10:44:37 +0100 Subject: [PATCH 01/11] create agent boostrap module --- apm-agent-bootstrap/pom.xml | 136 ++++++++++++++++++ .../dispatcher/IndyBootstrapDispatcher.java | 78 ++++++++++ .../bootstrap/modulesetter/ModuleSetter.java | 45 ++++++ 3 files changed, 259 insertions(+) create mode 100644 apm-agent-bootstrap/pom.xml create mode 100644 apm-agent-bootstrap/src/main/java/bootstrap/dispatcher/IndyBootstrapDispatcher.java create mode 100644 apm-agent-bootstrap/src/main/java/bootstrap/modulesetter/ModuleSetter.java diff --git a/apm-agent-bootstrap/pom.xml b/apm-agent-bootstrap/pom.xml new file mode 100644 index 0000000000..e8b34df800 --- /dev/null +++ b/apm-agent-bootstrap/pom.xml @@ -0,0 +1,136 @@ + + + 4.0.0 + + + apm-agent-parent + co.elastic.apm + 1.28.2-SNAPSHOT + + + apm-agent-bootstrap + ${project.groupId}:${project.artifactId} + + + true + + ${project.basedir}/.. + + + true + + ${project.basedir}/target/tmp + + + + + + maven-compiler-plugin + + + compile-java7 + + compile + + + + bootstrap/java7/**/*.java + + + bootstrap/java9 + + + + + compile-java9 + + compile + + + 9 + 9 + + bootstrap/java9/**/*.java + + + bootstrap/java7 + + + + + + + maven-shade-plugin + + + shade-classes + package + + shade + + + + + + + + bootstrap.dispatcher + java.lang + + + + bootstrap.modulesetter + co.elastic.apm.agent.modulesetter + + + + + + maven-antrun-plugin + + + rename-classes + package + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apm-agent-bootstrap/src/main/java/bootstrap/dispatcher/IndyBootstrapDispatcher.java b/apm-agent-bootstrap/src/main/java/bootstrap/dispatcher/IndyBootstrapDispatcher.java new file mode 100644 index 0000000000..0db91c4ac6 --- /dev/null +++ b/apm-agent-bootstrap/src/main/java/bootstrap/dispatcher/IndyBootstrapDispatcher.java @@ -0,0 +1,78 @@ +package bootstrap.dispatcher; +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.lang.invoke.CallSite; +import java.lang.invoke.ConstantCallSite; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Array; +import java.lang.reflect.Method; + +@SuppressWarnings("unused") +public class IndyBootstrapDispatcher { + + public static Method bootstrap; + + private static final MethodHandle VOID_NOOP; + + static { + try { + VOID_NOOP = MethodHandles.publicLookup().findStatic(IndyBootstrapDispatcher.class, "voidNoop", MethodType.methodType(void.class)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static CallSite bootstrap(MethodHandles.Lookup lookup, + String adviceMethodName, + MethodType adviceMethodType, + Object... args) { + CallSite callSite = null; + if (bootstrap != null) { + try { + callSite = (CallSite) bootstrap.invoke(null, + lookup, + adviceMethodName, + adviceMethodType, + args); + } catch (Exception e) { + e.printStackTrace(); + } + } + if (callSite == null) { + Class returnType = adviceMethodType.returnType(); + MethodHandle noopNoArg; + if (returnType == void.class) { + noopNoArg = VOID_NOOP; + } else if (!returnType.isPrimitive()) { + noopNoArg = MethodHandles.constant(returnType, null); + } else { + noopNoArg = MethodHandles.constant(returnType, Array.get(Array.newInstance(returnType, 1), 0)); + } + MethodHandle noop = MethodHandles.dropArguments(noopNoArg, 0, adviceMethodType.parameterList()); + callSite = new ConstantCallSite(noop); + } + return callSite; + } + + public static void voidNoop() { + } +} diff --git a/apm-agent-bootstrap/src/main/java/bootstrap/modulesetter/ModuleSetter.java b/apm-agent-bootstrap/src/main/java/bootstrap/modulesetter/ModuleSetter.java new file mode 100644 index 0000000000..39b7c33111 --- /dev/null +++ b/apm-agent-bootstrap/src/main/java/bootstrap/modulesetter/ModuleSetter.java @@ -0,0 +1,45 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package bootstrap.modulesetter; + +import sun.misc.Unsafe; + +import java.lang.reflect.Field; + +/** + * Overrides the module assigned to the class in with the {@code java.base} module. + *

+ * NOTE: This class is compiled with Java 9 so it must only be loaded though reflection and only when running on Java 9. + * In addition, since it relies on the {@link Unsafe} API, it must be loaded by the bootstrap or platform class loaders. + */ +@SuppressWarnings("unused") +public class ModuleSetter { + + public static void setJavaBaseModule(Class targetClass) throws Exception { + + Field moduleField = Class.class.getDeclaredField("module"); + if (moduleField.getType() == Module.class) { + Module javaBaseModule = Class.class.getModule(); + Unsafe unsafe = Unsafe.getUnsafe(); + unsafe.putObject(targetClass, unsafe.objectFieldOffset(moduleField), javaBaseModule); + } else { + throw new IllegalStateException("Unexpected module field type: " + moduleField.getType().getName()); + } + } +} From 2923b3eecaf971e7ff9b8d709b28acdd92d5ff33 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 10:45:59 +0100 Subject: [PATCH 02/11] remove previous dispatcher + setter --- .../bootstrap/IndyBootstrapDispatcher.clazz | Bin 2899 -> 0 bytes .../bootstrap/IndyBootstrapDispatcher.java | 76 ------------------ apm-indy-bootstrap-module/pom.xml | 28 ------- .../IndyBootstrapDispatcherModuleSetter.java | 44 ---------- 4 files changed, 148 deletions(-) delete mode 100644 apm-agent-core/src/main/resources/bootstrap/IndyBootstrapDispatcher.clazz delete mode 100644 apm-agent-core/src/main/resources/bootstrap/IndyBootstrapDispatcher.java delete mode 100644 apm-indy-bootstrap-module/pom.xml delete mode 100644 apm-indy-bootstrap-module/src/main/java/co/elastic/apm/agent/bci/IndyBootstrapDispatcherModuleSetter.java diff --git a/apm-agent-core/src/main/resources/bootstrap/IndyBootstrapDispatcher.clazz b/apm-agent-core/src/main/resources/bootstrap/IndyBootstrapDispatcher.clazz deleted file mode 100644 index 4528ca7da9ff6f8df256c44a6451d4b6b3f96ca3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2899 zcma)8SyL2O6#g!=Txc2>KwwbB4Os*+F`CFA20(urYpL%NG3qT_1%bmMFH?4Q{d_snNvn`Iyv(xcCM66yn|7R) zA`{T3Y}<4vaz>$G(!f`JAqzF)EF1|GlOeH`=UVnsn6gE2em!p{Z-nG$7w-_JWPgZM zQkXDuxs>H8Gz2r<6Oy=aFJtCC%dr)%w&UbyoN;$aKyyv6=-SGO!0wQOpAv=u3j*od&WR5OgEHJDqTNyh7J+(} z*M~u1?~8Uq7`1Kf1VT{ihSrdpkHhG|7@=rNc}8aCijnulBo-wy5~n4y5=^ds&9SmG zK3esonOvzGwUkqIGv-B0_1?a1n(DZMMaO=0>*&N@Vp7E^D7VCI9ZOgiNK{$Rm7Rc8 zd6k0eu$0+B+>uz(k;9OVedyA$3R}X_k;exTu8smc9Yw6^xQlx_*72dh!K%TsGsiA? zhV7McR8fDV<70fXMS7b=b==3NIzGeaJo{DK*NV1ht(u{j_u~tJo~p#ZwAvQ5g05oa zw^0rHYiE_~*H@scN~z&Wprgv)I;VIv0tJCH;lp1#r8PPkg2)r(^zbacJC!U}BOsSXxli}C{ zXQ4x|{m2PUcV!5-S6!B28h2e|odMeB-6_9yRB}gObT<`Fw}MM#$@Bzz!{Q}gZTY6W z;d0b?raNsFsM%abvFKU3VMS91IqN!kj=$onX?w)sYS?@YsFG6w7F8SJSZgT=9QrSt z>XOp)#l@VJDPJc2y%8;Jgj*hustw2@dMwgH)l{*L*<4b-de$7uKtjgQHUKSZzMH-3X1 ziI~`gu1Kv33Pm^36xqZMpO%P6sJwF%yGG`o`-6Eu%R6VdM(TLbzzo8wGX<#Hao zxb7nyUF39=ca+>CIL=?Flg#BcQpRu$7fGGL5EjTWZ~`t~=43s|j8FMEK=4aR?@%o==W5(l^VkfAr z9>37MTDT1geTHQ`UlGguJpvruL`!pP^Bz`b6Kxx4{{h-VG+lm*jx^gP@yjDWgBE&; zGiqh7jd1|YXu%%tTZlp{4sciQqjtYG1C&vjNYpJb=mw@g!OuEOqL*)tW_$R*dlZR( E02>GOv;Y7A diff --git a/apm-agent-core/src/main/resources/bootstrap/IndyBootstrapDispatcher.java b/apm-agent-core/src/main/resources/bootstrap/IndyBootstrapDispatcher.java deleted file mode 100644 index 317ff6637f..0000000000 --- a/apm-agent-core/src/main/resources/bootstrap/IndyBootstrapDispatcher.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package java.lang; - -import java.lang.invoke.CallSite; -import java.lang.invoke.ConstantCallSite; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.reflect.Array; -import java.lang.reflect.Method; - -public class IndyBootstrapDispatcher { - public static Method bootstrap; - - private static final MethodHandle VOID_NOOP; - - static { - try { - VOID_NOOP = MethodHandles.publicLookup().findStatic(IndyBootstrapDispatcher.class, "voidNoop", MethodType.methodType(void.class)); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static CallSite bootstrap(MethodHandles.Lookup lookup, - String adviceMethodName, - MethodType adviceMethodType, - Object... args) { - CallSite callSite = null; - if (bootstrap != null) { - try { - callSite = (CallSite) bootstrap.invoke(null, - lookup, - adviceMethodName, - adviceMethodType, - args); - } catch (Exception e) { - e.printStackTrace(); - } - } - if (callSite == null) { - Class returnType = adviceMethodType.returnType(); - MethodHandle noopNoArg; - if (returnType == void.class) { - noopNoArg = VOID_NOOP; - } else if (!returnType.isPrimitive()) { - noopNoArg = MethodHandles.constant(returnType, null); - } else { - noopNoArg = MethodHandles.constant(returnType, Array.get(Array.newInstance(returnType, 1), 0)); - } - MethodHandle noop = MethodHandles.dropArguments(noopNoArg, 0, adviceMethodType.parameterList()); - callSite = new ConstantCallSite(noop); - } - return callSite; - } - - public static void voidNoop() { - } -} diff --git a/apm-indy-bootstrap-module/pom.xml b/apm-indy-bootstrap-module/pom.xml deleted file mode 100644 index feefee45d3..0000000000 --- a/apm-indy-bootstrap-module/pom.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - 4.0.0 - - - apm-agent-parent - co.elastic.apm - 1.28.2-SNAPSHOT - - - apm-indy-bootstrap-module - ${project.groupId}:${project.artifactId} - - - true - - ${project.basedir}/.. - - 9 - - - ${maven.compiler.target} - - - true - - diff --git a/apm-indy-bootstrap-module/src/main/java/co/elastic/apm/agent/bci/IndyBootstrapDispatcherModuleSetter.java b/apm-indy-bootstrap-module/src/main/java/co/elastic/apm/agent/bci/IndyBootstrapDispatcherModuleSetter.java deleted file mode 100644 index f0a01e49a8..0000000000 --- a/apm-indy-bootstrap-module/src/main/java/co/elastic/apm/agent/bci/IndyBootstrapDispatcherModuleSetter.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package co.elastic.apm.agent.bci; - -import sun.misc.Unsafe; - -import java.lang.reflect.Field; - -/** - * Overrides the module assigned to the class in with the {@code java.base} module. - *

- * NOTE: This class is compiled with Java 9 so it must only be loaded though reflection and only when running on Java 9. - * In addition, since it relies on the {@link Unsafe} API, it must be loaded by the bootstrap or platform class loaders. - */ -@SuppressWarnings("unused") -public class IndyBootstrapDispatcherModuleSetter { - - public static void setJavaBaseModule(Class indyBootstrapDispatcherClass) throws Exception { - Field moduleField = Class.class.getDeclaredField("module"); - if (moduleField.getType() == Module.class) { - Module javaBaseModule = Class.class.getModule(); - Unsafe unsafe = Unsafe.getUnsafe(); - unsafe.putObject(indyBootstrapDispatcherClass, unsafe.objectFieldOffset(moduleField), javaBaseModule); - } else { - throw new IllegalStateException("Unexpected module field type: " + moduleField.getType().getName()); - } - } -} From 136ba538882caf074ab3ef57dc1f8bcd2693bb91 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 10:48:36 +0100 Subject: [PATCH 03/11] use new bootstrap module --- apm-agent-core/pom.xml | 5 +- .../elastic/apm/agent/bci/IndyBootstrap.java | 50 ++++++++++++------- .../apm/agent/bci/IndyBootstrapTest.java | 5 -- apm-agent/pom.xml | 4 +- pom.xml | 2 +- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/apm-agent-core/pom.xml b/apm-agent-core/pom.xml index d8609e4e2c..ae19d57920 100644 --- a/apm-agent-core/pom.xml +++ b/apm-agent-core/pom.xml @@ -93,10 +93,11 @@ ${project.groupId} - apm-indy-bootstrap-module + apm-agent-bootstrap ${project.version} - test + runtime + com.squareup.okhttp3 okhttp diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java index 5902a50ed0..d2aae1b2ba 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java @@ -168,19 +168,28 @@ public class IndyBootstrap { /** - * Starts with {@code java.lang} so that OSGi class loaders don't restrict access to it + * Starts with {@code java.lang} so that OSGi class loaders don't restrict access to it. + * This also allows to load it in {@code java.base} module on Java9+ for Hotspot, Open J9 requires {@code ModuleSetter} */ private static final String INDY_BOOTSTRAP_CLASS_NAME = "java.lang.IndyBootstrapDispatcher"; + + /** + * The class file of {@code IndyBootstrapDispatcher}, loaded from classpath resource, {@code esclazz} extension avoids + * being loaded as a regular class. + */ + private static final String INDY_BOOTSTRAP_RESOURCE = "bootstrap/java/lang/IndyBootstrapDispatcher.esclazz"; + /** * Needs to be loaded from the bootstrap CL because it uses {@code sun.misc.Unsafe}. * In addition, needs to be loaded explicitly by name only when running on Java 9, because compiled with Java 9 */ - private static final String INDY_BOOTSTRAP_MODULE_SETTER_CLASS_NAME = "co.elastic.apm.agent.bci.IndyBootstrapDispatcherModuleSetter"; + private static final String INDY_BOOTSTRAP_MODULE_SETTER_CLASS_NAME = "co.elastic.apm.agent.modulesetter.ModuleSetter"; + /** - * The class file of {@code java.lang.IndyBootstrapDispatcher}. - * Ends with {@code clazz} because if it ended with {@code class}, it would be loaded like a regular class. + * The class file of {@code ModuleSetter}, loaded from classpath resource, {@code esclazz} extension avoids being + * loaded as a regular class. */ - private static final String INDY_BOOTSTRAP_RESOURCE = "bootstrap/IndyBootstrapDispatcher.clazz"; + private static final String INDY_BOOTSTRAP_MODULE_SETTER_RESOURCE = "bootstrap/co/elastic/apm/agent/modulesetter/ModuleSetter.esclazz"; /** * The name of the class we use as the lookup class during the invokedynamic bootstrap flow. The bytecode of this @@ -220,17 +229,7 @@ public static Method getIndyBootstrapMethod(final Logger logger) { * Injects the {@code java.lang.IndyBootstrapDispatcher} class into the bootstrap class loader if it wasn't already. */ private static Class initIndyBootstrap(final Logger logger) throws Exception { - Class indyBootstrapDispatcherClass; - try { - indyBootstrapDispatcherClass = Class.forName(INDY_BOOTSTRAP_CLASS_NAME, false, null); - } catch (ClassNotFoundException e) { - byte[] bootstrapClass = IOUtils.readToBytes(ElasticApmAgent.getAgentClassLoader().getResourceAsStream(INDY_BOOTSTRAP_RESOURCE)); - if (bootstrapClass == null || bootstrapClass.length == 0) { - throw new IllegalStateException("Could not locate " + INDY_BOOTSTRAP_RESOURCE); - } - ClassInjector.UsingUnsafe.ofBootLoader().injectRaw(Collections.singletonMap(INDY_BOOTSTRAP_CLASS_NAME, bootstrapClass)); - indyBootstrapDispatcherClass = Class.forName(INDY_BOOTSTRAP_CLASS_NAME, false, null); - } + Class indyBootstrapDispatcherClass = loadClassInBootstrap(INDY_BOOTSTRAP_CLASS_NAME, INDY_BOOTSTRAP_RESOURCE); if (JvmRuntimeInfo.ofCurrentVM().getMajorVersion() >= 9 && JvmRuntimeInfo.ofCurrentVM().isJ9VM()) { try { @@ -243,6 +242,22 @@ private static Class initIndyBootstrap(final Logger logger) throws Exception return indyBootstrapDispatcherClass; } + private static Class loadClassInBootstrap(String className, String resourceName) throws IOException, ClassNotFoundException { + Class bootstrapClass; + try { + bootstrapClass = Class.forName(className, false, null); + } catch (ClassNotFoundException e) { + byte[] classBytes = IOUtils.readToBytes(ElasticApmAgent.getAgentClassLoader().getResourceAsStream(resourceName)); + if (classBytes == null || classBytes.length == 0) { + throw new IllegalStateException("Could not locate " + resourceName); + } + ClassInjector.UsingUnsafe.ofBootLoader().injectRaw(Collections.singletonMap(className, classBytes)); + bootstrapClass = Class.forName(className, false, null); + } + return bootstrapClass; + } + + /** * A package-private method for unit-testing of the module overriding functionality * @@ -252,7 +267,8 @@ private static Class initIndyBootstrap(final Logger logger) throws Exception static void setJavaBaseModule(Class targetClass) throws Throwable { // In order to override the original unnamed module assigned to the IndyBootstrapDispatcher, we rely on the // Unsafe API, which requires the caller to be loaded by the Bootstrap CL - Class moduleSetterClass = Class.forName(INDY_BOOTSTRAP_MODULE_SETTER_CLASS_NAME, false, null); + + Class moduleSetterClass = loadClassInBootstrap(INDY_BOOTSTRAP_MODULE_SETTER_CLASS_NAME, INDY_BOOTSTRAP_MODULE_SETTER_RESOURCE); MethodHandles.lookup() .findStatic(moduleSetterClass, "setJavaBaseModule", MethodType.methodType(void.class, Class.class)) .invoke(targetClass); diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/bci/IndyBootstrapTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/bci/IndyBootstrapTest.java index d23d39741a..1ca8b9466e 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/bci/IndyBootstrapTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/bci/IndyBootstrapTest.java @@ -19,12 +19,7 @@ package co.elastic.apm.agent.bci; import co.elastic.apm.agent.AbstractInstrumentationTest; -import net.bytebuddy.dynamic.loading.ClassInjector; import org.junit.jupiter.api.Test; -import org.stagemonitor.util.IOUtils; - -import java.io.InputStream; -import java.util.Collections; import static org.assertj.core.api.Assertions.assertThat; diff --git a/apm-agent/pom.xml b/apm-agent/pom.xml index 25d35b8025..359e872399 100644 --- a/apm-agent/pom.xml +++ b/apm-agent/pom.xml @@ -35,8 +35,8 @@ ${project.version} - ${project.groupId} - apm-indy-bootstrap-module + co.elastic.apm + apm-agent-bootstrap ${project.version} diff --git a/pom.xml b/pom.xml index f0a6f5a93a..510cc03f70 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,7 @@ integration-tests apm-agent-attach apm-agent-plugin-sdk - apm-indy-bootstrap-module + apm-agent-bootstrap apm-agent apm-agent-attach-cli apm-agent-common From a9143cf03f761e8461c797eade5d41da74da9abb Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 10:51:23 +0100 Subject: [PATCH 04/11] simplify test --- .../java/co/elastic/apm/agent/bci/IndyBootstrapTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apm-agent-core/src/test/java/co/elastic/apm/agent/bci/IndyBootstrapTest.java b/apm-agent-core/src/test/java/co/elastic/apm/agent/bci/IndyBootstrapTest.java index 1ca8b9466e..5139cf7014 100644 --- a/apm-agent-core/src/test/java/co/elastic/apm/agent/bci/IndyBootstrapTest.java +++ b/apm-agent-core/src/test/java/co/elastic/apm/agent/bci/IndyBootstrapTest.java @@ -30,12 +30,6 @@ void testSetJavaBaseModule() throws Throwable { Module javaBaseModule = Class.class.getModule(); assertThat(IndyBootstrapTest.class.getModule()).isNotEqualTo(javaBaseModule); - // In order to test this functionality, IndyBootstrapDispatcherModuleSetter needs to be loaded from the Boot CL. - // We don't mind loading it with the test's class loader as well only to get it's class file - InputStream classFileAsStream = IndyBootstrapDispatcherModuleSetter.class.getResourceAsStream("IndyBootstrapDispatcherModuleSetter.class"); - byte[] bootstrapClass = IOUtils.readToBytes(classFileAsStream); - ClassInjector.UsingUnsafe.ofBootLoader().injectRaw(Collections.singletonMap(IndyBootstrapDispatcherModuleSetter.class.getName(), bootstrapClass)); - IndyBootstrap.setJavaBaseModule(IndyBootstrapTest.class); assertThat(IndyBootstrapTest.class.getModule()).isEqualTo(javaBaseModule); } From 2f206eb2db97a37b8aaeeca60e4e6e9a8150a558 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 10:51:45 +0100 Subject: [PATCH 05/11] use single version of antrun plugin --- elastic-apm-agent/pom.xml | 1 - pom.xml | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/elastic-apm-agent/pom.xml b/elastic-apm-agent/pom.xml index 993e018fd1..0c6d6d6d51 100644 --- a/elastic-apm-agent/pom.xml +++ b/elastic-apm-agent/pom.xml @@ -106,7 +106,6 @@ maven-antrun-plugin - 3.0.0 shade-cached-lookup-key diff --git a/pom.xml b/pom.xml index 510cc03f70..7e5406a561 100644 --- a/pom.xml +++ b/pom.xml @@ -514,6 +514,10 @@ maven-site-plugin 3.8.2 + + maven-antrun-plugin + 3.0.0 + From 9d796327662cb328fc01b074d9b7fe371c9fe9dd Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 11:00:43 +0100 Subject: [PATCH 06/11] update comment in OpenJ9 tests --- .../src/test/java/co/elastic/apm/servlet/TomcatIT.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java index c48a5ee0bf..49f77b0880 100644 --- a/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java @@ -48,7 +48,7 @@ public static Iterable data() { {"9-jre11-slim"}, {"9.0.39-jdk14-openjdk-oracle"}, {"jdk8-adoptopenjdk-openj9"}, - // TODO openj9 on JDK11 has an access problem from java.base + // TODO openj9 on JDK11 seems unable to capture system.container //{"jdk11-adoptopenjdk-openj9"}, //{"9.0.50-jdk11-adoptopenjdk-openj9"} }); From 677d7bb2b2b99b3b72f893b7346cd9294adc3711 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 11:46:39 +0100 Subject: [PATCH 07/11] fix java7 compatibility --- apm-agent-bootstrap/pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apm-agent-bootstrap/pom.xml b/apm-agent-bootstrap/pom.xml index e8b34df800..a01aba4788 100644 --- a/apm-agent-bootstrap/pom.xml +++ b/apm-agent-bootstrap/pom.xml @@ -35,10 +35,10 @@ - bootstrap/java7/**/*.java + bootstrap/dispatcher/**/*.java - bootstrap/java9 + bootstrap/modulesetter @@ -51,10 +51,10 @@ 9 9 - bootstrap/java9/**/*.java + bootstrap/modulesetter/**/*.java - bootstrap/java7 + bootstrap/dispatcher From 519914ed16a9c87b242f3cd94257564e0b744186 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 15:31:42 +0100 Subject: [PATCH 08/11] fix minor details --- apm-agent/pom.xml | 2 +- .../src/test/java/co/elastic/apm/servlet/TomcatIT.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/apm-agent/pom.xml b/apm-agent/pom.xml index 359e872399..76dfcd2f77 100644 --- a/apm-agent/pom.xml +++ b/apm-agent/pom.xml @@ -35,7 +35,7 @@ ${project.version} - co.elastic.apm + ${project.groupId} apm-agent-bootstrap ${project.version} diff --git a/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java index 49f77b0880..7ff8a75947 100644 --- a/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java +++ b/integration-tests/application-server-integration-tests/src/test/java/co/elastic/apm/servlet/TomcatIT.java @@ -48,9 +48,8 @@ public static Iterable data() { {"9-jre11-slim"}, {"9.0.39-jdk14-openjdk-oracle"}, {"jdk8-adoptopenjdk-openj9"}, - // TODO openj9 on JDK11 seems unable to capture system.container - //{"jdk11-adoptopenjdk-openj9"}, - //{"9.0.50-jdk11-adoptopenjdk-openj9"} + {"jdk11-adoptopenjdk-openj9"}, + {"9.0.50-jdk11-adoptopenjdk-openj9"} }); } From 12e5da00cf1690c6756efa0053e5181e4167effa Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Tue, 14 Dec 2021 15:33:56 +0100 Subject: [PATCH 09/11] update changelog --- CHANGELOG.asciidoc | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc index 9c11a8f583..f7e5fd3835 100644 --- a/CHANGELOG.asciidoc +++ b/CHANGELOG.asciidoc @@ -28,6 +28,7 @@ endif::[] [float] ===== Bug fixes +* Fix module loading errors on J9 JVM - {pull}2341[#2341] [[release-notes-1.x]] === Java Agent version 1.x From 5cbc724f290fd86c1e039226446f1635095b588a Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Wed, 15 Dec 2021 10:06:40 +0100 Subject: [PATCH 10/11] add comments to clarify bootstrap class inj. --- .../elastic/apm/agent/bci/IndyBootstrap.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java index d2aae1b2ba..efb2472fb2 100644 --- a/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java +++ b/apm-agent-core/src/main/java/co/elastic/apm/agent/bci/IndyBootstrap.java @@ -242,9 +242,29 @@ private static Class initIndyBootstrap(final Logger logger) throws Exception return indyBootstrapDispatcherClass; } + /** + * Loads a class from classpath resource in bootstrap classloader. + *

+ * Ensuring that classes loaded through this method can ONLY be loaded in the bootstrap CL requires the following: + *

+ * + * @param className class name + * @param resourceName class resource name + * @return class loaded in bootstrap classloader + * @throws IOException if unable to open provided resource + * @throws ClassNotFoundException if unable to load class in bootstrap CL + */ private static Class loadClassInBootstrap(String className, String resourceName) throws IOException, ClassNotFoundException { Class bootstrapClass; try { + // Will return non-null value only if the class has already been loaded. + // Ensuring that a class can ONLY be loaded through this method and not from regular classloading relies + // on applying the listed instructions in method documentation bootstrapClass = Class.forName(className, false, null); } catch (ClassNotFoundException e) { byte[] classBytes = IOUtils.readToBytes(ElasticApmAgent.getAgentClassLoader().getResourceAsStream(resourceName)); From 7757a939707ce97a185c482d07c6c40b751f87e6 Mon Sep 17 00:00:00 2001 From: Sylvain Juge Date: Wed, 15 Dec 2021 10:33:12 +0100 Subject: [PATCH 11/11] check-in packaged resources + more doc comments --- apm-agent-bootstrap/pom.xml | 8 +++++--- .../dispatcher/IndyBootstrapDispatcher.java | 9 +++++++++ .../bootstrap/modulesetter/ModuleSetter.java | 8 ++++++++ .../apm/agent/modulesetter/ModuleSetter.esclazz | Bin 0 -> 1912 bytes .../java/lang/IndyBootstrapDispatcher.esclazz | Bin 0 -> 2899 bytes 5 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 apm-agent-bootstrap/src/main/resources/bootstrap/co/elastic/apm/agent/modulesetter/ModuleSetter.esclazz create mode 100644 apm-agent-bootstrap/src/main/resources/bootstrap/java/lang/IndyBootstrapDispatcher.esclazz diff --git a/apm-agent-bootstrap/pom.xml b/apm-agent-bootstrap/pom.xml index a01aba4788..cf5893c2cb 100644 --- a/apm-agent-bootstrap/pom.xml +++ b/apm-agent-bootstrap/pom.xml @@ -115,10 +115,12 @@ - + + diff --git a/apm-agent-bootstrap/src/main/java/bootstrap/dispatcher/IndyBootstrapDispatcher.java b/apm-agent-bootstrap/src/main/java/bootstrap/dispatcher/IndyBootstrapDispatcher.java index 0db91c4ac6..fdb50c59d4 100644 --- a/apm-agent-bootstrap/src/main/java/bootstrap/dispatcher/IndyBootstrapDispatcher.java +++ b/apm-agent-bootstrap/src/main/java/bootstrap/dispatcher/IndyBootstrapDispatcher.java @@ -26,6 +26,15 @@ import java.lang.reflect.Array; import java.lang.reflect.Method; +/** + * Indy bootstrap dispatcher + *

+ * IMPORTANT: This class is relocated in a different package and stored as a classpath resource to be injected into bootstrap classloader. + * A copy of this resource is stored in 'src/main/resources' and should be updated by running 'mvn clean package' whenever + * this class is being modified. This has only an effect when running code/tests in the IDE as the resources are loaded + * from the project classpath and not the packaged artifact. + *

+ */ @SuppressWarnings("unused") public class IndyBootstrapDispatcher { diff --git a/apm-agent-bootstrap/src/main/java/bootstrap/modulesetter/ModuleSetter.java b/apm-agent-bootstrap/src/main/java/bootstrap/modulesetter/ModuleSetter.java index 39b7c33111..80573f0148 100644 --- a/apm-agent-bootstrap/src/main/java/bootstrap/modulesetter/ModuleSetter.java +++ b/apm-agent-bootstrap/src/main/java/bootstrap/modulesetter/ModuleSetter.java @@ -27,7 +27,15 @@ *

* NOTE: This class is compiled with Java 9 so it must only be loaded though reflection and only when running on Java 9. * In addition, since it relies on the {@link Unsafe} API, it must be loaded by the bootstrap or platform class loaders. + *

+ *

+ * IMPORTANT: This class is relocated in a different package and stored as a classpath resource to be injected into bootstrap classloader. + * A copy of this resource is stored in 'src/main/resources' and should be updated by running 'mvn clean package' whenever + * this class is being modified. This has only an effect when running code/tests in the IDE as the resources are loaded + * from the project classpath and not the packaged artifact. + *

*/ + @SuppressWarnings("unused") public class ModuleSetter { diff --git a/apm-agent-bootstrap/src/main/resources/bootstrap/co/elastic/apm/agent/modulesetter/ModuleSetter.esclazz b/apm-agent-bootstrap/src/main/resources/bootstrap/co/elastic/apm/agent/modulesetter/ModuleSetter.esclazz new file mode 100644 index 0000000000000000000000000000000000000000..b73dbacd2f948be6297e87721f66cc33d47d913b GIT binary patch literal 1912 zcmb7EZBr9h6n-us8)6g;XiBjXEnpIbwJ+LgkhY*yXn?i>thH~K%_XdCb~C#-j{cMW zg7$O2U`J=#5B=8P)amrOyQ$e&#+fFw_vPGk&V9~v&bfd7{rooo*YShEf)m)vlaY2E zTee%aY${*dt)S8IRHU?4p}i4r>hZ>c5Ey$TA4}Vle$(FCd!!s~VNl>qT5rLq2+a00 zUH@@#sO$};4}!)$={M+qrWOQ;owkKxfeWu!wU7}QPV~80bbVJZ2@ICXyE&XhE{h?Y z5*X44ZX|H6_W#1F55*!5ieXsq`J?crsLtRabcpf%)_`bsf5Xvsz983e~BQT+Ct`m-_OYFk)dwV1)KPg3=xm zDUrB3TW;joJANehm4!;;A=xGvUeTe0tC-K?3Kp1_Ag-`D#;yH*CQ0CY znwY)-tL60^uHhYH{4OtQcXU#r0;RN3BCM{b*zAf-IlYhT#=#AN=^l}5o~N49t81xM zDz_gdgl@_f37zO8w41UVZlP-ESfsxlUp;9vX{u37l3(06$u4Rp1bcmdesyIUA!qtpP{LlW7Hp} z^#A2BCF;6Zk)Bs~wPJ3Uv696nxHCG8y8?4*pvM&XOA?pyX`YYPJ%O{wnZ&QadKNeF znZRkoV7ig>DMZ~WW&3sFl4On5UadfZlUjx>^tdUQ*pz)NG7WDGd#Os=hlWXByFEOa z(&(>LzEvwhgGDo1bA7ehY3-?STkd(3l%}{zBQp z^f(NNOUQ7X;W*1n=h$=bWK@mETAI082~( Ae*gdg literal 0 HcmV?d00001 diff --git a/apm-agent-bootstrap/src/main/resources/bootstrap/java/lang/IndyBootstrapDispatcher.esclazz b/apm-agent-bootstrap/src/main/resources/bootstrap/java/lang/IndyBootstrapDispatcher.esclazz new file mode 100644 index 0000000000000000000000000000000000000000..544cd281f8531da9d2afd6e4c9ffe479ecb7cae8 GIT binary patch literal 2899 zcma)8S#J|p6#j0!+}Jn}5=d}Z!WX&?)WOE$2Z*3d#H_K*y5X58^OkS=tS zDplea^sx`+wNNQUMO~g+ssE@FYWv+8FJqFF`eBwk-#O1rGc-RH9KJ?BN9>^A(l?9g{UnTfdtpwQ`gp z0_SFu6L+R(W@ZHr`hc6TAv!#4n1(YV5a{lii(vq)H-jlv!>jsk1yq#P}~l(x039z(Yhv>iPHQCoLPwyB)ZL$|+< z<9V%E9E#xt`l2|7lLFgo6y_`=Co#Z|NM~j*3GDOGZCD^U<^&zuIl_cxzt>^ zFo`z=wi(4)+gLUnV}&f(b2no+k31Ves}iH6W$O2nZs;s&9p4x`=`UAR=W$F#F$NYTu%MH4m*23A+T8LA zt}4rRxgy(FlFlsN9 zmUYwN7QXIhwMmSjq*vLRH-EC58N_fMH&k6yb+fe6;bjpk+fw3ffy1vN;Z2`+qL{+@?qRA8SWh+B&ZlZ2|{i91rutr%I| zYolpao#pl!mxtC%IB!qw_u=Y-xTB1uG<$(^G-k`=iW_~SMWtwJH>_~yO}mLS4rlY_ zIUOsM=JQ6jaxC;zdci%->cZBaIBb!7SW=?p8?nf7z=qak`d2#FD0|+io#+${tNwB|EEMHu5?;IU$4mGtxjccrfv)Lk&*egCG$!^ZE(j z26z{|hkBo(rAKfHt_q{I=4V-j7G1rieN;TPzTIM?z5%@UJ;q0P;HjO76jn*dJJ*C4$m z=-?dsd5{cZm`@z~xPZ&Jh-r*+o{T}m1Z=K6#1+;k=~k}5TJPf@AtHdK@k)uv(O~-Ni3NYebEHK~CxvKQ? z{Ju}W5iC~4j`OSf2_>}f2|Yy_jVi3*_6X3qj^&ny7L)3%!(PM6k2w1nP1l~|L5A(} z@vl!@KCP@;J2|LYOEk=}tP$6D8^ePHTUo$1bP?2zL+GtGRXfS4(x|5Ug4ZbBNv=f^ J$CvJE=wHJ&`iuYo literal 0 HcmV?d00001