Skip to content

Commit 912ff90

Browse files
committed
Fix #3549: Workaround broken FileZipArchive#LeakyEntry jpath
1 parent 6cceefc commit 912ff90

File tree

4 files changed

+46
-11
lines changed

4 files changed

+46
-11
lines changed

compiler/src/dotty/tools/dotc/core/classfile/ClassfileParser.scala

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import scala.collection.{ mutable, immutable }
1313
import scala.collection.mutable.{ ListBuffer, ArrayBuffer }
1414
import scala.annotation.switch
1515
import typer.Checking.checkNonCyclic
16-
import io.{AbstractFile, PlainFile}
16+
import io.{AbstractFile, PlainFile, Path, FileZipArchive, JarArchive}
1717
import scala.util.control.NonFatal
1818

1919
object ClassfileParser {
@@ -781,11 +781,32 @@ class ClassfileParser(
781781

782782
if (scan(tpnme.TASTYATTR)) {
783783
val attrLen = in.nextInt
784-
if (attrLen == 0) {
785-
// A tasty attribute implies the existence of the .tasty file
786-
val file = new PlainFile(io.File(classfile.jpath).changeExtension("tasty"))
787-
if (file.exists) return unpickleTASTY(new AbstractFileReader(file).nextBytes(file.sizeOption.get))
788-
else ctx.error("Could not find " + file)
784+
if (attrLen == 0) { // A tasty attribute implies the existence of the .tasty file
785+
def readBytes(file: io.Path): Array[Byte] = {
786+
val plainFile = new PlainFile(file)
787+
if (plainFile.exists) new AbstractFileReader(plainFile).nextBytes(plainFile.sizeOption.get)
788+
else {
789+
ctx.error("Could not find " + file)
790+
Array.empty
791+
}
792+
}
793+
val tastyBytes = classfile match {
794+
case entry: FileZipArchive#LeakyEntry =>
795+
// Workaround broken java paths in LeakyEntry.
796+
// This is only necessary because classfile.jpath is null
797+
val jarPath = entry.underlyingSource.get.jpath
798+
val jarFile = JarArchive.open(Path(jarPath))
799+
try {
800+
val tastyPath = jarFile.jpath.resolve(entry.path.dropRight(".class".length) + ".tasty")
801+
readBytes(io.File(tastyPath))
802+
} finally jarFile.close()
803+
804+
case _ =>
805+
assert(classfile.jpath ne null)
806+
readBytes(io.File(classfile.jpath).changeExtension("tasty"))
807+
}
808+
if (tastyBytes.nonEmpty)
809+
return unpickleTASTY(tastyBytes)
789810
}
790811
else return unpickleTASTY(in.nextBytes(attrLen))
791812
}

compiler/src/dotty/tools/io/JarArchive.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@ object JarArchive {
1616
/** Create a new jar file. Overwrite if file already exists */
1717
def create(path: Path): JarArchive = {
1818
require(path.extension == "jar")
19-
2019
path.delete()
20+
open(path, create = true)
21+
}
22+
23+
/** Create a jar file. */
24+
def open(path: Path, create: Boolean = false): JarArchive = {
25+
require(path.extension == "jar")
2126

2227
// creating a new zip file system by using the JAR URL syntax:
2328
// https://docs.oracle.com/javase/7/docs/technotes/guides/io/fsp/zipfilesystemprovider.html
24-
val env = Map("create" -> "true").asJava
29+
val env = Map("create" -> create.toString).asJava
2530
val uri = java.net.URI.create("jar:file:" + path.toAbsolute.path)
2631
val fs = FileSystems.newFileSystem(uri, env)
2732

compiler/src/dotty/tools/io/ZipArchive.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ final class FileZipArchive(jpath: JPath) extends ZipArchive(jpath) {
139139
// on Windows, and leaks memory on all OS (typically by stopping
140140
// classloaders from being garbage collected). But is slightly
141141
// faster than LazyEntry.
142-
private[this] class LeakyEntry(
142+
private[tools] class LeakyEntry(
143143
zipFile: ZipFile,
144144
zipEntry: ZipEntry
145145
) extends Entry(zipEntry.getName) {

project/scripts/sbtTests

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ fi
3030

3131
# check that `sbt dotc -decompile` runs
3232
echo "testing sbt dotc -decompile"
33-
./project/scripts/sbt ";dotc -decompile -code -color:never -classpath out/scriptedtest1 dotrtest.Test" > sbtdotc3.out
33+
./project/scripts/sbt ";dotc -decompile -color:never -classpath out/scriptedtest1 dotrtest.Test" > sbtdotc3.out
3434
cat sbtdotc3.out
3535
if grep -e "def main(args: Array\[String\]): Unit =" sbtdotc3.out; then
3636
echo "output ok"
@@ -39,11 +39,20 @@ else
3939
exit -1
4040
fi
4141
echo "testing sbt dotr with no -classpath"
42-
4342
./project/scripts/sbt ";dotc tests/pos/sbtDotrTest.scala; dotr dotrtest.Test" > sbtdotr3.out
4443
cat sbtdotr3.out
4544
if grep -e "dotr test ok" sbtdotr3.out; then
4645
echo "output ok"
4746
else
4847
exit -1
4948
fi
49+
50+
echo "testing loading tasty from .tasty file in jar"
51+
./project/scripts/sbt ";dotc -d out/scriptedtest4.jar -YemitTasty tests/pos/sbtDotrTest.scala; dotc -decompile -classpath out/scriptedtest4.jar -color:never dotrtest.Test" > sbtdot4.out
52+
cat sbtdot4.out
53+
if grep -e "def main(args: Array\[String\]): Unit =" sbtdot4.out; then
54+
echo "output ok"
55+
else
56+
echo "failed output check"
57+
exit -1
58+
fi

0 commit comments

Comments
 (0)