Skip to content
Commits on Source (2)
jboss-classfilewriter (1.2.4-1) unstable; urgency=medium
* New upstream version 1.2.4
* Declare compliance with Debian Policy 4.3.0.
-- Markus Koschany <apo@debian.org> Sat, 09 Feb 2019 12:43:29 +0100
jboss-classfilewriter (1.2.3-1) unstable; urgency=medium
* New upstream version 1.2.3.
......
......@@ -12,9 +12,9 @@ Build-Depends:
libmaven-javadoc-plugin-java,
libmaven-bundle-plugin-java,
maven-debian-helper (>= 1.5)
Standards-Version: 4.1.5
Vcs-Git: https://anonscm.debian.org/git/pkg-java/jboss-classfilewriter.git
Vcs-Browser: https://anonscm.debian.org/cgit/pkg-java/jboss-classfilewriter.git
Standards-Version: 4.3.0
Vcs-Git: https://salsa.debian.org/java-team/jboss-classfilewriter.git
Vcs-Browser: https://salsa.debian.org/java-team/jboss-classfilewriter
Homepage: https://github.com/jbossas/jboss-classfilewriter
Package: libjboss-classfilewriter-java
......
......@@ -3,11 +3,11 @@ Upstream-Name: classfilewriter
Source: https://github.com/jbossas/jboss-classfilewriter
Files: *
Copyright: 2015-2018, Stuart Douglas <sdouglas@redhat.com>
Copyright: 2015-2019, Stuart Douglas <sdouglas@redhat.com>
License: Apache-2.0
Files: debian/*
Copyright: 2015-2018, Markus Koschany <apo@debian.org>
Copyright: 2015-2019, Markus Koschany <apo@debian.org>
License: Apache-2.0
License: Apache-2.0
......
......@@ -9,7 +9,7 @@
<groupId>org.jboss.classfilewriter</groupId>
<artifactId>jboss-classfilewriter</artifactId>
<version>1.2.3.Final</version>
<version>1.2.4.Final</version>
<packaging>jar</packaging>
<description>A bytecode writer that creates .class files at runtime</description>
......
/*
* JBoss, Home of Professional Open Source.
*
* Copyright 2019 Red Hat, Inc.
*
* Licensed 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.jboss.classfilewriter;
import java.security.ProtectionDomain;
/**
* Class definition factory.
*
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
*/
public interface ClassFactory {
/**
* Converts an array of bytes into an instance of class <tt>Class</tt>.
*
* @param loader
* The classloader to be used for class definition.
*
* @param name
* The expected <a href="#name">binary name</a> of the class, or
* <tt>null</tt> if not known
*
* @param b
* The bytes that make up the class data. The bytes in positions
* <tt>off</tt> through <tt>off+len-1</tt> should have the format
* of a valid class file as defined by
* <cite>The Java&trade; Virtual Machine Specification</cite>.
*
* @param off
* The start offset in <tt>b</tt> of the class data
*
* @param len
* The length of the class data
*
* @param protectionDomain
* The ProtectionDomain of the class
*
* @return The <tt>Class</tt> object that was created from the specified
* class data.
*
* @throws ClassFormatError
* If the data did not contain a valid class
*/
Class<?> defineClass(ClassLoader loader, String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) throws ClassFormatError;
}
......@@ -19,14 +19,9 @@ package org.jboss.classfilewriter;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -42,12 +37,8 @@ import org.jboss.classfilewriter.constpool.ConstPool;
import org.jboss.classfilewriter.util.ByteArrayDataOutputStream;
import org.jboss.classfilewriter.util.DescriptorUtils;
import sun.misc.Unsafe;
/**
*
* @author Stuart Douglas
*
*/
public class ClassFile implements WritableEntry {
......@@ -75,37 +66,69 @@ public class ClassFile implements WritableEntry {
private final ClassLoader classLoader;
private final ClassFactory classFactory;
@Deprecated
public ClassFile(String name, String superclass, String... interfaces) {
this(name, AccessFlag.of(AccessFlag.SUPER, AccessFlag.PUBLIC), superclass, null, interfaces);
}
@Deprecated
public ClassFile(String name, int accessFlags, String superclass, String... interfaces) {
this(name, accessFlags, superclass, null, interfaces);
}
@Deprecated
public ClassFile(String name, String superclass, ClassLoader classLoader, String... interfaces) {
this(name, AccessFlag.of(AccessFlag.SUPER, AccessFlag.PUBLIC), superclass, classLoader, interfaces);
}
@Deprecated
public ClassFile(String name, int accessFlags, String superclass, ClassLoader classLoader, String... interfaces) {
this(name, accessFlags, superclass, JavaVersions.JAVA_6, classLoader, interfaces);
}
@Deprecated
public ClassFile(String name, int accessFlags, String superclass, int version, ClassLoader classLoader, String... interfaces) {
if(version > JavaVersions.JAVA_6 && classLoader == null) {
throw new IllegalArgumentException("ClassLoader must be specified if version is greater than Java 6");
}
this.version = version;
this.classLoader = classLoader;
this.classFactory = null; // allowed to be null for backward compatibility reasons
this.name = name.replace('/', '.'); // store the name in . form
this.superclass = superclass;
this.accessFlags = accessFlags;
this.interfaces.addAll(Arrays.asList(interfaces));
runtimeVisibleAnnotationsAttribute = new AnnotationsAttribute(AnnotationsAttribute.Type.RUNTIME_VISIBLE, constPool);
this.runtimeVisibleAnnotationsAttribute = new AnnotationsAttribute(AnnotationsAttribute.Type.RUNTIME_VISIBLE, constPool);
this.attributes.add(runtimeVisibleAnnotationsAttribute);
}
private final static java.lang.reflect.Method defineClass1, defineClass2;
public ClassFile(String name, String superclass, ClassLoader classLoader, ClassFactory classFactory, String... interfaces) {
this(name, AccessFlag.of(AccessFlag.SUPER, AccessFlag.PUBLIC), superclass, classLoader, classFactory, interfaces);
}
public ClassFile(String name, int accessFlags, String superclass, ClassLoader classLoader, ClassFactory classFactory, String... interfaces) {
this(name, accessFlags, superclass, JavaVersions.JAVA_6, classLoader, classFactory, interfaces);
}
public ClassFile(String name, int accessFlags, String superclass, int version, ClassLoader classLoader, ClassFactory classFactory, String... interfaces) {
if(version > JavaVersions.JAVA_6 && classLoader == null) {
throw new IllegalArgumentException("ClassLoader must be specified if version is greater than Java 6");
}
if (classFactory == null) {
throw new IllegalArgumentException("ClassFactory must be specified");
}
this.version = version;
this.classLoader = classLoader;
this.classFactory = classFactory;
this.name = name.replace('/', '.'); // store the name in . form
this.superclass = superclass;
this.accessFlags = accessFlags;
this.interfaces.addAll(Arrays.asList(interfaces));
this.runtimeVisibleAnnotationsAttribute = new AnnotationsAttribute(AnnotationsAttribute.Type.RUNTIME_VISIBLE, constPool);
this.attributes.add(runtimeVisibleAnnotationsAttribute);
}
public void addInterface(String iface) {
this.interfaces.add(iface);
......@@ -271,35 +294,9 @@ public class ClassFile implements WritableEntry {
}
private Class<?> defineInternal(ClassLoader loader, ProtectionDomain domain) {
try {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
final int index = name.lastIndexOf('.');
final String packageName;
if(index == -1 ) {
packageName = "";
} else {
packageName = name.substring(0, index);
}
RuntimePermission permission = new RuntimePermission("defineClassInPackage." + packageName);
sm.checkPermission(permission);
}
byte[] b = toBytecode();
java.lang.reflect.Method method;
Object[] args;
if (domain == null) {
method = defineClass1;
args = new Object[] { name.replace('/', '.'), b, Integer.valueOf(0), Integer.valueOf(b.length) };
} else {
method = defineClass2;
args = new Object[] { name.replace('/', '.'), b, Integer.valueOf(0), Integer.valueOf(b.length), domain };
}
return (Class<?>) method.invoke(loader, args);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
final ClassFactory classFactory = this.classFactory == null ? DefaultClassFactory.INSTANCE : this.classFactory;
return classFactory.defineClass(loader, name, b, 0, b.length, domain);
}
public byte[] toBytecode() {
......@@ -378,48 +375,4 @@ public class ClassFile implements WritableEntry {
return Collections.unmodifiableSet(methods);
}
// Unsafe mechanics
static {
try {
Method[] defineClassMethods = AccessController.doPrivileged(new PrivilegedExceptionAction<Method[]>() {
public Method[] run() throws Exception {
final sun.misc.Unsafe UNSAFE;
final long overrideOffset;
// first we need to grab Unsafe
try {
UNSAFE = getUnsafe();
overrideOffset = UNSAFE.objectFieldOffset(AccessibleObject.class.getDeclaredField("override"));
} catch (Exception e) {
throw new Error(e);
}
// now we gain access to CL.defineClass methods
Class<?> cl = ClassLoader.class;
Method defClass1 = cl.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class,
int.class });
Method defClass2 = cl.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class,
int.class, ProtectionDomain.class });
// use Unsafe to crack open both CL.defineClass() methods (instead of using setAccessible())
UNSAFE.putBoolean(defClass1, overrideOffset, true);
UNSAFE.putBoolean(defClass2, overrideOffset, true);
return new Method[]{defClass1, defClass2};
}
});
// set methods to final fields
defineClass1 = defineClassMethods[0];
defineClass2 = defineClassMethods[1];
} catch (PrivilegedActionException pae) {
throw new RuntimeException("cannot initialize ClassFile", pae.getException());
}
}
private static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
} catch (Throwable t) {
throw new RuntimeException("JDK did not allow accessing unsafe", t);
}
}
}
/*
* JBoss, Home of Professional Open Source.
*
* Copyright 2019 Red Hat, Inc.
*
* Licensed 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.jboss.classfilewriter;
import sun.misc.Unsafe;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
/**
* Default class definition factory. This factory maintains backward compatibility
* but it doesn't work on JDK 12 and above where ClassLoader reflection magic is forbidden.
*
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
*/
final class DefaultClassFactory implements ClassFactory {
static final ClassFactory INSTANCE = new DefaultClassFactory();
private final java.lang.reflect.Method defineClass1, defineClass2;
private DefaultClassFactory() {
try {
Method[] defineClassMethods = AccessController.doPrivileged(new PrivilegedExceptionAction<Method[]>() {
public Method[] run() throws Exception {
final sun.misc.Unsafe UNSAFE;
final long overrideOffset;
// first we need to grab Unsafe
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null);
overrideOffset = UNSAFE.objectFieldOffset(AccessibleObject.class.getDeclaredField("override"));
} catch (Exception e) {
throw new Error(e);
}
// now we gain access to CL.defineClass methods
Class<?> cl = ClassLoader.class;
Method defClass1 = cl.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class,
int.class });
Method defClass2 = cl.getDeclaredMethod("defineClass", new Class[] { String.class, byte[].class, int.class,
int.class, ProtectionDomain.class });
// use Unsafe to crack open both CL.defineClass() methods (instead of using setAccessible())
UNSAFE.putBoolean(defClass1, overrideOffset, true);
UNSAFE.putBoolean(defClass2, overrideOffset, true);
return new Method[]{defClass1, defClass2};
}
});
// set methods to volatile fields
defineClass1 = defineClassMethods[0];
defineClass2 = defineClassMethods[1];
} catch (PrivilegedActionException pae) {
throw new RuntimeException("Cannot initialize DefaultClassFactory", pae.getException());
}
}
@Override
public Class<?> defineClass(final ClassLoader loader, final String name,
final byte[] b, final int off, final int len,
final ProtectionDomain domain) throws ClassFormatError {
try {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
final int index = name.lastIndexOf('.');
final String packageName;
if(index == -1 ) {
packageName = "";
} else {
packageName = name.substring(0, index);
}
RuntimePermission permission = new RuntimePermission("defineClassInPackage." + packageName);
sm.checkPermission(permission);
}
java.lang.reflect.Method method;
Object[] args;
if (domain == null) {
method = defineClass1;
args = new Object[]{name, b, 0, b.length};
} else {
method = defineClass2;
args = new Object[]{name, b, 0, b.length, domain};
}
return (Class<?>) method.invoke(loader, args);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}