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

Forking JavacCompiler breaks multiline arguments on Windows #351

Open
commonquail opened this issue Jan 24, 2024 · 0 comments
Open

Forking JavacCompiler breaks multiline arguments on Windows #351

commonquail opened this issue Jan 24, 2024 · 0 comments

Comments

@commonquail
Copy link

commonquail commented Jan 24, 2024

When a forking JavacCompiler receives an argument it translates all canonical platform path separators to /. This behaviour is invisible on most contemporary JVM capable platforms but it trivially manifests on Windows where the canonical path separator is \.

The practical effect of this behaviour is that Maven cannot pass multiline arguments to a forked javac on Windows. Multiline arguments rely on \ to escape line breaks, and javac does accept these on Windows, but JavacCompiler corrupts such arguments by erroneously POSIX-path'ifying them.

Besides the unfortunate translation just described, JavacCompiler additionally fails to replicate that same translation when merely reporting the command line. The practical effect of that behaviour is that mvn -X will report multiline compiler arguments verbatim, then actually pass another set of arguments to javac.

This translation behaviour was introduced in commit d3fee7f ([PLX-314] When forking javac, receive "The input line is too long" error from Windows, 2007-01-11), first released in plexus-compiler-1.5.3, and has existed since. There is no apparent motivation for the translation part of that change.

It is evident that JavacCompiler's path separator handling is defective but it is not obvious what the defect is.

Arguably the path separator translation may now be considered canonical and therefore unchangeable. Hypothetically, a configuration may have passed path arguments on some non-/ path separator platform using native path separators and since come to rely on the hidden translation for compilation on / path separator platforms. Such a configuration would break on / path separator platforms were the translation to be removed. I would personally argue that a translation such as this should never be automatically performed and that the functionality is in every sense an undesirable bug, however, I can understand erring on the side of caution here. If simply removing the translation is unacceptable, as a compromise, JavacCompiler might learn to preserve any \ immediately followed by /[\r\n]+/, i.e. a line break escape.

The relevant implementations are

  • JavacCompiler::createCommandLine
  • JavacCompiler::createFileWithArguments

The behaviour can be trivially reproduced with any forking maven-compiler-plugin on Windows. For example, the POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>example.multi-line-fork-crash</groupId>
  <artifactId>minimally-reproducible</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <maven.compiler.release>21</maven.compiler.release>
    <maven-compiler-plugin.version>3.12.1</maven-compiler-plugin.version>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven-compiler-plugin.version}</version>
        <configuration>
          <fork>true</fork>
          <compilerArgs>
            <arg>
              -Xplugin:ErrorProne \
              -Xep:DeadException:WARN</arg>
          </compilerArgs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

generates a target/javac.bat that contains

"-Xplugin:ErrorProne /
  -Xep:DeadException:WARN"

whose execution fails with

error: invalid flag: -Xep:DeadException

where it should fail with

plug-in not found: ErrorProne

For an authentic example see google/error-prone#4256.

For comparison, InProcessCompiler supports multiline arguments in Linux and Windows whether or not the line break is escaped, i.e. the following is accepted:

            <arg>
              -Xplugin:ErrorProne \
              -Xep:DeadException:WARN
              -Xep:DeadException:WARN
            </arg>

javac does not support the unescaped form; arguably, JavacCompiler might reasonably learn to perform a translation from unescaped to escaped.

@commonquail commonquail changed the title JavacCompiler breaks multiline arguments on Windows Forking JavacCompiler breaks multiline arguments on Windows Jan 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant