aboutsummaryrefslogtreecommitdiff
path: root/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java')
-rw-r--r--org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java58
1 files changed, 45 insertions, 13 deletions
diff --git a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java
index 99e00270..1e438958 100644
--- a/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java
+++ b/org.jacoco.core/src/org/jacoco/core/internal/instr/InstrSupport.java
@@ -158,18 +158,52 @@ public final class InstrSupport {
*/
static final int CLINIT_ACC = Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC;
- private static final int MAJOR_VERSION_INDEX = 6;
+ /**
+ * Gets major version number from given bytes of class (unsigned two bytes
+ * at offset 6).
+ *
+ * @param b
+ * bytes of class
+ * @return major version of bytecode
+ * @see <a href=
+ * "https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.1">Java
+ * Virtual Machine Specification ยง4 The class File Format</a>
+ * @see #setMajorVersion(int, byte[])
+ * @see #getMajorVersion(ClassReader)
+ */
+ public static int getMajorVersion(final byte[] b) {
+ return ((b[6] & 0xFF) << 8) | (b[7] & 0xFF);
+ }
/**
- * Gets major of bytecode version number from given bytes of class.
+ * Sets major version number in given bytes of class (unsigned two bytes at
+ * offset 6).
*
+ * @param majorVersion
+ * major version of bytecode to set
* @param b
* bytes of class
- * @return version of bytecode
+ * @see #getMajorVersion(byte[])
+ */
+ public static void setMajorVersion(final int majorVersion, final byte[] b) {
+ b[6] = (byte) (majorVersion >>> 8);
+ b[7] = (byte) majorVersion;
+ }
+
+ /**
+ * Gets major version number from given {@link ClassReader}.
+ *
+ * @param reader
+ * reader to get information about the class
+ * @return major version of bytecode
+ * @see ClassReader#ClassReader(byte[], int, int)
+ * @see #getMajorVersion(byte[])
*/
- public static int getVersionMajor(final byte[] b) {
- return (short) (((b[MAJOR_VERSION_INDEX] & 0xFF) << 8)
- | (b[MAJOR_VERSION_INDEX + 1] & 0xFF));
+ public static int getMajorVersion(final ClassReader reader) {
+ // relative to the beginning of constant pool because ASM provides API
+ // to construct ClassReader which reads from the middle of array
+ final int firstConstantPoolEntryOffset = reader.getItem(1) - 1;
+ return reader.readUnsignedShort(firstConstantPoolEntryOffset - 4);
}
/**
@@ -237,15 +271,13 @@ public final class InstrSupport {
* @return {@link ClassReader}
*/
public static ClassReader classReaderFor(final byte[] b) {
- final byte[] originalVersion = new byte[] { b[4], b[5], b[6], b[7] };
- if (getVersionMajor(b) == Opcodes.V12 + 1) {
- b[4] = (byte) (Opcodes.V12 >>> 24);
- b[5] = (byte) (Opcodes.V12 >>> 16);
- b[6] = (byte) (Opcodes.V12 >>> 8);
- b[7] = (byte) Opcodes.V12;
+ final int originalVersion = getMajorVersion(b);
+ if (originalVersion == Opcodes.V12 + 1) {
+ // temporarily downgrade version to bypass check in ASM
+ setMajorVersion(Opcodes.V12, b);
}
final ClassReader classReader = new ClassReader(b);
- System.arraycopy(originalVersion, 0, b, 4, originalVersion.length);
+ setMajorVersion(originalVersion, b);
return classReader;
}