Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1385,13 +1385,18 @@ def construct_arguments(

# For determinism to help with build distribution and such
if remap_path_prefix != None:
# `--remap-path-prefix` flags are applied in reverse order. We need to
# specify the outermost directory (output_base) first, so that it's
# remapped last. Otherwise we can end up with a partial rewrite where
# "/path/to/output_base/execroot" becomes "./execroot" rather than ".".
rustc_flags.add("--remap-path-prefix=${{output_base}}={}".format(remap_path_prefix))
rustc_flags.add("--remap-path-prefix=${{pwd}}={}".format(remap_path_prefix))
rustc_flags.add("--remap-path-prefix=${{exec_root}}={}".format(remap_path_prefix))
if toolchain._bootstrapping:
# rustc resolves cwd itself, so bootstrap response files need no
# placeholder substitution to remap source paths in crate metadata.
rustc_flags.add(remap_path_prefix, format = "-Zremap-cwd-prefix=%s")
else:
# `--remap-path-prefix` flags are applied in reverse order. We need to
# specify the outermost directory (output_base) first, so that it's
# remapped last. Otherwise we can end up with a partial rewrite where
# "/path/to/output_base/execroot" becomes "./execroot" rather than ".".
rustc_flags.add("--remap-path-prefix=${output_base}=%s" % remap_path_prefix)
rustc_flags.add("--remap-path-prefix=${pwd}=%s" % remap_path_prefix)
rustc_flags.add("--remap-path-prefix=${exec_root}=%s" % remap_path_prefix)

emit_without_paths = []
redirect_link_to_metadata = build_metadata and crate_info.metadata != None
Expand Down Expand Up @@ -1661,6 +1666,11 @@ def construct_arguments(
if hasattr(ctx.attr, "_extra_exec_rustc_env") and is_exec_configuration(ctx):
env.update(ctx.attr._extra_exec_rustc_env[ExtraExecRustcEnvInfo].extra_exec_rustc_env)

if toolchain._bootstrapping and remap_path_prefix != None:
# -Zremap-cwd-prefix is unstable. Respect explicit RUSTC_BOOTSTRAP values;
# otherwise limit the opt-in to this bootstrap crate.
env.setdefault("RUSTC_BOOTSTRAP", ctx.configuration.default_shell_env.get("RUSTC_BOOTSTRAP", crate_info.name))

# Strip any `-Zallow-features=` entries out of the toolchain's extra
# rustc flags into `all_allowed_unstable_features` and, when
# `unstable_rust_features_config` is configured to a concrete list,
Expand Down Expand Up @@ -2163,6 +2173,8 @@ def rustc_compile(
use_json_output = bool(build_metadata) or bool(rustc_output) or bool(rustc_rmeta_output),
skip_expanding_rustc_env = skip_expanding_rustc_env,
require_explicit_unstable_features = require_explicit_unstable_features,
# _spawnvp in bootstrap_process_wrapper does not preserve embedded
# quotes in direct Windows arguments. rustc reads them from a response file.
always_use_param_file = rust_toolchain._bootstrapping,
inject_allow_features_guardrail = inject_allow_features_guardrail,
allowed_unstable_rust_features = allowed_unstable_rust_features,
Expand Down
16 changes: 16 additions & 0 deletions test/process_wrapper_bootstrap/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
load("//rust:defs.bzl", "rust_binary", "rust_test")
load(":bootstrap_tinyjson.bzl", "bootstrap_tinyjson")

bootstrap_tinyjson(
name = "bootstrap_tinyjson",
)

rust_test(
name = "bootstrap_reproducibility_test",
srcs = ["bootstrap_reproducibility_test.rs"],
data = [":bootstrap_tinyjson"],
edition = "2021",
env = {
"BOOTSTRAP_TINYJSON_RLOCATIONPATH": "$(rlocationpath :bootstrap_tinyjson)",
},
deps = ["//rust/runfiles"],
)

rust_binary(
name = "bootstrap_process_wrapper_probe",
Expand Down
19 changes: 19 additions & 0 deletions test/process_wrapper_bootstrap/bootstrap_reproducibility_test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! Check the metadata of tinyjson compiled with the bootstrap process wrapper.

#[test]
fn bootstrap_tinyjson_does_not_embed_execution_paths() {
let rfiles = runfiles::Runfiles::create().unwrap();
let rlocation = std::env::var("BOOTSTRAP_TINYJSON_RLOCATIONPATH").unwrap();
let artifact = runfiles::rlocation!(rfiles, rlocation.as_str()).unwrap();
let bytes = std::fs::read(&artifact).unwrap();

for prefix in ["/execroot/", "\\execroot\\", "/sandbox/", "\\sandbox\\"] {
assert!(
!bytes
.windows(prefix.len())
.any(|part| part == prefix.as_bytes()),
"{} contains an unremapped execution path ({prefix})",
artifact.display(),
);
}
}
21 changes: 21 additions & 0 deletions test/process_wrapper_bootstrap/bootstrap_tinyjson.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Expose tinyjson from the process wrapper's bootstrap configuration."""

load("//rust:defs.bzl", "rust_common")

def _bootstrap_tinyjson_impl(ctx):
crates = ctx.attr.process_wrapper[rust_common.dep_info].transitive_crates.to_list()
tinyjson = [crate.output for crate in crates if crate.name == "tinyjson"]
if len(tinyjson) != 1:
fail("Expected one bootstrap tinyjson output, got %s" % tinyjson)
return [DefaultInfo(files = depset(tinyjson))]

bootstrap_tinyjson = rule(
implementation = _bootstrap_tinyjson_impl,
attrs = {
"process_wrapper": attr.label(
cfg = "exec",
default = "//util/process_wrapper:process_wrapper",
providers = [rust_common.dep_info],
),
},
)
Loading