Skip to content

Commit 6597523

Browse files
committed
Auto merge of #9523 - ehuss:link-args-validate, r=alexcrichton
Add some validation to rustc-link-arg This adds some validation, so that if a `cargo:rustc-link-arg-*` build script instruction specifies a target that doesn't exist, it will generate an error. This also changes a parse warning to an error if the `=` is missing from BIN=ARG. I intentionally did not bother to add the validation to config overrides, as it is a bit trickier to do, and that feature is very rarely used (AFAIK), and I'm uncertain if rustc-link-arg is really useful in that context. cc #9426
2 parents 5fb59b0 + 836e537 commit 6597523

File tree

2 files changed

+130
-19
lines changed

2 files changed

+130
-19
lines changed

src/cargo/core/compiler/custom_build.rs

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ use super::job::{Freshness, Job, Work};
22
use super::{fingerprint, Context, LinkType, Unit};
33
use crate::core::compiler::context::Metadata;
44
use crate::core::compiler::job_queue::JobState;
5-
use crate::core::{profiles::ProfileRoot, PackageId};
5+
use crate::core::{profiles::ProfileRoot, PackageId, Target};
66
use crate::util::errors::CargoResult;
77
use crate::util::machine_message::{self, Message};
88
use crate::util::{internal, profile};
9-
use anyhow::Context as _;
9+
use anyhow::{bail, Context as _};
1010
use cargo_platform::Cfg;
1111
use cargo_util::paths;
1212
use std::collections::hash_map::{Entry, HashMap};
@@ -296,6 +296,9 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
296296

297297
let extra_link_arg = cx.bcx.config.cli_unstable().extra_link_arg;
298298
let nightly_features_allowed = cx.bcx.config.nightly_features_allowed;
299+
let targets: Vec<Target> = unit.pkg.targets().iter().cloned().collect();
300+
// Need a separate copy for the fresh closure.
301+
let targets_fresh = targets.clone();
299302

300303
// Prepare the unit of "dirty work" which will actually run the custom build
301304
// command.
@@ -405,6 +408,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
405408
&script_out_dir,
406409
extra_link_arg,
407410
nightly_features_allowed,
411+
&targets,
408412
)?;
409413

410414
if json_messages {
@@ -432,6 +436,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
432436
&script_out_dir,
433437
extra_link_arg,
434438
nightly_features_allowed,
439+
&targets_fresh,
435440
)?,
436441
};
437442

@@ -484,6 +489,7 @@ impl BuildOutput {
484489
script_out_dir: &Path,
485490
extra_link_arg: bool,
486491
nightly_features_allowed: bool,
492+
targets: &[Target],
487493
) -> CargoResult<BuildOutput> {
488494
let contents = paths::read_bytes(path)?;
489495
BuildOutput::parse(
@@ -494,6 +500,7 @@ impl BuildOutput {
494500
script_out_dir,
495501
extra_link_arg,
496502
nightly_features_allowed,
503+
targets,
497504
)
498505
}
499506

@@ -509,6 +516,7 @@ impl BuildOutput {
509516
script_out_dir: &Path,
510517
extra_link_arg: bool,
511518
nightly_features_allowed: bool,
519+
targets: &[Target],
512520
) -> CargoResult<BuildOutput> {
513521
let mut library_paths = Vec::new();
514522
let mut library_links = Vec::new();
@@ -543,7 +551,7 @@ impl BuildOutput {
543551
let (key, value) = match (key, value) {
544552
(Some(a), Some(b)) => (a, b.trim_end()),
545553
// Line started with `cargo:` but didn't match `key=value`.
546-
_ => anyhow::bail!("Wrong output in {}: `{}`", whence, line),
554+
_ => bail!("Wrong output in {}: `{}`", whence, line),
547555
};
548556

549557
// This will rewrite paths if the target directory has been moved.
@@ -552,7 +560,7 @@ impl BuildOutput {
552560
script_out_dir.to_str().unwrap(),
553561
);
554562

555-
// Keep in sync with TargetConfig::new.
563+
// Keep in sync with TargetConfig::parse_links_overrides.
556564
match key {
557565
"rustc-flags" => {
558566
let (paths, links) = BuildOutput::parse_rustc_flags(&value, &whence)?;
@@ -562,29 +570,61 @@ impl BuildOutput {
562570
"rustc-link-lib" => library_links.push(value.to_string()),
563571
"rustc-link-search" => library_paths.push(PathBuf::from(value)),
564572
"rustc-link-arg-cdylib" | "rustc-cdylib-link-arg" => {
573+
if !targets.iter().any(|target| target.is_cdylib()) {
574+
bail!(
575+
"invalid instruction `cargo:{}` from {}\n\
576+
The package {} does not have a cdylib target.",
577+
key,
578+
whence,
579+
pkg_descr
580+
);
581+
}
565582
linker_args.push((LinkType::Cdylib, value))
566583
}
567584
"rustc-link-arg-bins" => {
568585
if extra_link_arg {
586+
if !targets.iter().any(|target| target.is_bin()) {
587+
bail!(
588+
"invalid instruction `cargo:{}` from {}\n\
589+
The package {} does not have a bin target.",
590+
key,
591+
whence,
592+
pkg_descr
593+
);
594+
}
569595
linker_args.push((LinkType::Bin, value));
570596
} else {
571597
warnings.push(format!("cargo:{} requires -Zextra-link-arg flag", key));
572598
}
573599
}
574600
"rustc-link-arg-bin" => {
575601
if extra_link_arg {
576-
let parts = value.splitn(2, "=").collect::<Vec<_>>();
577-
if parts.len() == 2 {
578-
linker_args.push((
579-
LinkType::SingleBin(parts[0].to_string()),
580-
parts[1].to_string(),
581-
));
582-
} else {
583-
warnings.push(format!(
584-
"cargo:{} has invalid syntax: expected `cargo:{}=BIN=ARG`",
585-
key, key
586-
));
602+
let mut parts = value.splitn(2, '=');
603+
let bin_name = parts.next().unwrap().to_string();
604+
let arg = parts.next().ok_or_else(|| {
605+
anyhow::format_err!(
606+
"invalid instruction `cargo:{}={}` from {}\n\
607+
The instruction should have the form cargo:{}=BIN=ARG",
608+
key,
609+
value,
610+
whence,
611+
key
612+
)
613+
})?;
614+
if !targets
615+
.iter()
616+
.any(|target| target.is_bin() && target.name() == bin_name)
617+
{
618+
bail!(
619+
"invalid instruction `cargo:{}` from {}\n\
620+
The package {} does not have a bin target with the name `{}`.",
621+
key,
622+
whence,
623+
pkg_descr,
624+
bin_name
625+
);
587626
}
627+
linker_args.push((LinkType::SingleBin(bin_name), arg.to_string()));
588628
} else {
589629
warnings.push(format!("cargo:{} requires -Zextra-link-arg flag", key));
590630
}
@@ -632,7 +672,7 @@ impl BuildOutput {
632672
} else {
633673
// Setting RUSTC_BOOTSTRAP would change the behavior of the crate.
634674
// Abort with an error.
635-
anyhow::bail!("Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n\
675+
bail!("Cannot set `RUSTC_BOOTSTRAP={}` from {}.\n\
636676
note: Crates cannot set `RUSTC_BOOTSTRAP` themselves, as doing so would subvert the stability guarantees of Rust for your project.\n\
637677
help: If you're sure you want to do this in your project, set the environment variable `RUSTC_BOOTSTRAP={}` before running cargo instead.",
638678
val,
@@ -683,7 +723,7 @@ impl BuildOutput {
683723
if value.is_empty() {
684724
value = match flags_iter.next() {
685725
Some(v) => v,
686-
None => anyhow::bail! {
726+
None => bail! {
687727
"Flag in rustc-flags has no value in {}: {}",
688728
whence,
689729
value
@@ -699,7 +739,7 @@ impl BuildOutput {
699739
_ => unreachable!(),
700740
};
701741
} else {
702-
anyhow::bail!(
742+
bail!(
703743
"Only `-l` and `-L` flags are allowed in {}: `{}`",
704744
whence,
705745
value
@@ -715,7 +755,7 @@ impl BuildOutput {
715755
let val = iter.next();
716756
match (name, val) {
717757
(Some(n), Some(v)) => Ok((n.to_owned(), v.to_owned())),
718-
_ => anyhow::bail!("Variable rustc-env has no value in {}: {}", whence, value),
758+
_ => bail!("Variable rustc-env has no value in {}: {}", whence, value),
719759
}
720760
}
721761
}
@@ -900,6 +940,7 @@ fn prev_build_output(cx: &mut Context<'_, '_>, unit: &Unit) -> (Option<BuildOutp
900940
&script_out_dir,
901941
extra_link_arg,
902942
cx.bcx.config.nightly_features_allowed,
943+
unit.pkg.targets(),
903944
)
904945
.ok(),
905946
prev_script_out_dir,

tests/testsuite/build_script_extra_link_arg.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,73 @@ fn build_script_extra_link_arg_warn_without_flag() {
113113
.with_stderr_contains("warning: cargo:rustc-link-arg requires -Zextra-link-arg flag")
114114
.run();
115115
}
116+
117+
#[cargo_test]
118+
fn link_arg_missing_target() {
119+
// Errors when a given target doesn't exist.
120+
let p = project()
121+
.file("src/lib.rs", "")
122+
.file(
123+
"build.rs",
124+
r#"fn main() { println!("cargo:rustc-link-arg-cdylib=--bogus"); }"#,
125+
)
126+
.build();
127+
128+
p.cargo("check")
129+
.with_status(101)
130+
.with_stderr("\
131+
[COMPILING] foo [..]
132+
error: invalid instruction `cargo:rustc-link-arg-cdylib` from build script of `foo v0.0.1 ([ROOT]/foo)`
133+
The package foo v0.0.1 ([ROOT]/foo) does not have a cdylib target.
134+
")
135+
.run();
136+
137+
p.change_file(
138+
"build.rs",
139+
r#"fn main() { println!("cargo:rustc-link-arg-bins=--bogus"); }"#,
140+
);
141+
142+
p.cargo("check -Zextra-link-arg")
143+
.masquerade_as_nightly_cargo()
144+
.with_status(101)
145+
.with_stderr("\
146+
[COMPILING] foo [..]
147+
error: invalid instruction `cargo:rustc-link-arg-bins` from build script of `foo v0.0.1 ([ROOT]/foo)`
148+
The package foo v0.0.1 ([ROOT]/foo) does not have a bin target.
149+
")
150+
.run();
151+
152+
p.change_file(
153+
"build.rs",
154+
r#"fn main() { println!("cargo:rustc-link-arg-bin=abc=--bogus"); }"#,
155+
);
156+
157+
p.cargo("check -Zextra-link-arg")
158+
.masquerade_as_nightly_cargo()
159+
.with_status(101)
160+
.with_stderr(
161+
"\
162+
[COMPILING] foo [..]
163+
error: invalid instruction `cargo:rustc-link-arg-bin` from build script of `foo v0.0.1 ([ROOT]/foo)`
164+
The package foo v0.0.1 ([ROOT]/foo) does not have a bin target with the name `abc`.
165+
",
166+
)
167+
.run();
168+
169+
p.change_file(
170+
"build.rs",
171+
r#"fn main() { println!("cargo:rustc-link-arg-bin=abc"); }"#,
172+
);
173+
174+
p.cargo("check -Zextra-link-arg")
175+
.masquerade_as_nightly_cargo()
176+
.with_status(101)
177+
.with_stderr(
178+
"\
179+
[COMPILING] foo [..]
180+
error: invalid instruction `cargo:rustc-link-arg-bin=abc` from build script of `foo v0.0.1 ([ROOT]/foo)`
181+
The instruction should have the form cargo:rustc-link-arg-bin=BIN=ARG
182+
",
183+
)
184+
.run();
185+
}

0 commit comments

Comments
 (0)