Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ContentTypeDetector should recognize future versions of Java class files #952

Merged
merged 7 commits into from Oct 4, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -125,6 +125,23 @@ private static byte[] createClass(final int version) {
return cw.toByteArray();
}

/**
* @see #analyzeAll_should_throw_exception_for_unsupported_class_file_version()
*/
@Test
public void analyzeClass_should_throw_exception_for_unsupported_class_file_version() {
final byte[] bytes = createClass(Opcodes.V14 + 1);
try {
analyzer.analyzeClass(bytes, "UnsupportedVersion");
fail("exception expected");
} catch (IOException e) {
assertEquals("Error while analyzing UnsupportedVersion.",
e.getMessage());
assertEquals("Unsupported class file major version 59",
e.getCause().getMessage());
}
}

@Test
public void testAnalyzeClassFromStream() throws IOException {
analyzer.analyzeClass(TargetLoader.getClassData(AnalyzerTest.class),
Expand Down Expand Up @@ -196,6 +213,24 @@ public void testAnalyzeClass_BrokenStream() throws IOException {
}
}

/**
* @see #analyzeClass_should_throw_exception_for_unsupported_class_file_version()
*/
@Test
public void analyzeAll_should_throw_exception_for_unsupported_class_file_version() {
final byte[] bytes = createClass(Opcodes.V14 + 1);
try {
analyzer.analyzeAll(new ByteArrayInputStream(bytes),
"UnsupportedVersion");
fail("exception expected");
} catch (IOException e) {
assertEquals("Error while analyzing UnsupportedVersion.",
e.getMessage());
assertEquals("Unsupported class file major version 59",
e.getCause().getMessage());
}
}

@Test
public void testAnalyzeAll_Class() throws IOException {
final int count = analyzer.analyzeAll(
Expand Down
Expand Up @@ -117,6 +117,23 @@ private static byte[] createClass(final int version) {
return cw.toByteArray();
}

/**
* @see #instrumentAll_should_throw_exception_for_unsupported_class_file_version()
*/
@Test
public void instrument_should_throw_exception_for_unsupported_class_file_version() {
final byte[] bytes = createClass(Opcodes.V14 + 1);
try {
instrumenter.instrument(bytes, "UnsupportedVersion");
fail("exception expected");
} catch (final IOException e) {
assertEquals("Error while instrumenting UnsupportedVersion.",
e.getMessage());
assertEquals("Unsupported class file major version 59",
e.getCause().getMessage());
}
}

@Test
public void testInstrumentClass() throws Exception {
byte[] bytes = instrumenter.instrument(
Expand Down Expand Up @@ -202,6 +219,24 @@ public void testSerialization() throws Exception {
assertEquals("Hello42", obj2.toString());
}

/**
* @see #instrument_should_throw_exception_for_unsupported_class_file_version()
*/
@Test
public void instrumentAll_should_throw_exception_for_unsupported_class_file_version() {
final byte[] bytes = createClass(Opcodes.V14 + 1);
try {
instrumenter.instrumentAll(new ByteArrayInputStream(bytes),
new ByteArrayOutputStream(), "UnsupportedVersion");
fail("exception expected");
} catch (final IOException e) {
assertEquals("Error while instrumenting UnsupportedVersion.",
e.getMessage());
assertEquals("Unsupported class file major version 59",
e.getCause().getMessage());
}
}

@Test
public void testInstrumentAll_Class() throws IOException {
InputStream in = TargetLoader.getClassData(getClass());
Expand Down
Expand Up @@ -180,6 +180,21 @@ public void should_detect_java_14_with_preview_features() throws IOException {
assertContent();
}

@Test
public void should_detect_java_42() throws IOException {
initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x56);
assertEquals(ContentTypeDetector.CLASSFILE, detector.getType());
assertContent();
}

@Test
public void should_not_detect_MachO_fat_binary_with_44_architectures()
throws IOException {
initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x2C);
assertEquals(ContentTypeDetector.UNKNOWN, detector.getType());
assertContent();
}

@Test
public void testMachObjectFile() throws IOException {
initData(0xCA, 0xFE, 0xBA, 0xBE, 0x00, 0x00, 0x00, 0x02);
Expand Down
Expand Up @@ -16,8 +16,6 @@
import java.io.IOException;
import java.io.InputStream;

import org.objectweb.asm.Opcodes;

/**
* Detector for content types of binary streams based on a magic headers.
*/
Expand Down Expand Up @@ -73,26 +71,14 @@ private static int determineType(final InputStream in) throws IOException {
case PACK200FILE:
return PACK200FILE;
case CLASSFILE:
// also verify version to distinguish from Mach Object files:
switch (readInt(in)) {
case Opcodes.V1_1:
case Opcodes.V1_2:
case Opcodes.V1_3:
case Opcodes.V1_4:
case Opcodes.V1_5:
case Opcodes.V1_6:
case Opcodes.V1_7:
case Opcodes.V1_8:
case Opcodes.V9:
case Opcodes.V10:
case Opcodes.V11:
case Opcodes.V11 | Opcodes.V_PREVIEW:
case Opcodes.V12:
case Opcodes.V12 | Opcodes.V_PREVIEW:
case Opcodes.V13:
case Opcodes.V13 | Opcodes.V_PREVIEW:
case (Opcodes.V13 + 1):
case (Opcodes.V13 + 1) | Opcodes.V_PREVIEW:
// Mach-O fat/universal binaries have the same magic header as Java
// class files, number of architectures is stored in unsigned 4
// bytes in the same place and in the same big-endian order as major
// and minor version of class file. Hopefully on practice number of
// architectures in single executable is less than 45, which is
// major version of Java 1.1 class files:
final int majorVersion = readInt(in) & 0xFFFF;
if (majorVersion >= 45) {
return CLASSFILE;
}
}
Expand Down
3 changes: 3 additions & 0 deletions org.jacoco.doc/docroot/doc/changes.html
Expand Up @@ -70,6 +70,9 @@ <h3>API Changes</h3>
a coverage ratio limit is configured outside the range [0,1] to avoid
common configuration mistakes
(GitHub <a href="https://github.com/jacoco/jacoco/issues/783">#783</a>).</li>
<li>Report generation and offline instrumentation now throw an exception for
class files of unsupported version instead of skipping them silently
(GitHub <a href="https://github.com/jacoco/jacoco/issues/952">#952</a>).</li>
</ul>

<h2>Release 0.8.4 (2019/05/08)</h2>
Expand Down