Skip to content

incompatible_windows_escape_jvm_flags: on Windows, enables tokenization and escaping of jvm_flags #7486

Closed
@laszlocsomor

Description

Description

Add --incompatible_windows_escape_jvm_flags flag (default: false). This flag only affects builds on Windows.

This flag has no effect on Linux/macOS/non-Windows.

Background

When you build a java_binary or java_test on Windows, one of the outputs is an .exe file. This is called the launcher, and this is what you run with "bazel run" and "bazel test". The launcher's purpose is to set up the environment, compute the JVM command line (classpath, JVM flags, etc.) and launch the JVM.

The target-specific data (such as the classpath, main class name, but also the jvm_flags attribute from the BUILD-file) are embedded into the launcher as binary data. When you run the launcher, it will compute the command line to run the JVM as a subprocess (using the CreateProcessW system call), and that involves escaping the JVM flags so they can safely be passed to the subprcoess.

The new flag

The --incompatible_windows_escape_jvm_flags flag affects how Bazel builds the launcher:

  • whether or not Bazel will Bash-tokenize the jvm_flags before embedding them in the launcher, and
  • whether the launcher will escape these flags using the correct escaping logic or the buggy one.

When the flag is enabled:

  • Bazel will Bash-tokenize java_binary.jvm_flags and java_test.jvm_flags (as documented by the Build Encyclopedia) before embedding them into the launcher.

  • The launcher will properly escape these flags when it runs the JVM as a subprocess (using launcher_util::WindowsEscapeArg2).

  • The result is that the jvm_flags declared in the BUILD file will arrive to the Java program as intended.

When the flag is disabled:

  • Bazel does not Bash-tokenize the jvm_flags before embedding them in the launcher.

  • The launcher escapes the flags with a Bash-like escaping logic (launcher_util::WindowsEscapeArg)
    which cannot properly quote and escape everything.

  • The result is that the jvm_flags declared in the BUILD file might get messed up as they are passed to the JVM, or the launcher may not even be able to run the JVM.

Related bug: #7072

Example

BUILD file:

java_binary(
    name = "x",
    srcs = ["A.java"],
    main_class = "A",
    jvm_flags = [
        "-Darg0='hello world'",
        r"-Darg1=\"C:\\Program\ Files\\\"",
    ],
)

A.java:

public class A {
  public static void main(String[] args) {
    System.out.printf(
        "arg0=(%s)%narg1=(%s)%n",
        System.getProperty("arg0"),
        System.getProperty("arg1"));
  }
}

The expected output of running the binary is:

arg0=(hello world)
arg1=("C:\Program Files\")

Currently the output is something like:

Error: Could not find or load main class

Migration recipe

None, as of 2019-02-21.

We don't expect any breakages when this flag is enabled. However if it breaks your build or if it breaks your java_binaries or java_tests, please let us know so we can help fixing it and provide a migration recipe.

Rollout plan

  • Bazel 0.23.0 will not support this flag.
  • Bazel 0.24.0 is expected to support this flag, with default value being false.
  • Bazel 0.25.0 is expected to flip this flag to true.

Metadata

Assignees

Labels

area-WindowsWindows-specific issues and feature requestsincompatible-changeIncompatible/breaking changeteam-OSSIssues for the Bazel OSS team: installation, release processBazel packaging, website

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions