Commit 779c361a authored by Eric Bruneton's avatar Eric Bruneton
Browse files

Merge branch '317825-fix-copypool-with-version-change' into 'master'

Resolve "ACC_SYNTHETIC attribute is still lost if constant pool is retained"

Closes #317825

See merge request asm/asm!170
parents b14e3c29 6fe48a7a
......@@ -976,6 +976,8 @@ public class ClassReader {
int exceptionsOffset = 0;
// - The strings corresponding to the Exceptions attribute, or null.
String[] exceptions = null;
// - Whether the method has a Synthetic attribute.
boolean synthetic = false;
// - The constant pool index contained in the Signature attribute, or 0.
int signatureIndex = 0;
// - The offset of the RuntimeVisibleAnnotations attribute, or 0.
......@@ -1030,6 +1032,7 @@ public class ClassReader {
} else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) {
annotationDefaultOffset = currentOffset;
} else if (Constants.SYNTHETIC.equals(attributeName)) {
synthetic = true;
context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC;
} else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
runtimeInvisibleAnnotationsOffset = currentOffset;
......@@ -1079,7 +1082,8 @@ public class ClassReader {
this,
methodInfoOffset,
currentOffset - methodInfoOffset,
context.currentMethodAccessFlags,
synthetic,
(context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0,
signatureIndex,
exceptionsOffset)) {
return currentOffset;
......
......@@ -1953,8 +1953,10 @@ final class MethodWriter extends MethodVisitor {
* the attributes of this method might be copied.
* @param methodInfoLength the length in 'source.b' of the method_info JVMS structure from which
* the attributes of this method might be copied.
* @param access the access flags (including the ASM specific ones) of the method_info JVMS
* structure from which the attributes of this method might be copied.
* @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes
* of this method might be copied contains a Synthetic attribute.
* @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes
* of this method might be copied contains a Deprecated attribute.
* @param signatureIndex the constant pool index contained in the Signature attribute of the
* method_info JVMS structure from which the attributes of this method might be copied, or 0.
* @param exceptionsOffset the offset in 'source.b' of the Exceptions attribute of the method_info
......@@ -1967,17 +1969,18 @@ final class MethodWriter extends MethodVisitor {
final ClassReader source,
final int methodInfoOffset,
final int methodInfoLength,
final int access,
final boolean hasSyntheticAttribute,
final boolean hasDeprecatedAttribute,
final int signatureIndex,
final int exceptionsOffset) {
if (source != symbolTable.getSource()
|| signatureIndex != this.signatureIndex
|| (access & Opcodes.ACC_DEPRECATED) != (accessFlags & Opcodes.ACC_DEPRECATED)) {
|| hasDeprecatedAttribute != ((accessFlags & Opcodes.ACC_DEPRECATED) != 0)) {
return false;
}
boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
if (useSyntheticAttribute
&& (access & Opcodes.ACC_SYNTHETIC) != (accessFlags & Opcodes.ACC_SYNTHETIC)) {
boolean needSyntheticAttribute =
symbolTable.getMajorVersion() < Opcodes.V1_5 && (accessFlags & Opcodes.ACC_SYNTHETIC) != 0;
if (hasSyntheticAttribute != needSyntheticAttribute) {
return false;
}
if (exceptionsOffset == 0) {
......
......@@ -31,6 +31,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.objectweb.asm.test.AsmTest;
......@@ -122,6 +123,40 @@ public class ClassVisitorTest extends AsmTest {
assertThatClass(classWriterWithCopyPool.toByteArray()).isEqualTo(classWriter.toByteArray());
}
/**
* Tests that a ClassReader -> class adapter -> ClassWriter chain give the same result with or
* without the copy pool option, when the class version is changed (and optionally a synthetic
* attribute as well).
*/
@ParameterizedTest
@CsvSource({"true, true", "true, false", "false, true", "false, false"})
public void testReadAndWriteWithCopyPoolAndSyntheticAdapter(
final boolean upgradeVersion, final boolean changeSynthetic) {
ClassWriter sourceClassWriter = new ClassWriter(0);
sourceClassWriter.visit(
upgradeVersion ? Opcodes.V1_4 : Opcodes.V1_5,
Opcodes.ACC_ABSTRACT,
"C",
null,
"java/lang/Object",
null);
sourceClassWriter
.visitMethod(Opcodes.ACC_ABSTRACT | Opcodes.ACC_SYNTHETIC, "m", "()V", null, null)
.visitEnd();
sourceClassWriter.visitEnd();
ClassReader classReader = new ClassReader(sourceClassWriter.toByteArray());
ClassWriter classWriter = new ClassWriter(0);
ClassWriter copyPoolClassWriter = new ClassWriter(classReader, 0);
int version = upgradeVersion ? Opcodes.V1_5 : Opcodes.V1_4;
int access = changeSynthetic ? Opcodes.ACC_SYNTHETIC : 0;
classReader.accept(
new ChangeVersionAdapter(new ChangeAccessAdapter(classWriter, access), version), 0);
classReader.accept(
new ChangeVersionAdapter(new ChangeAccessAdapter(copyPoolClassWriter, access), version), 0);
assertThatClass(copyPoolClassWriter.toByteArray()).isEqualTo(classWriter.toByteArray());
}
/** Test that classes with only visible or only invisible annotations can be read correctly. */
@ParameterizedTest
@ValueSource(strings = {"true", "false"})
......@@ -317,6 +352,27 @@ public class ClassVisitorTest extends AsmTest {
}
}
private static class ChangeVersionAdapter extends ClassVisitor {
private final int newVersion;
ChangeVersionAdapter(final ClassVisitor classVisitor, final int newVersion) {
super(Opcodes.ASM6, classVisitor);
this.newVersion = newVersion;
}
@Override
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
super.visit(newVersion, access, name, signature, superName, interfaces);
}
}
private static class ChangeAccessAdapter extends ClassVisitor {
private final int accessFlags;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment