Skip to content

Commit d572d2d

Browse files
eholkjakos-sec
authored andcommitted
Generate ASAN-enabled sysroot
Build asan-enabled version of rustc too, so rustc asan libs are available. Add config option to control whether to build lib-asan.
1 parent 82403ea commit d572d2d

File tree

5 files changed

+159
-26
lines changed

5 files changed

+159
-26
lines changed

bootstrap.example.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,9 @@
862862
#
863863
#rust.parallel-frontend-threads = 1
864864

865+
# Whether to build an ASAN-enabled version of the standard library.
866+
#rust.std-asan = false
867+
865868
# =============================================================================
866869
# Distribution options
867870
#

src/bootstrap/src/core/build_steps/compile.rs

Lines changed: 117 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ pub struct Std {
5656
force_recompile: bool,
5757
extra_rust_args: &'static [&'static str],
5858
is_for_mir_opt_tests: bool,
59+
/// Whether to build with AddressSanitizer enabled.
60+
asan: bool,
5961
}
6062

6163
impl Std {
@@ -67,6 +69,7 @@ impl Std {
6769
force_recompile: false,
6870
extra_rust_args: &[],
6971
is_for_mir_opt_tests: false,
72+
asan: false,
7073
}
7174
}
7275

@@ -107,6 +110,11 @@ impl Std {
107110
pub fn should_be_uplifted_from_stage_1(builder: &Builder<'_>, stage: u32) -> bool {
108111
stage > 1 && !builder.config.full_bootstrap
109112
}
113+
114+
pub fn asan(mut self, asan: bool) -> Self {
115+
self.asan = asan;
116+
self
117+
}
110118
}
111119

112120
impl Step for Std {
@@ -134,7 +142,7 @@ impl Step for Std {
134142
trace!("download_rustc: {}", builder.download_rustc());
135143
trace!(force_recompile);
136144

137-
run.builder.ensure(Std {
145+
let std = Std {
138146
// Note: we don't use compiler_for_std here, so that `x build library --stage 2`
139147
// builds a stage2 rustc.
140148
build_compiler: run.builder.compiler(run.builder.top_stage, builder.host_target),
@@ -143,7 +151,13 @@ impl Step for Std {
143151
force_recompile,
144152
extra_rust_args: &[],
145153
is_for_mir_opt_tests: false,
146-
});
154+
asan: false,
155+
};
156+
157+
if builder.config.needs_sanitizer_runtime_built(run.target) {
158+
run.builder.ensure(std.clone().asan(true));
159+
}
160+
run.builder.ensure(std.asan(false));
147161
}
148162

149163
/// Builds the standard library.
@@ -182,8 +196,11 @@ impl Step for Std {
182196
&& builder.config.is_host_target(target)
183197
&& !self.force_recompile
184198
{
185-
let sysroot =
186-
builder.ensure(Sysroot { compiler: build_compiler, force_recompile: false });
199+
let sysroot = builder.ensure(Sysroot {
200+
compiler: build_compiler,
201+
force_recompile: false,
202+
asan: self.asan,
203+
});
187204
cp_rustc_component_to_ci_sysroot(
188205
builder,
189206
&sysroot,
@@ -268,6 +285,9 @@ impl Step for Std {
268285
Kind::Build,
269286
);
270287
std_cargo(builder, target, &mut cargo, &self.crates);
288+
if self.asan {
289+
cargo.rustflag("-Zsanitizer=address");
290+
}
271291
cargo
272292
};
273293

@@ -722,6 +742,8 @@ pub struct StdLink {
722742
crates: Vec<String>,
723743
/// See [`Std::force_recompile`].
724744
force_recompile: bool,
745+
/// Whether to build with AddressSanitizer enabled.
746+
asan: bool,
725747
}
726748

727749
impl StdLink {
@@ -732,6 +754,7 @@ impl StdLink {
732754
target: std.target,
733755
crates: std.crates,
734756
force_recompile: std.force_recompile,
757+
asan: std.asan,
735758
}
736759
}
737760
}
@@ -759,16 +782,25 @@ impl Step for StdLink {
759782
// NOTE: intentionally does *not* check `target == builder.build` to avoid having to add the same check in `test::Crate`.
760783
let (libdir, hostdir) = if !self.force_recompile && builder.download_rustc() {
761784
// NOTE: copies part of `sysroot_libdir` to avoid having to add a new `force_recompile` argument there too
762-
let lib = builder.sysroot_libdir_relative(self.compiler);
785+
let lib = if self.asan {
786+
builder.sysroot_asan_libdir_relative(self.compiler)
787+
} else {
788+
builder.sysroot_libdir_relative(self.compiler)
789+
};
763790
let sysroot = builder.ensure(crate::core::build_steps::compile::Sysroot {
764791
compiler: self.compiler,
765792
force_recompile: self.force_recompile,
793+
asan: self.asan,
766794
});
767795
let libdir = sysroot.join(lib).join("rustlib").join(target).join("lib");
768796
let hostdir = sysroot.join(lib).join("rustlib").join(compiler.host).join("lib");
769797
(libdir, hostdir)
770798
} else {
771-
let libdir = builder.sysroot_target_libdir(target_compiler, target);
799+
let libdir = if self.asan {
800+
builder.sysroot_target_asan_libdir(target_compiler, target)
801+
} else {
802+
builder.sysroot_target_libdir(target_compiler, target)
803+
};
772804
let hostdir = builder.sysroot_target_libdir(target_compiler, compiler.host);
773805
(libdir, hostdir)
774806
};
@@ -1001,11 +1033,18 @@ pub struct Rustc {
10011033
/// Using it within bootstrap can lead to confusing situation where lints are replayed
10021034
/// in two different steps.
10031035
crates: Vec<String>,
1036+
/// Whether to build with AddressSanitizer enabled.
1037+
asan: bool,
10041038
}
10051039

10061040
impl Rustc {
10071041
pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self {
1008-
Self { target, build_compiler, crates: Default::default() }
1042+
Self { target, build_compiler, crates: Default::default(), asan: false }
1043+
}
1044+
1045+
pub fn asan(mut self, asan: bool) -> Self {
1046+
self.asan = asan;
1047+
self
10091048
}
10101049
}
10111050

@@ -1042,6 +1081,7 @@ impl Step for Rustc {
10421081
.compiler(run.builder.top_stage.saturating_sub(1), run.build_triple()),
10431082
target: run.target,
10441083
crates,
1084+
asan: false,
10451085
});
10461086
}
10471087

@@ -1059,8 +1099,11 @@ impl Step for Rustc {
10591099
if builder.download_rustc() && build_compiler.stage != 0 {
10601100
trace!(stage = build_compiler.stage, "`download_rustc` requested");
10611101

1062-
let sysroot =
1063-
builder.ensure(Sysroot { compiler: build_compiler, force_recompile: false });
1102+
let sysroot = builder.ensure(Sysroot {
1103+
compiler: build_compiler,
1104+
force_recompile: false,
1105+
asan: self.asan,
1106+
});
10641107
cp_rustc_component_to_ci_sysroot(
10651108
builder,
10661109
&sysroot,
@@ -1071,7 +1114,7 @@ impl Step for Rustc {
10711114

10721115
// Build a standard library for `target` using the `build_compiler`.
10731116
// This will be the standard library that the rustc which we build *links to*.
1074-
builder.std(build_compiler, target);
1117+
builder.std_maybe_asan(build_compiler, target, self.asan);
10751118

10761119
if builder.config.keep_stage.contains(&build_compiler.stage) {
10771120
trace!(stage = build_compiler.stage, "`keep-stage` requested");
@@ -1112,6 +1155,7 @@ impl Step for Rustc {
11121155
build_compiler,
11131156
target,
11141157
self.crates,
1158+
self.asan,
11151159
));
11161160

11171161
// Here we have performed an uplift, so we return the actual build compiler that "built"
@@ -1143,6 +1187,14 @@ impl Step for Rustc {
11431187
// NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be
11441188
// consistently applied by check/doc/test modes too.
11451189

1190+
if self.asan && build_compiler.stage > 0 {
1191+
cargo.rustflag("-Zsanitizer=address");
1192+
cargo.rustflag(&format!(
1193+
"-L{}",
1194+
builder.sysroot_asan_libdir_relative(build_compiler).display()
1195+
));
1196+
}
1197+
11461198
for krate in &*self.crates {
11471199
cargo.arg("-p").arg(krate);
11481200
}
@@ -1523,6 +1575,8 @@ struct RustcLink {
15231575
target: TargetSelection,
15241576
/// Not actually used; only present to make sure the cache invalidation is correct.
15251577
crates: Vec<String>,
1578+
/// Whether to build with AddressSanitizer enabled.
1579+
asan: bool,
15261580
}
15271581

15281582
impl RustcLink {
@@ -1534,6 +1588,7 @@ impl RustcLink {
15341588
sysroot_compiler: rustc.build_compiler,
15351589
target: rustc.target,
15361590
crates: rustc.crates,
1591+
asan: rustc.asan,
15371592
}
15381593
}
15391594

@@ -1543,8 +1598,9 @@ impl RustcLink {
15431598
sysroot_compiler: Compiler,
15441599
target: TargetSelection,
15451600
crates: Vec<String>,
1601+
asan: bool,
15461602
) -> Self {
1547-
Self { build_compiler, sysroot_compiler, target, crates }
1603+
Self { build_compiler, sysroot_compiler, target, crates, asan }
15481604
}
15491605
}
15501606

@@ -1560,10 +1616,23 @@ impl Step for RustcLink {
15601616
let build_compiler = self.build_compiler;
15611617
let sysroot_compiler = self.sysroot_compiler;
15621618
let target = self.target;
1619+
1620+
let target_libdir = if self.asan {
1621+
builder.sysroot_target_asan_libdir(sysroot_compiler, target)
1622+
} else {
1623+
builder.sysroot_target_libdir(sysroot_compiler, target)
1624+
};
1625+
1626+
let host_libdir = if self.asan {
1627+
builder.sysroot_target_asan_libdir(sysroot_compiler, sysroot_compiler.host)
1628+
} else {
1629+
builder.sysroot_target_libdir(sysroot_compiler, sysroot_compiler.host)
1630+
};
1631+
15631632
add_to_sysroot(
15641633
builder,
1565-
&builder.sysroot_target_libdir(sysroot_compiler, target),
1566-
&builder.sysroot_target_libdir(sysroot_compiler, sysroot_compiler.host),
1634+
&target_libdir,
1635+
&host_libdir,
15671636
&build_stamp::librustc_stamp(builder, build_compiler, target),
15681637
);
15691638
}
@@ -1827,11 +1896,13 @@ pub struct Sysroot {
18271896
pub compiler: Compiler,
18281897
/// See [`Std::force_recompile`].
18291898
force_recompile: bool,
1899+
/// Whether to build with AddressSanitizer enabled.
1900+
asan: bool,
18301901
}
18311902

18321903
impl Sysroot {
18331904
pub(crate) fn new(compiler: Compiler) -> Self {
1834-
Sysroot { compiler, force_recompile: false }
1905+
Sysroot { compiler, force_recompile: false, asan: false }
18351906
}
18361907
}
18371908

@@ -1849,18 +1920,18 @@ impl Step for Sysroot {
18491920
let compiler = self.compiler;
18501921
let host_dir = builder.out.join(compiler.host);
18511922

1852-
let sysroot_dir = |stage| {
1923+
let sysroot_dir = |stage, asan| {
18531924
if stage == 0 {
18541925
host_dir.join("stage0-sysroot")
18551926
} else if self.force_recompile && stage == compiler.stage {
18561927
host_dir.join(format!("stage{stage}-test-sysroot"))
18571928
} else if builder.download_rustc() && compiler.stage != builder.top_stage {
18581929
host_dir.join("ci-rustc-sysroot")
18591930
} else {
1860-
host_dir.join(format!("stage{stage}"))
1931+
host_dir.join(format!("stage{stage}{}", if asan { "-asan" } else { "" }))
18611932
}
18621933
};
1863-
let sysroot = sysroot_dir(compiler.stage);
1934+
let sysroot = sysroot_dir(compiler.stage, self.asan);
18641935
trace!(stage = ?compiler.stage, ?sysroot);
18651936

18661937
builder.do_if_verbose(|| {
@@ -1889,7 +1960,7 @@ impl Step for Sysroot {
18891960
// #102002, cleanup old toolchain folders when using download-rustc so people don't use them by accident.
18901961
for stage in 0..=2 {
18911962
if stage != compiler.stage {
1892-
let dir = sysroot_dir(stage);
1963+
let dir = sysroot_dir(stage, self.asan);
18931964
if !dir.ends_with("ci-rustc-sysroot") {
18941965
let _ = fs::remove_dir_all(dir);
18951966
}
@@ -2149,8 +2220,11 @@ impl Step for Assemble {
21492220
trace!("`download-rustc` requested, reusing CI compiler for stage > 0");
21502221

21512222
builder.std(target_compiler, target_compiler.host);
2152-
let sysroot =
2153-
builder.ensure(Sysroot { compiler: target_compiler, force_recompile: false });
2223+
let sysroot = builder.ensure(Sysroot {
2224+
compiler: target_compiler,
2225+
force_recompile: false,
2226+
asan: false,
2227+
});
21542228
// Ensure that `libLLVM.so` ends up in the newly created target directory,
21552229
// so that tools using `rustc_private` can use it.
21562230
dist::maybe_install_llvm_target(builder, target_compiler.host, &sysroot);
@@ -2215,6 +2289,11 @@ impl Step for Assemble {
22152289
"building compiler libraries to link to"
22162290
);
22172291

2292+
// Build ASAN-enabled rustc to populate the ASAN sysroot
2293+
if target_compiler.stage > 0 && builder.config.std_asan {
2294+
builder.ensure(Rustc::new(build_compiler, target_compiler.host).asan(true));
2295+
}
2296+
22182297
// It is possible that an uplift has happened, so we override build_compiler here.
22192298
let BuiltRustc { build_compiler } =
22202299
builder.ensure(Rustc::new(build_compiler, target_compiler.host));
@@ -2249,11 +2328,7 @@ impl Step for Assemble {
22492328
})
22502329
.collect::<HashSet<_>>();
22512330

2252-
let sysroot = builder.sysroot(target_compiler);
2253-
let rustc_libdir = builder.rustc_libdir(target_compiler);
2254-
t!(fs::create_dir_all(&rustc_libdir));
2255-
let src_libdir = builder.sysroot_target_libdir(build_compiler, host);
2256-
for f in builder.read_dir(&src_libdir) {
2331+
let copy_link = |f: fs::DirEntry, rustc_libdir: &Path| {
22572332
let filename = f.file_name().into_string().unwrap();
22582333

22592334
let is_proc_macro = proc_macros.contains(&filename);
@@ -2275,6 +2350,23 @@ impl Step for Assemble {
22752350
if is_dylib_or_debug && can_be_rustc_dynamic_dep && !is_proc_macro {
22762351
builder.copy_link(&f.path(), &rustc_libdir.join(&filename), FileType::Regular);
22772352
}
2353+
};
2354+
2355+
// Copy non-ASAN libraries to the sysroot.
2356+
let sysroot = builder.sysroot(target_compiler);
2357+
let rustc_libdir = builder.rustc_libdir(target_compiler);
2358+
t!(fs::create_dir_all(&rustc_libdir));
2359+
let src_libdir = builder.sysroot_target_libdir(build_compiler, host);
2360+
for f in builder.read_dir(&src_libdir) {
2361+
copy_link(f, &rustc_libdir);
2362+
}
2363+
2364+
// Copy ASAN libraries to the sysroot
2365+
let rustc_libdir = builder.sysroot_target_asan_libdir(target_compiler, host);
2366+
t!(fs::create_dir_all(&rustc_libdir));
2367+
let src_libdir = builder.sysroot_target_asan_libdir(build_compiler, host);
2368+
for f in builder.read_dir(&src_libdir) {
2369+
copy_link(f, &rustc_libdir);
22782370
}
22792371

22802372
{

0 commit comments

Comments
 (0)