This is an automated email from the ASF dual-hosted git repository. pauls pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git
commit 4aebf335eaf28705c7fdae78ca7a4515075e4ef7 Author: Karl Pauls <karlpa...@gmail.com> AuthorDate: Fri Dec 1 10:15:22 2023 +0100 Add a weaver that allows to weave references to get classloader --- atomosfeaturelauncherweaver/pom.xml | 82 +++++++++++++++ .../launcher/atomos/weaver/AtomosWeaver.java | 25 +++++ .../sling/feature/launcher/atomos/weaver/Test.java | 64 ++++++++++++ .../atomos/weaver/impl/AtomosWeaverImpl.java | 28 +++++ .../atomos/weaver/impl/AtomosWeaverVisitor.java | 115 +++++++++++++++++++++ .../atomos/weaver/impl/StaticToolClassWriter.java | 72 +++++++++++++ .../feature/launcher/atomos/weaver/main/Main.java | 71 +++++++++++++ ...ing.feature.launcher.atomos.weaver.AtomosWeaver | 1 + 8 files changed, 458 insertions(+) diff --git a/atomosfeaturelauncherweaver/pom.xml b/atomosfeaturelauncherweaver/pom.xml new file mode 100644 index 00000000..502f018f --- /dev/null +++ b/atomosfeaturelauncherweaver/pom.xml @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF 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. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~--> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.sling</groupId> + <artifactId>sling-bundle-parent</artifactId> + <version>35</version> + <relativePath/> + </parent> + + <artifactId>org.apache.sling.feature.launcher.atomos.weaver</artifactId> + <name>Apache Sling Atomos feature launcher weaver</name> + <description></description> + <version>0.0.1-SNAPSHOT</version> + <properties> + <sling.java.version>11</sling.java.version> + </properties> + <build> + <plugins> + <plugin> + <groupId>biz.aQute.bnd</groupId> + <artifactId>bnd-baseline-maven-plugin</artifactId> + <configuration> + <failOnMissing>false</failOnMissing> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.rat</groupId> + <artifactId>apache-rat-plugin</artifactId> + <configuration> + <excludes> + <exclude>readme.md</exclude> + <exclude>src/main/resources/META-INF/services/**</exclude> + <exclude>**/*.properties</exclude> + <exclude>launcher/**</exclude> + <exclude>**/*.patch</exclude> + </excludes> + </configuration> + </plugin> + </plugins> + </build> + <dependencies> +<dependency> + <groupId>org.ow2.asm</groupId> + <artifactId>asm</artifactId> + <version>9.4</version> + </dependency> + <dependency> + <groupId>org.ow2.asm</groupId> + <artifactId>asm-commons</artifactId> + <version>9.4</version> + </dependency> + <dependency> + <groupId>org.ow2.asm</groupId> + <artifactId>asm-util</artifactId> + <version>9.4</version> + </dependency> + </dependencies> + +</project> diff --git a/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/AtomosWeaver.java b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/AtomosWeaver.java new file mode 100644 index 00000000..379ff7e0 --- /dev/null +++ b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/AtomosWeaver.java @@ -0,0 +1,25 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF 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 org.apache.sling.feature.launcher.atomos.weaver; + +import java.lang.reflect.Method; + +public interface AtomosWeaver { + byte[] weave(byte[] bytes, String targetClass, String targetMethodClassLoader, String targetMethodResource, String targetMethodStream, ClassLoader cl); +} diff --git a/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/Test.java b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/Test.java new file mode 100644 index 00000000..815ad2e2 --- /dev/null +++ b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/Test.java @@ -0,0 +1,64 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF 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 org.apache.sling.feature.launcher.atomos.weaver; + +import org.apache.sling.feature.launcher.atomos.weaver.impl.AtomosWeaverVisitor; + +import java.util.stream.Stream; + +public class Test { + private static final Class t = AtomosWeaverVisitor.class; + private static final ClassLoader tt = AtomosWeaverVisitor.class.getClassLoader(); + + public Test() { + System.out.println("S" + Test.class.getClassLoader()); + System.out.println("I" + getClass().getClassLoader()); + System.out.println("SS" + Test.class.getResource("/" + Test.class.getName().replace('.', '/') + ".class")); + System.out.println("II" + getClass().getResource("/" + Test.class.getName().replace('.', '/') + ".class")); + + System.out.println("SSS" + Test.class.getResourceAsStream("/" +Test.class.getName().replace('.', '/') + ".class")); + + System.out.println("III" + getClass().getResourceAsStream("/" +Test.class.getName().replace('.', '/') + ".class")); + + foo(Test.class); + bar(Test.class.getClassLoader()); + la(); + } + + private void foo(Class cl) { + System.out.println("FOO: " + cl.getClassLoader()); + ClassLoader loader = cl.getClassLoader(); + + Stream.of(cl).map(l -> l.getClassLoader()).forEach(ll -> { + System.out.println("ll. " + ll); + }); + + System.out.println("fl: " + loader); + } + + private void bar(ClassLoader cl) { + System.out.println("BAR: " + cl); + System.out.println("t: " + t.getClassLoader()); + System.out.println("tt: " + tt); + } + + private static void la() { + System.out.println(Test.class.getClassLoader()); + } +} diff --git a/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/AtomosWeaverImpl.java b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/AtomosWeaverImpl.java new file mode 100644 index 00000000..ec4fc027 --- /dev/null +++ b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/AtomosWeaverImpl.java @@ -0,0 +1,28 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF 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 org.apache.sling.feature.launcher.atomos.weaver.impl; + +import org.apache.sling.feature.launcher.atomos.weaver.AtomosWeaver; + +public class AtomosWeaverImpl implements AtomosWeaver { + @Override + public byte[] weave(byte[] bytes, String targetClass, String targetMethodClassLoader, String targetMethodResource, String targetMethodStream, ClassLoader cl) { + return AtomosWeaverVisitor.weave(bytes, targetClass, targetMethodClassLoader, targetMethodResource, targetMethodStream, cl); + } +} diff --git a/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/AtomosWeaverVisitor.java b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/AtomosWeaverVisitor.java new file mode 100644 index 00000000..349fd8ba --- /dev/null +++ b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/AtomosWeaverVisitor.java @@ -0,0 +1,115 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF 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 org.apache.sling.feature.launcher.atomos.weaver.impl; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +import org.objectweb.asm.Type; +import org.objectweb.asm.commons.GeneratorAdapter; +import org.objectweb.asm.commons.JSRInlinerAdapter; +import org.objectweb.asm.commons.Method; + +import java.io.InputStream; +import java.net.URL; + +public class AtomosWeaverVisitor extends ClassVisitor implements Opcodes { + public static byte[] weave(byte[] bytes, String targetClass, String targetMethodClassLoader, String targetMethodResource, String targetMethodStream, ClassLoader cl) { + ClassReader cr = new ClassReader(bytes); + ClassWriter cw = new StaticToolClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES, cl); + AtomosWeaverVisitor cv = new AtomosWeaverVisitor(cw, + Type.getType("L" + targetClass.replace('.', '/') + ";"), + new Method(targetMethodClassLoader, + Type.getType(ClassLoader.class), + new Type[] {Type.getType(Class.class)} + ),new Method(targetMethodResource, + Type.getType(URL.class), + new Type[] {Type.getType(Class.class),Type.getType(String.class)} + ),new Method(targetMethodStream, + Type.getType(InputStream.class), + new Type[] {Type.getType(Class.class), Type.getType(String.class)} + ) + ); + cr.accept(cv, ClassReader.SKIP_FRAMES); + if (cv.isWoven()) { + return cw.toByteArray(); + } else { + return bytes; + } + } + + private volatile boolean m_woven = false; + private final Type target; + private final Method targetMethodClassLoader; + private final Method targetMethodResource; + private final Method targetMethodStream; + + AtomosWeaverVisitor(ClassWriter cv, Type target, Method targetMethodClassLoader, Method targetMethodResource, Method targetMethodStream) { + super(Opcodes.ASM9, cv); + this.target = target; + this.targetMethodClassLoader = targetMethodClassLoader; + this.targetMethodResource = targetMethodResource; + this.targetMethodStream = targetMethodStream; + } + + boolean isWoven() { + return m_woven; + } + + @Override + public MethodVisitor visitMethod(int access, String name, String desc, + String signature, String[] exceptions) { + MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); + mv = new MethodWeaverVisitor(mv, access, name, desc); + mv = new JSRInlinerAdapter(mv, access, name, desc, signature, exceptions); + + return mv; + } + + private class MethodWeaverVisitor extends GeneratorAdapter { + public MethodWeaverVisitor(MethodVisitor mv, int access, String name, String descriptor) { + super(Opcodes.ASM7, mv, access, name, descriptor); + } + + @Override + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { + if (opcode == INVOKEVIRTUAL && owner.replace('/', '.').equals("java.lang.Class")) { + Method targetMethod; + if (name.equals("getClassLoader")) { + targetMethod = targetMethodClassLoader; + } else if (name.equals("getResource")) { + targetMethod = targetMethodResource; + } else if (name.equals("getResourceAsStream")) { + targetMethod = targetMethodStream; + } else { + targetMethod = null; + } + if (targetMethod != null) { + invokeStatic(target, targetMethod); + m_woven = true; + return; + } + } + super.visitMethodInsn(opcode, owner, name, desc, itf); + } + } +} diff --git a/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/StaticToolClassWriter.java b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/StaticToolClassWriter.java new file mode 100644 index 00000000..451a44ff --- /dev/null +++ b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/impl/StaticToolClassWriter.java @@ -0,0 +1,72 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF 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 org.apache.sling.feature.launcher.atomos.weaver.impl; + +import org.objectweb.asm.ClassWriter; + +/** + * We need to override ASM's default behaviour in + * {@link #getCommonSuperClass(String, String)} so that it accepts a custom + * classloader that can also see the jar that is being processed. + */ +public final class StaticToolClassWriter extends ClassWriter { + + private static final String OBJECT_INTERNAL_NAME = "java/lang/Object"; + private final ClassLoader loader; + + public StaticToolClassWriter(int flags, ClassLoader loader) { + super(flags); + + this.loader = loader; + } + + /** + * The implementation uses the classloader provided using the Constructor. + * + * This is a slight variation on ASM's default behaviour as that obtains the + * classloader to use ASMs classloader. + */ + @Override + protected String getCommonSuperClass(final String type1, final String type2) { + Class<?> c, d; + try { + c = Class.forName(type1.replace('/', '.'), false, loader); + d = Class.forName(type2.replace('/', '.'), false, loader); + } catch (Throwable e) { + throw new RuntimeException(e); + } + + if (c.isAssignableFrom(d)) { + return type1; + } + if (d.isAssignableFrom(c)) { + return type2; + } + + if (c.isInterface() || d.isInterface()) { + return OBJECT_INTERNAL_NAME; + } + + do { + c = c.getSuperclass(); + } while (!c.isAssignableFrom(d)); + + return c.getName().replace('.', '/'); + } +} diff --git a/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/main/Main.java b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/main/Main.java new file mode 100644 index 00000000..7b9525cb --- /dev/null +++ b/atomosfeaturelauncherweaver/src/main/java/org/apache/sling/feature/launcher/atomos/weaver/main/Main.java @@ -0,0 +1,71 @@ +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~ Licensed to the Apache Software Foundation (ASF) under one + ~ or more contributor license agreements. See the NOTICE file + ~ distributed with this work for additional information + ~ regarding copyright ownership. The ASF 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 org.apache.sling.feature.launcher.atomos.weaver.main; + +import org.apache.sling.feature.launcher.atomos.weaver.AtomosWeaver; +import org.apache.sling.feature.launcher.atomos.weaver.impl.AtomosWeaverVisitor; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ServiceLoader; + +public class Main { + + public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException { + AtomosWeaver weaver = ServiceLoader.load(AtomosWeaver.class).iterator().next(); + + byte[] bytes = weaver.weave( + new FileInputStream(args[0].replace('.', File.separatorChar) + ".class").readAllBytes(), + Main.class.getName(), "getClassLoaderFix", "getResourceFix", "getStreamFix", + AtomosWeaverVisitor.class.getClassLoader() + ); + try (FileOutputStream output = new FileOutputStream("dump.class")) { + output.write(bytes); + } + new ClassLoader(){ + @Override + public Class<?> loadClass(String name) throws ClassNotFoundException { + if (name.equals(args[0])) { + return defineClass(name, bytes, 0, bytes.length); + } else { + return AtomosWeaverVisitor.class.getClassLoader().loadClass(name); + } + } + }.loadClass(args[0]).newInstance(); + } + + public static ClassLoader getClassLoaderFix(Class c) { + System.out.println("CALLED! " + c.getName()); + return c.getClassLoader(); + } + + public static URL getResourceFix(Class c, String r) { + System.out.println("CALLED!! " + c.getName() + " " + r); + return c.getResource(r); + } + + public static InputStream getStreamFix(Class c, String r) { + System.out.println("CALLED!!! " + c.getName() + " " + r); + return c.getResourceAsStream(r); + } +} diff --git a/atomosfeaturelauncherweaver/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.atomos.weaver.AtomosWeaver b/atomosfeaturelauncherweaver/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.atomos.weaver.AtomosWeaver new file mode 100644 index 00000000..a59df85a --- /dev/null +++ b/atomosfeaturelauncherweaver/src/main/resources/META-INF/services/org.apache.sling.feature.launcher.atomos.weaver.AtomosWeaver @@ -0,0 +1 @@ +org.apache.sling.feature.launcher.atomos.weaver.impl.AtomosWeaverImpl \ No newline at end of file