Closed
Description
Compiler version
# scala -version
Scala code runner version: 1.5.4
Scala version (default): 3.6.3
Minimized code
#!/usr/bin/env -S scala_legacy -classpath ./pallet_3.jar
object LegacyBug {
def main(args: Array[String]): Unit = {
printf("hello legacy!\n")
}
}
Can be reproduced by a jar with empty Class-Path:
attribute.
If the jar has an empty Class-Path:
attribute in the MANIFEST, it crashes.
If it has no Class-Path:
attribute, or a non-empty Class-Path:
attribute, no problem.
Output
[warning] MainGenericRunner class is deprecated since Scala 3.5.0, and Scala CLI features will not work.
[warning] Please be sure to update to the Scala CLI launcher to use the new features.
[warning] Check the Scala 3.5.0 release notes to troubleshoot your installation.
Exception while compiling C:\opt\ue\jsrc\legacyBug.sc
An unhandled exception was thrown in the compiler.
Please file a crash report here:
https://github.com/scala/scala3/issues/new/choose
For non-enriched exceptions, compile with -Xno-enrich-error-messages.
while compiling: <no file>
during phase: <some phase>
mode: Mode()
library version: version 2.13.15
compiler version: version 3.6.3
settings: -classpath C:/opt/scala3/lib/scala.jar;C:/opt/scala3/lib/with_compiler.jar;emptyClassPath.jar -d C:\tmp\scala3-scripting13458733512999800816
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "dotty.tools.io.AbstractFile.ext()" because "file" is null
at dotty.tools.dotc.classpath.FileUtils$.isJarOrZip(FileUtils.scala:37)
at dotty.tools.dotc.classpath.ClassPathFactory$.newClassPath(ClassPathFactory.scala:94)
at dotty.tools.dotc.classpath.ClassPathFactory.newClassPath(ClassPathFactory.scala:20)
at dotty.tools.dotc.classpath.ClassPathFactory.$anonfun$2$$anonfun$3(ClassPathFactory.scala:73)
at scala.collection.Iterator$$anon$9.next(Iterator.scala:584)
at scala.collection.immutable.List.prependedAll(List.scala:153)
at scala.collection.immutable.List$.from(List.scala:685)
at scala.collection.immutable.List$.from(List.scala:682)
at scala.collection.IterableOps$WithFilter.map(Iterable.scala:900)
at dotty.tools.dotc.classpath.ClassPathFactory.$anonfun$2(ClassPathFactory.scala:69)
at scala.collection.immutable.List.flatMap(List.scala:294)
at dotty.tools.dotc.classpath.ClassPathFactory.classesInPathImpl(ClassPathFactory.scala:68)
at dotty.tools.dotc.classpath.ClassPathFactory.classesInExpandedPath(ClassPathFactory.scala:46)
at dotty.tools.dotc.config.PathResolver$Calculated$.basis(PathResolver.scala:232)
at dotty.tools.dotc.config.PathResolver$Calculated$.containers$lzyINIT1(PathResolver.scala:236)
at dotty.tools.dotc.config.PathResolver$Calculated$.containers(PathResolver.scala:236)
at dotty.tools.dotc.config.PathResolver.containers(PathResolver.scala:258)
at dotty.tools.dotc.config.PathResolver.result$lzyINIT1(PathResolver.scala:261)
at dotty.tools.dotc.config.PathResolver.result(PathResolver.scala:260)
at dotty.tools.dotc.config.JavaPlatform.classPath(JavaPlatform.scala:18)
at dotty.tools.dotc.config.JavaPlatform.rootLoader(JavaPlatform.scala:38)
at dotty.tools.dotc.core.Contexts$ContextBase.rootLoader(Contexts.scala:909)
at dotty.tools.dotc.core.Definitions.RootClass$$anonfun$1(Definitions.scala:203)
at dotty.tools.dotc.core.Symbols$.$anonfun$2(Symbols.scala:655)
at dotty.tools.dotc.core.Symbols$.newClassSymbol(Symbols.scala:589)
at dotty.tools.dotc.core.Symbols$.newModuleSymbol(Symbols.scala:655)
at dotty.tools.dotc.core.Symbols$.newPackageSymbol(Symbols.scala:716)
at dotty.tools.dotc.core.Definitions.RootClass(Definitions.scala:203)
at dotty.tools.dotc.core.Denotations$.recurSimple$1(Denotations.scala:1352)
at dotty.tools.dotc.core.Denotations$.recur$1(Denotations.scala:1356)
at dotty.tools.dotc.core.Denotations$.staticRef(Denotations.scala:1360)
at dotty.tools.dotc.core.Symbols$.requiredPackage(Symbols.scala:944)
at dotty.tools.dotc.core.Definitions.ScalaPackageVal(Definitions.scala:215)
at dotty.tools.dotc.core.Definitions.ScalaPackageClass(Definitions.scala:218)
at dotty.tools.dotc.core.Definitions.AnyClass(Definitions.scala:281)
at dotty.tools.dotc.core.Definitions.syntheticScalaClasses(Definitions.scala:2184)
at dotty.tools.dotc.core.Definitions.syntheticCoreClasses(Definitions.scala:2199)
at dotty.tools.dotc.core.Definitions.init(Definitions.scala:2215)
at dotty.tools.dotc.core.Contexts$ContextBase.initialize(Contexts.scala:922)
at dotty.tools.dotc.core.Contexts$Context.initialize(Contexts.scala:544)
at dotty.tools.dotc.Run.rootContext(Run.scala:502)
at dotty.tools.dotc.Run.<init>(Run.scala:523)
at dotty.tools.dotc.Compiler.newRun(Compiler.scala:178)
at dotty.tools.dotc.Driver.doCompile(Driver.scala:35)
at dotty.tools.scripting.ScriptingDriver.compileAndRun(ScriptingDriver.scala:22)
at dotty.tools.scripting.Main$.process(Main.scala:39)
at dotty.tools.MainGenericRunner$.run$1(MainGenericRunner.scala:250)
at dotty.tools.MainGenericRunner$.process(MainGenericRunner.scala:286)
at dotty.tools.MainGenericRunner$.main(MainGenericRunner.scala:297)
at dotty.tools.MainGenericRunner.main(MainGenericRunner.scala)
Expectation
Should not crash.
The following script verifies that scala3-3.3.1 has no problem with the jar file.
#!/opt/scala3-3.3.1/bin/scala -classpath ./emptyClassPath.jar
object LegacyBug {
def main(args: Array[String]): Unit = {
printf("hello legacy!\n")
}
}
An empty string is a legal classpath
entry, interpreted by the jvm
as the current working directory, although it might have been created by accident. The following entry in build.sbt
can produce a problem jar:
Compile / packageBin / packageOptions += Package.ManifestAttributes(java.util.jar.Attributes.Name.CLASS_PATH -> "")
Here's a script to create a problem jar named emptyClassPath.jar
in the current directory:
#!/bin/bash
HERE=`pwd -P`
WORK_NAME=emptyClassPath
PROBLEM_JAR="$HERE"/$WORK_NAME.jar
WORK_DIR=/tmp/${WORK_NAME}$$
MANIFEST="$WORK_DIR"/META-INF/MANIFEST.MF
set -x
mkdir -p $WORK_DIR/META-INF
cd $WORK_DIR
touch main.class
cat > $MANIFEST <<- EOF
Manifest-Version: 1.0
Class-Path:
Created-By: $WORK_NAME
EOF
cat $MANIFEST
/opt/jdk8/bin/jar -cmf $MANIFEST "$PROBLEM_JAR" .