FastJarFS: fix behavior on invalid zip files

"emulate" the ZipHandler - log error and ignore invalid file
#KT-55712 fixed
This commit is contained in:
Ilya Chernikov
2023-01-31 11:26:08 +01:00
committed by Space Team
parent b415aa7446
commit 46c8cbe1bb
2 changed files with 66 additions and 1 deletions
@@ -4,12 +4,14 @@
*/
package org.jetbrains.kotlin.cli.jvm.compiler.jarfs
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VirtualFile
import java.io.File
import java.io.FileNotFoundException
import java.io.RandomAccessFile
import java.nio.channels.FileChannel
import kotlin.collections.HashMap
class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) {
private val myRoot: VirtualFile?
@@ -25,7 +27,10 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) {
entries = try {
mappedByteBuffer.parseCentralDirectory()
} catch (e: Exception) {
throw IllegalStateException("Error while reading '${file.path}': $e", e)
// copying the behavior of ArchiveHandler (and therefore ZipHandler)
// TODO: consider propagating to compiler error or warning, but take into account that both javac and K1 simply ignore invalid jars in such cases
Logger.getInstance(this::class.java).warn("Error while reading zip file: ${file.path}: $e", e)
emptyList()
}
cachedManifest =
entries.singleOrNull { StringUtil.equals(MANIFEST_PATH, it.relativePath) }
@@ -5,12 +5,16 @@
package org.jetbrains.kotlin.jvm.compiler
import com.intellij.core.JavaCoreApplicationEnvironment
import com.intellij.openapi.util.Disposer
import junit.framework.TestCase
import org.jetbrains.kotlin.cli.jvm.compiler.jarfs.FastJarFileSystem
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.junit.Assert
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.PrintStream
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
@@ -18,13 +22,18 @@ import java.util.zip.ZipOutputStream
class FastJarFSTest : TestCase() {
private var fs: FastJarFileSystem? = null
private var coreAppEnv: JavaCoreApplicationEnvironment? = null
private val rootDisposable = Disposer.newDisposable()
override fun setUp() {
super.setUp()
fs = FastJarFileSystem.createIfUnmappingPossible()
coreAppEnv = JavaCoreApplicationEnvironment(rootDisposable)
}
override fun tearDown() {
coreAppEnv = null
rootDisposable.dispose()
fs?.clearHandlersCache()
fs = null
super.tearDown()
@@ -57,4 +66,55 @@ class FastJarFSTest : TestCase() {
Assert.assertEquals(String(file.contentsToByteArray()), i.toString())
}
}
fun testInvalidJar() {
val fs = fs ?: return
val tmpDir = KotlinTestUtils.tmpDirForTest(this)
val badJarFile = File(tmpDir, "file.pom")
badJarFile.writeText(A_POM_FILE)
val errFromFastJarFs = captureErr {
fs.findFileByPath(badJarFile.absolutePath + "!/a.class")
}
Assert.assertTrue(errFromFastJarFs.contains("WARN: Error while reading zip file:"))
val errFromCoreJarFs = captureErr {
coreAppEnv!!.jarFileSystem.findFileByPath(badJarFile.absolutePath + "!/a.class")
}
// Asserting that core jar FS still behaves the same way as the "emulation" implemented in FastJarFS
Assert.assertTrue(errFromCoreJarFs.contains("WARN: error in opening zip file"))
}
}
private fun captureErr(body: () -> Unit): String {
val outStream = ByteArrayOutputStream()
val prevErr = System.err
System.setErr(PrintStream(outStream))
try {
body()
}
finally {
System.err.flush()
System.setErr(prevErr)
}
return outStream.toString()
}
private const val A_POM_FILE =
"""<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>a</groupId>
<artifactId>b</artifactId>
<version>0.0.1</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>c</groupId>
<artifactId>d</artifactId>
<version>0.0.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
"""